/*! init triangle divisions */ void calcTriangleDivs(Object *ob, MVert *verts, int numverts, MFace *faces, int numfaces, int numtris, int **tridivs, float cell_len) { // mTriangleDivs1.resize( faces.size() ); // mTriangleDivs2.resize( faces.size() ); // mTriangleDivs3.resize( faces.size() ); size_t i = 0, facecounter = 0; float maxscale[3] = {1,1,1}; // = channelFindMaxVf(mcScale); float maxpart = ABS(maxscale[0]); float scaleFac = 0; float fsTri = 0; if(ABS(maxscale[1])>maxpart) maxpart = ABS(maxscale[1]); if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]); scaleFac = 1.0 / maxpart; // featureSize = mLevel[mMaxRefine].nodeSize fsTri = cell_len * 0.5 * scaleFac; if(*tridivs) MEM_freeN(*tridivs); *tridivs = MEM_callocN(sizeof(int) * numtris * 3, "Smoke_Tridivs"); for(i = 0, facecounter = 0; i < numfaces; i++) { float p0[3], p1[3], p2[3]; float side1[3]; float side2[3]; float side3[3]; int divs1=0, divs2=0, divs3=0; VECCOPY(p0, verts[faces[i].v1].co); Mat4MulVecfl (ob->obmat, p0); VECCOPY(p1, verts[faces[i].v2].co); Mat4MulVecfl (ob->obmat, p1); VECCOPY(p2, verts[faces[i].v3].co); Mat4MulVecfl (ob->obmat, p2); VECSUB(side1, p1, p0); VECSUB(side2, p2, p0); VECSUB(side3, p1, p2); if(INPR(side1, side1) > fsTri*fsTri) { float tmp = Normalize(side1); divs1 = (int)ceil(tmp/fsTri); } if(INPR(side2, side2) > fsTri*fsTri) { float tmp = Normalize(side2); divs2 = (int)ceil(tmp/fsTri); /* // debug if(i==0) printf("b tmp: %f, fsTri: %f, divs2: %d\n", tmp, fsTri, divs2); */ } (*tridivs)[3 * facecounter + 0] = divs1; (*tridivs)[3 * facecounter + 1] = divs2; (*tridivs)[3 * facecounter + 2] = divs3; // TODO quad case if(faces[i].v4) { divs1=0, divs2=0, divs3=0; facecounter++; VECCOPY(p0, verts[faces[i].v3].co); Mat4MulVecfl (ob->obmat, p0); VECCOPY(p1, verts[faces[i].v4].co); Mat4MulVecfl (ob->obmat, p1); VECCOPY(p2, verts[faces[i].v1].co); Mat4MulVecfl (ob->obmat, p2); VECSUB(side1, p1, p0); VECSUB(side2, p2, p0); VECSUB(side3, p1, p2); if(INPR(side1, side1) > fsTri*fsTri) { float tmp = Normalize(side1); divs1 = (int)ceil(tmp/fsTri); } if(INPR(side2, side2) > fsTri*fsTri) { float tmp = Normalize(side2); divs2 = (int)ceil(tmp/fsTri); } (*tridivs)[3 * facecounter + 0] = divs1; (*tridivs)[3 * facecounter + 1] = divs2; (*tridivs)[3 * facecounter + 2] = divs3; } facecounter++; } }
/* get a vector, vec, that points from v1->co to wherever makes sense to * the bevel operation as a whole based on the relationship between v1 and v2 * (won't necessarily be a vec from v1->co to v2->co, though it probably will be); * the return value is -1 for failure, 0 if we used vert co's, and 1 if we used transform origins */ static int BME_bevel_get_vec(float *vec, BME_Vert *v1, BME_Vert *v2, BME_TransData_Head *td) { BME_TransData *vtd1, *vtd2; vtd1 = BME_get_transdata(td,v1); vtd2 = BME_get_transdata(td,v2); if (!vtd1 || !vtd2) { //printf("BME_bevel_get_vec() got called without proper BME_TransData\n"); return -1; } /* compare the transform origins to see if we can use the vert co's; * if they belong to different origins, then we will use the origins to determine * the vector */ if (compare_v3v3(vtd1->org,vtd2->org,0.000001f)) { VECSUB(vec,v2->co,v1->co); if (len_v3(vec) < 0.000001f) { mul_v3_fl(vec,0); } return 0; } else { VECSUB(vec,vtd2->org,vtd1->org); if (len_v3(vec) < 0.000001f) { mul_v3_fl(vec,0); } return 1; } }
/* -------- pdDoEffectors() -------- generic force/speed system, now used for particles and softbodies scene = scene where it runs in, for time and stuff lb = listbase with objects that take part in effecting opco = global coord, as input force = force accumulator speed = actual current speed which can be altered cur_time = "external" time in frames, is constant for static particles loc_time = "local" time in frames, range <0-1> for the lifetime of particle par_layer = layer the caller is in flags = only used for softbody wind now guide = old speed of particle */ void pdDoEffectors(ListBase *effectors, ListBase *colliders, EffectorWeights *weights, EffectedPoint *point, float *force, float *impulse) { /* Modifies the force on a particle according to its relation with the effector object Different kind of effectors include: Forcefields: Gravity-like attractor (force power is related to the inverse of distance to the power of a falloff value) Vortex fields: swirling effectors (particles rotate around Z-axis of the object. otherwise, same relation as) (Forcefields, but this is not done through a force/acceleration) Guide: particles on a path (particles are guided along a curve bezier or old nurbs) (is independent of other effectors) */ EffectorCache *eff; EffectorData efd; int p=0, tot = 1, step = 1; /* Cycle through collected objects, get total of (1/(gravity_strength * dist^gravity_power)) */ /* Check for min distance here? (yes would be cool to add that, ton) */ if(effectors) for(eff = effectors->first; eff; eff=eff->next) { /* object effectors were fully checked to be OK to evaluate! */ get_effector_tot(eff, &efd, point, &tot, &p, &step); for(; p<tot; p+=step) { if(get_effector_data(eff, &efd, point, 0)) { efd.falloff= effector_falloff(eff, &efd, point, weights); if(efd.falloff > 0.0f) efd.falloff *= eff_calc_visibility(colliders, eff, &efd, point); if(efd.falloff <= 0.0f) ; /* don't do anything */ else if(eff->pd->forcefield == PFIELD_TEXTURE) do_texture_effector(eff, &efd, point, force); else { float temp1[3]={0,0,0}, temp2[3]; copy_v3_v3(temp1, force); do_physical_effector(eff, &efd, point, force); // for softbody backward compatibility if(point->flag & PE_WIND_AS_SPEED && impulse){ VECSUB(temp2, force, temp1); VECSUB(impulse, impulse, temp2); } } } else if(eff->flag & PE_VELOCITY_TO_IMPULSE && impulse) { /* special case for harmonic effector */ VECADD(impulse, impulse, efd.vel); } } } }
static int convex(float *p0, float *up, float *a, float *b) { // Vec3 va = a-p0, vb = b-p0; float va[3], vb[3], tmp[3]; VECSUB(va, a, p0); VECSUB(vb, b, p0); cross_v3_v3v3(tmp, va, vb); return INPR(up, tmp) >= 0; }
static void traverse_octree(ScatterTree *tree, ScatterNode *node, float *co, int self, ScatterResult *result) { float sub[3], dist; int i, index = 0; if(node->totpoint > 0) { /* leaf - add radiance from all samples */ for(i=0; i<node->totpoint; i++) { ScatterPoint *p= &node->points[i]; VECSUB(sub, co, p->co); dist= INPR(sub, sub); if(p->back) add_radiance(tree, NULL, p->rad, 0.0f, p->area, dist, result); else add_radiance(tree, p->rad, NULL, p->area, 0.0f, dist, result); } } else { /* branch */ if (self) index = SUBNODE_INDEX(co, node->split); for(i=0; i<8; i++) { if(node->child[i]) { ScatterNode *subnode= node->child[i]; if(self && index == i) { /* always traverse node containing the point */ traverse_octree(tree, subnode, co, 1, result); } else { /* decide subnode traversal based on maximum solid angle */ VECSUB(sub, co, subnode->co); dist= INPR(sub, sub); /* actually area/dist > error, but this avoids division */ if(subnode->area+subnode->backarea>tree->error*dist) { traverse_octree(tree, subnode, co, 0, result); } else { add_radiance(tree, subnode->rad, subnode->backrad, subnode->area, subnode->backarea, dist, result); } } } } } }
int playWave3DPitch(const char *fname, const double src[3], const double org[3], const double pyr[3], double vol, double attn, double delay, unsigned short pitch){ extern double dwo; avec3_t delta, xhat; double sdist, dist; VECSUB(delta, src, org); sdist = VECSLEN(delta); dist = sqrt(sdist); /* xhat[0] = cos(pyr[1]); xhat[1] = 0; xhat[2] =- sin(pyr[1]);*/ /* return playWaveCustom(fname, (size_t)(SAMPLERATE * (dist / wave_sonic_speed)), (unsigned char)(256 * vol / (1. + sdist / attn)), 0, 128 * VECSP(delta, xhat) / dist, 0, 0);*/ return playWave3DCustom(fname, src, delay < dwo ? 0 : (size_t)(SAMPLERATE * (delay - dwo)), vol, attn, pitch); }
int playMemoryWave3D(const unsigned char *wav, size_t size, short pitch, const double src[3], const double org[3], const double pyr[3], double vol, double attn, double delay){ extern double dwo; avec3_t delta, xhat; double sdist, dist; VECSUB(delta, src, org); sdist = VECSLEN(delta); dist = sqrt(sdist); /* xhat[0] = -cos(pyr[1]); xhat[1] = 0; xhat[2] = sin(pyr[1]);*/ /* return addsound(wav, size, (size_t)(SAMPLERATE * (dist / wave_sonic_speed)), (unsigned char)(256 * vol / (1. + sdist / attn)), pitch, -128 * VECSP(delta, xhat) / dist, 0, 0);*/ return addsound3d(wav, size, delay < dwo ? 0 : (size_t)(SAMPLERATE * (delay - dwo/* + dist / wave_sonic_speed*/)), vol, attn, src, pitch + 256, 8000); }
// check whether a ship is in jump range of a stargate ------------------------ // PRIVATE int ShipInStargateJumpRange( Stargate *stargate, ShipObject *ship, geomv_t range ) { ASSERT( stargate != NULL ); ASSERT( ship != NULL ); //NOTE: // the ship is treated as a point for jump // range detection. Vector3 gatenormal; FetchZVector( stargate->ObjPosition, &gatenormal ); Vertex3 gatepos; FetchTVector( stargate->ObjPosition, &gatepos ); Vertex3 shippos; FetchTVector( ship->ObjPosition, &shippos ); geomv_t shipdot = -DOT_PRODUCT( &gatenormal, &shippos ); geomv_t gatedot = -DOT_PRODUCT( &gatenormal, &gatepos ); geomv_t distance = shipdot - gatedot; // not in range if ship in wrong halfspace if ( GEOMV_NEGATIVE( distance ) ) { return FALSE; } // check whether inside of boundingsphere around stargate Vector3 stargate_ship; VECSUB( &stargate_ship, &shippos, &gatepos ); geomv_t stargate_ship_len = VctLenX( &stargate_ship ); if ( stargate_ship_len > stargate->BoundingSphere ) { return FALSE; } // inside the activation distance/range ? if ( distance < range ) { Vector3 shipnormal; FetchZVector( ship->ObjPosition, &shipnormal ); // ship must be flying approximately head-on into the gate //FIXME: cone_angle like for teleporter geomv_t dirdot = DOT_PRODUCT( &gatenormal, &shipnormal ); return ( dirdot > FLOAT_TO_GEOMV( 0.7f ) ); } return FALSE; }
static float BME_bevel_get_angle(BME_Mesh *UNUSED(bm), BME_Edge *e, BME_Vert *v) { BME_Vert *v1, *v2; BME_Loop *l1, *l2; float vec1[3], vec2[3], vec3[3], vec4[3]; l1 = e->loop; l2 = e->loop->radial.next->data; if (l1->v == v) { v1 = l1->prev->v; v2 = l1->next->v; } else { v1 = l1->next->next->v; v2 = l1->v; } VECSUB(vec1,v1->co,v->co); VECSUB(vec2,v2->co,v->co); cross_v3_v3v3(vec3,vec1,vec2); l1 = l2; if (l1->v == v) { v1 = l1->prev->v; v2 = l1->next->v; } else { v1 = l1->next->next->v; v2 = l1->v; } VECSUB(vec1,v1->co,v->co); VECSUB(vec2,v2->co,v->co); cross_v3_v3v3(vec4,vec2,vec1); normalize_v3(vec3); normalize_v3(vec4); return dot_v3v3(vec3,vec4); }
// ---------------------------------------------------------------------------- // void BOT_AI::_GoalCheck_AgentMode_Retreat() { BOT_Goal* pGoal = m_State.GetCurGoal(); Vector3* pGoalPos = pGoal->GetGoalPosition(); ExtraObject* pObject = NULL; ASSERT( pGoal != NULL ); if(pGoal->GetTargetObject() == NULL) { if(m_pShip->CurDamage > (m_pShip->MaxDamage * 0.9)) { pObject = m_Character.SelectRepairObject(); } if(m_pShip->CurEnergy < (m_pShip->MaxEnergy * 0.1)) { pObject = m_Character.SelectEnergyObject(); m_nAgentMode = AGENTMODE_RETREAT; } if(pObject == NULL) { m_nAgentMode = AGENTMODE_IDLE; return; } pGoal->SetTargetObject(pObject); FetchTVector( pObject->ObjPosition, pGoalPos ); #ifdef BOT_LOGFILES BOT_MsgOut("Retreat: Targetting Extra"); #endif } pGoalPos = pGoal->GetGoalPosition(); // get vector to target Vector3 vec2Target; VECSUB( &vec2Target, pGoalPos, &m_AgentPos ); float len = VctLenX( &vec2Target ); #ifdef BOT_LOGFILES BOT_MsgOut( "BOT: distance to goal: %f", len ); #endif if ( len < 100.0f ) { #ifdef BOT_LOGFILES BOT_MsgOut("Clearing Goal"); #endif pGoal->SetTargetObject(NULL); } }
/* tracing */ static float vol_get_shadow(ShadeInput *shi, LampRen *lar, float *co) { float visibility = 1.f; if(lar->shb) { float dxco[3]={0.f, 0.f, 0.f}, dyco[3]={0.f, 0.f, 0.f}; visibility = testshadowbuf(&R, lar->shb, co, dxco, dyco, 1.0, 0.0); } else if (lar->mode & LA_SHAD_RAY) { /* trace shadow manually, no good lamp api atm */ Isect is; copy_v3_v3(is.start, co); if(lar->type==LA_SUN || lar->type==LA_HEMI) { is.dir[0] = -lar->vec[0]; is.dir[1] = -lar->vec[1]; is.dir[2] = -lar->vec[2]; is.dist = R.maxdist; } else { VECSUB( is.dir, lar->co, is.start ); is.dist = normalize_v3( is.dir ); } is.mode = RE_RAY_MIRROR; is.check = RE_CHECK_VLR_NON_SOLID_MATERIAL; is.skip = 0; if(lar->mode & (LA_LAYER|LA_LAYER_SHADOW)) is.lay= lar->lay; else is.lay= -1; is.orig.ob = NULL; is.orig.face = NULL; is.last_hit = lar->last_hit[shi->thread]; if(RE_rayobject_raycast(R.raytree,&is)) { visibility = 0.f; } lar->last_hit[shi->thread]= is.last_hit; } return visibility; }
static void get_cell(float *p0, int res[3], float dx, float *pos, int *cell, int correct) { float tmp[3]; VECSUB(tmp, pos, p0); VecMulf(tmp, 1.0 / dx); if(correct) { cell[0] = MIN2(res[0] - 1, MAX2(0, (int)floor(tmp[0]))); cell[1] = MIN2(res[1] - 1, MAX2(0, (int)floor(tmp[1]))); cell[2] = MIN2(res[2] - 1, MAX2(0, (int)floor(tmp[2]))); } else { cell[0] = (int)floor(tmp[0]); cell[1] = (int)floor(tmp[1]); cell[2] = (int)floor(tmp[2]); } }
/* a wrapper for BME_SEMV that transfers element flags */ /*add custom data interpolation in here!*/ static BME_Vert *BME_split_edge(BME_Mesh *bm, BME_Vert *v, BME_Edge *e, BME_Edge **ne, float percent) { BME_Vert *nv, *v2; float len; v2 = BME_edge_getothervert(e,v); nv = BME_SEMV(bm,v,e,ne); if (nv == NULL) return NULL; VECSUB(nv->co,v2->co,v->co); len = len_v3(nv->co); VECADDFAC(nv->co,v->co,nv->co,len*percent); nv->flag = v->flag; nv->bweight = v->bweight; if (ne) { (*ne)->flag = e->flag; (*ne)->h = e->h; (*ne)->crease = e->crease; (*ne)->bweight = e->bweight; } /*v->nv->v2*/ BME_data_facevert_edgesplit(bm,v2, v, nv, e, 0.75); return nv; }
// ---------------------------------------------------------------------------- // void BOT_AI::_GoalCheck_AgentMode_Powerup() { BOT_Goal* pGoal = m_State.GetCurGoal(); Vector3* pGoalPos = pGoal->GetGoalPosition(); ASSERT( pGoal != NULL ); if(pGoal->GetTargetObject() == NULL) { ExtraObject* pObject = FetchFirstExtra(); if(pObject == NULL) { m_nAgentMode = AGENTMODE_IDLE; return; } pGoal->SetTargetObject(pObject); FetchTVector( pObject->ObjPosition, pGoalPos ); #ifdef BOT_LOGFILES BOT_MsgOut("Targetting Extra"); #endif } pGoalPos = pGoal->GetGoalPosition(); // get vector to target Vector3 vec2Target; VECSUB( &vec2Target, pGoalPos, &m_AgentPos ); float len = VctLenX( &vec2Target ); #ifdef BOT_LOGFILES BOT_MsgOut( "BOT: distance to goal: %f", len ); #endif if ( len < 100.0f ) { #ifdef BOT_LOGFILES BOT_MsgOut("Clearing Goal"); pGoal->SetTargetObject(NULL); #endif } }
// ---------------------------------------------------------------------------- // void BOT_AI::_SteerToPosition( Vector3* targetPos, object_control_s* pObjctl ) { // get vector to target Vector3 vec2Target; VECSUB( &vec2Target, targetPos, &m_AgentPos ); float oldaccel = pObjctl->accel; UTL_LocomotionController _LomoCtrl; _LomoCtrl.ControlOjbect( pObjctl, &vec2Target, pObjctl->pShip->MaxSpeed ); if ( pObjctl->accel != oldaccel ) { #ifdef BOT_LOGFILES BOT_AccelMode_MsgOut( "%f %f %f", m_AgentPos.X, m_AgentPos.Y, m_AgentPos.Z ); #endif // BOT_LOGFILES } Vector3 xDir, yDir, zDir; FetchXVector( m_pShip->ObjPosition, &xDir ); FetchYVector( m_pShip->ObjPosition, &yDir ); FetchZVector( m_pShip->ObjPosition, &zDir ); #ifdef BOT_LOGFILES BOT_MsgOut( "pos: %7.2f/%7.2f/%7.2f vec2target: %7.2f/%7.2f/%7.2f xDir: %7.2f/%7.2f/%7.2f yDir: %7.2f/%7.2f/%7.2f rot_x: %7.2f rot_y: %7.2f accel: %7.2f", m_AgentPos.X, m_AgentPos.Y, m_AgentPos.Z, vec2Target.X, vec2Target.Y, vec2Target.Z, xDir.X, xDir.Y, xDir.Z, yDir.X, yDir.Y, yDir.Z, pObjctl->rot_x, pObjctl->rot_y, pObjctl->accel ); BOT_Pos_MsgOut ( "%f %f %f", m_AgentPos.X, m_AgentPos.Y, m_AgentPos.Z ); BOT_XDir_MsgOut( "%f %f %f", xDir.X, xDir.Y, xDir.Z ); BOT_ZDir_MsgOut( "%f %f %f", zDir.X, zDir.Y, zDir.Z ); #endif // BOT_LOGFILES }
static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFace *activetf) { EditFace *efa; MTFace *tf; Image *ima= sima->image; float aspx, aspy, col[4], tf_uv[4][2]; ED_space_image_uv_aspect(sima, &aspx, &aspy); switch(sima->dt_uvstretch) { case SI_UVDT_STRETCH_AREA: { float totarea=0.0f, totuvarea=0.0f, areadiff, uvarea, area; for(efa= em->faces.first; efa; efa= efa->next) { tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); uv_copy_aspect(tf->uv, tf_uv, aspx, aspy); totarea += EM_face_area(efa); //totuvarea += tf_area(tf, efa->v4!=0); totuvarea += uv_area(tf_uv, efa->v4!=0); if(uvedit_face_visible(scene, ima, efa, tf)) { efa->tmp.p = tf; } else { if(tf == activetf) activetf= NULL; efa->tmp.p = NULL; } } if(totarea < FLT_EPSILON || totuvarea < FLT_EPSILON) { col[0] = 1.0; col[1] = col[2] = 0.0; glColor3fv(col); for(efa= em->faces.first; efa; efa= efa->next) { if((tf=(MTFace *)efa->tmp.p)) { glBegin(efa->v4?GL_QUADS:GL_TRIANGLES); glVertex2fv(tf->uv[0]); glVertex2fv(tf->uv[1]); glVertex2fv(tf->uv[2]); if(efa->v4) glVertex2fv(tf->uv[3]); glEnd(); } } } else { for(efa= em->faces.first; efa; efa= efa->next) { if((tf=(MTFace *)efa->tmp.p)) { area = EM_face_area(efa) / totarea; uv_copy_aspect(tf->uv, tf_uv, aspx, aspy); //uvarea = tf_area(tf, efa->v4!=0) / totuvarea; uvarea = uv_area(tf_uv, efa->v4!=0) / totuvarea; if(area < FLT_EPSILON || uvarea < FLT_EPSILON) areadiff = 1.0; else if(area>uvarea) areadiff = 1.0-(uvarea/area); else areadiff = 1.0-(area/uvarea); weight_to_rgb(areadiff, col, col+1, col+2); glColor3fv(col); glBegin(efa->v4?GL_QUADS:GL_TRIANGLES); glVertex2fv(tf->uv[0]); glVertex2fv(tf->uv[1]); glVertex2fv(tf->uv[2]); if(efa->v4) glVertex2fv(tf->uv[3]); glEnd(); } } } break; } case SI_UVDT_STRETCH_ANGLE: { float uvang1,uvang2,uvang3,uvang4; float ang1,ang2,ang3,ang4; float av1[3], av2[3], av3[3], av4[3]; /* use for 2d and 3d angle vectors */ float a; col[3] = 0.5; /* hard coded alpha, not that nice */ glShadeModel(GL_SMOOTH); for(efa= em->faces.first; efa; efa= efa->next) { tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); if(uvedit_face_visible(scene, ima, efa, tf)) { efa->tmp.p = tf; uv_copy_aspect(tf->uv, tf_uv, aspx, aspy); if(efa->v4) { #if 0 /* Simple but slow, better reuse normalized vectors */ uvang1 = RAD2DEG(Vec2Angle3(tf_uv[3], tf_uv[0], tf_uv[1])); ang1 = RAD2DEG(VecAngle3(efa->v4->co, efa->v1->co, efa->v2->co)); uvang2 = RAD2DEG(Vec2Angle3(tf_uv[0], tf_uv[1], tf_uv[2])); ang2 = RAD2DEG(VecAngle3(efa->v1->co, efa->v2->co, efa->v3->co)); uvang3 = RAD2DEG(Vec2Angle3(tf_uv[1], tf_uv[2], tf_uv[3])); ang3 = RAD2DEG(VecAngle3(efa->v2->co, efa->v3->co, efa->v4->co)); uvang4 = RAD2DEG(Vec2Angle3(tf_uv[2], tf_uv[3], tf_uv[0])); ang4 = RAD2DEG(VecAngle3(efa->v3->co, efa->v4->co, efa->v1->co)); #endif /* uv angles */ VECSUB2D(av1, tf_uv[3], tf_uv[0]); Normalize2(av1); VECSUB2D(av2, tf_uv[0], tf_uv[1]); Normalize2(av2); VECSUB2D(av3, tf_uv[1], tf_uv[2]); Normalize2(av3); VECSUB2D(av4, tf_uv[2], tf_uv[3]); Normalize2(av4); /* This is the correct angle however we are only comparing angles * uvang1 = 90-((NormalizedVecAngle2_2D(av1, av2) * 180.0/M_PI)-90);*/ uvang1 = NormalizedVecAngle2_2D(av1, av2)*180.0/M_PI; uvang2 = NormalizedVecAngle2_2D(av2, av3)*180.0/M_PI; uvang3 = NormalizedVecAngle2_2D(av3, av4)*180.0/M_PI; uvang4 = NormalizedVecAngle2_2D(av4, av1)*180.0/M_PI; /* 3d angles */ VECSUB(av1, efa->v4->co, efa->v1->co); Normalize(av1); VECSUB(av2, efa->v1->co, efa->v2->co); Normalize(av2); VECSUB(av3, efa->v2->co, efa->v3->co); Normalize(av3); VECSUB(av4, efa->v3->co, efa->v4->co); Normalize(av4); /* This is the correct angle however we are only comparing angles * ang1 = 90-((NormalizedVecAngle2(av1, av2) * 180.0/M_PI)-90);*/ ang1 = NormalizedVecAngle2(av1, av2)*180.0/M_PI; ang2 = NormalizedVecAngle2(av2, av3)*180.0/M_PI; ang3 = NormalizedVecAngle2(av3, av4)*180.0/M_PI; ang4 = NormalizedVecAngle2(av4, av1)*180.0/M_PI; glBegin(GL_QUADS); /* This simple makes the angles display worse then they really are ;) * 1.0-pow((1.0-a), 2) */ a = fabs(uvang1-ang1)/180.0; weight_to_rgb(1.0-pow((1.0-a), 2), col, col+1, col+2); glColor3fv(col); glVertex2fv(tf->uv[0]); a = fabs(uvang2-ang2)/180.0; weight_to_rgb(1.0-pow((1.0-a), 2), col, col+1, col+2); glColor3fv(col); glVertex2fv(tf->uv[1]); a = fabs(uvang3-ang3)/180.0; weight_to_rgb(1.0-pow((1.0-a), 2), col, col+1, col+2); glColor3fv(col); glVertex2fv(tf->uv[2]); a = fabs(uvang4-ang4)/180.0; weight_to_rgb(1.0-pow((1.0-a), 2), col, col+1, col+2); glColor3fv(col); glVertex2fv(tf->uv[3]); } else { #if 0 /* Simple but slow, better reuse normalized vectors */ uvang1 = RAD2DEG(Vec2Angle3(tf_uv[2], tf_uv[0], tf_uv[1])); ang1 = RAD2DEG(VecAngle3(efa->v3->co, efa->v1->co, efa->v2->co)); uvang2 = RAD2DEG(Vec2Angle3(tf_uv[0], tf_uv[1], tf_uv[2])); ang2 = RAD2DEG(VecAngle3(efa->v1->co, efa->v2->co, efa->v3->co)); uvang3 = M_PI-(uvang1+uvang2); ang3 = M_PI-(ang1+ang2); #endif /* uv angles */ VECSUB2D(av1, tf_uv[2], tf_uv[0]); Normalize2(av1); VECSUB2D(av2, tf_uv[0], tf_uv[1]); Normalize2(av2); VECSUB2D(av3, tf_uv[1], tf_uv[2]); Normalize2(av3); /* This is the correct angle however we are only comparing angles * uvang1 = 90-((NormalizedVecAngle2_2D(av1, av2) * 180.0/M_PI)-90); */ uvang1 = NormalizedVecAngle2_2D(av1, av2)*180.0/M_PI; uvang2 = NormalizedVecAngle2_2D(av2, av3)*180.0/M_PI; uvang3 = NormalizedVecAngle2_2D(av3, av1)*180.0/M_PI; /* 3d angles */ VECSUB(av1, efa->v3->co, efa->v1->co); Normalize(av1); VECSUB(av2, efa->v1->co, efa->v2->co); Normalize(av2); VECSUB(av3, efa->v2->co, efa->v3->co); Normalize(av3); /* This is the correct angle however we are only comparing angles * ang1 = 90-((NormalizedVecAngle2(av1, av2) * 180.0/M_PI)-90); */ ang1 = NormalizedVecAngle2(av1, av2)*180.0/M_PI; ang2 = NormalizedVecAngle2(av2, av3)*180.0/M_PI; ang3 = NormalizedVecAngle2(av3, av1)*180.0/M_PI; /* This simple makes the angles display worse then they really are ;) * 1.0-pow((1.0-a), 2) */ glBegin(GL_TRIANGLES); a = fabs(uvang1-ang1)/180.0; weight_to_rgb(1.0-pow((1.0-a), 2), col, col+1, col+2); glColor3fv(col); glVertex2fv(tf->uv[0]); a = fabs(uvang2-ang2)/180.0; weight_to_rgb(1.0-pow((1.0-a), 2), col, col+1, col+2); glColor3fv(col); glVertex2fv(tf->uv[1]); a = fabs(uvang3-ang3)/180.0; weight_to_rgb(1.0-pow((1.0-a), 2), col, col+1, col+2); glColor3fv(col); glVertex2fv(tf->uv[2]); } glEnd(); } else { if(tf == activetf) activetf= NULL; efa->tmp.p = NULL; } } glShadeModel(GL_FLAT); break; } } }
// scan ship objects for radar ------------------------------------------------ // INLINE void RadarScanShipObjects() { GenObject *targetobj = NULL; for ( GenObject *walkobjs = FetchFirstShip(); walkobjs; ) { // set color for normal objects int rocolor = NORMAL_RADAR_OBJ_COL2; if ( AUX_ENABLE_DEPTHCUED_RADAR_DOTS && !AUX_ENABLE_ELITE_RADAR ) { Vertex3 shippos; FetchTVector( walkobjs->ObjPosition, &shippos ); Vertex3 myshippos; FetchTVector( MyShip->ObjPosition, &myshippos ); Vector3 dist; VECSUB( &dist, &shippos, &myshippos ); geomv_t vx = dist.X; geomv_t vy = dist.Y; geomv_t vz = dist.Z; ABS_GEOMV( vx ); ABS_GEOMV( vy ); ABS_GEOMV( vz ); int distance = 0; if ( ( vx > GEOMV_VANISHING ) || ( vy > GEOMV_VANISHING ) || ( vz > GEOMV_VANISHING ) ) { distance = GEOMV_TO_INT( VctLenX( &dist ) ); } if ( distance > 4096 ) { rocolor = NORMAL_RADAR_OBJ_COL3; } else if ( distance > 2048 ) { rocolor = NORMAL_RADAR_OBJ_COL2; } else { rocolor = NORMAL_RADAR_OBJ_COL1; } } // ensure that the target object is drawn last if ( walkobjs->HostObjNumber == TargetObjNumber ) { if ( targetobj == NULL ) { targetobj = walkobjs; if ( ( walkobjs = walkobjs->NextObj ) == NULL ) { walkobjs = targetobj; } continue; } rocolor = TARGET_RADAR_OBJ_COL; } // depict ship's position on radar if ( AUX_ENABLE_ELITE_RADAR ) { CalcDrawEliteRadarObj( walkobjs, rocolor ); } else { CalcDrawRadarObj( walkobjs, rocolor ); } if ( walkobjs == targetobj ) { break; } if ( ( walkobjs = walkobjs->NextObj ) == NULL ) { walkobjs = targetobj; } } }
/* BME_bevel_split_edge() is the main math work-house; its responsibilities are: * using the vert and the loop passed, get or make the split vert, set its coordinates * and transform properties, and set the max limits. * Finally, return the split vert. */ static BME_Vert *BME_bevel_split_edge(BME_Mesh *bm, BME_Vert *v, BME_Vert *v1, BME_Loop *l, float *up_vec, float value, BME_TransData_Head *td) { BME_TransData *vtd, *vtd1, *vtd2; BME_Vert *sv, *v2, *v3, *ov; BME_Loop *lv1, *lv2; BME_Edge *ne, *e1, *e2; float maxfactor, scale, len, dis, vec1[3], vec2[3], t_up_vec[3]; int is_edge, forward, is_split_vert; if (l == NULL) { /* what you call operator overloading in C :) * I wanted to use the same function for both wire edges and poly loops * so... here we walk around edges to find the needed verts */ forward = 1; is_split_vert = 0; if (v->edge == NULL) { //printf("We can't split a loose vert's edge!\n"); return NULL; } e1 = v->edge; /* we just use the first two edges */ e2 = BME_disk_nextedge(v->edge, v); if (e1 == e2) { //printf("You need at least two edges to use BME_bevel_split_edge()\n"); return NULL; } v2 = BME_edge_getothervert(e1, v); v3 = BME_edge_getothervert(e2, v); if (v1 != v2 && v1 != v3) { //printf("Error: more than 2 edges in v's disk cycle, or v1 does not share an edge with v\n"); return NULL; } if (v1 == v2) { v2 = v3; } else { e1 = e2; } ov = BME_edge_getothervert(e1,v); sv = BME_split_edge(bm,v,e1,&ne,0); //BME_data_interp_from_verts(bm, v, ov, sv, 0.25); /*this is technically wrong...*/ //BME_data_interp_from_faceverts(bm, v, ov, sv, 0.25); //BME_data_interp_from_faceverts(bm, ov, v, sv, 0.25); BME_assign_transdata(td, bm, sv, sv->co, sv->co, NULL, sv->co, 0, -1, -1, NULL); /* quick default */ sv->tflag1 |= BME_BEVEL_BEVEL; ne->tflag1 = BME_BEVEL_ORIG; /* mark edge as original, even though it isn't */ BME_bevel_get_vec(vec1,v1,v,td); BME_bevel_get_vec(vec2,v2,v,td); cross_v3_v3v3(t_up_vec,vec1,vec2); normalize_v3(t_up_vec); up_vec = t_up_vec; } else { /* establish loop direction */ if (l->v == v) { forward = 1; lv1 = l->next; lv2 = l->prev; v1 = l->next->v; v2 = l->prev->v; } else if (l->next->v == v) { forward = 0; lv1 = l; lv2 = l->next->next; v1 = l->v; v2 = l->next->next->v; } else { //printf("ERROR: BME_bevel_split_edge() - v must be adjacent to l\n"); return NULL; } if (BME_bevel_is_split_vert(lv1)) { is_split_vert = 1; sv = v1; if (forward) v1 = l->next->next->v; else v1 = l->prev->v; } else { is_split_vert = 0; ov = BME_edge_getothervert(l->e,v); sv = BME_split_edge(bm,v,l->e,&ne,0); //BME_data_interp_from_verts(bm, v, ov, sv, 0.25); /*this is technically wrong...*/ //BME_data_interp_from_faceverts(bm, v, ov, sv, 0.25); //BME_data_interp_from_faceverts(bm, ov, v, sv, 0.25); BME_assign_transdata(td, bm, sv, sv->co, sv->co, NULL, sv->co, 0, -1, -1, NULL); /* quick default */ sv->tflag1 |= BME_BEVEL_BEVEL; ne->tflag1 = BME_BEVEL_ORIG; /* mark edge as original, even though it isn't */ } if (BME_bevel_is_split_vert(lv2)) { if (forward) v2 = lv2->prev->v; else v2 = lv2->next->v; } } is_edge = BME_bevel_get_vec(vec1,v,v1,td); /* get the vector we will be projecting onto */ BME_bevel_get_vec(vec2,v,v2,td); /* get the vector we will be projecting parallel to */ len = len_v3(vec1); normalize_v3(vec1); vtd = BME_get_transdata(td, sv); vtd1 = BME_get_transdata(td, v); vtd2 = BME_get_transdata(td,v1); if (vtd1->loc == NULL) { /* this is a vert with data only for calculating initial weights */ if (vtd1->weight < 0) { vtd1->weight = 0; } scale = vtd1->weight/vtd1->factor; if (!vtd1->max) { vtd1->max = BME_new_transdata_float(td); *vtd1->max = -1; } } else { scale = vtd1->weight; } vtd->max = vtd1->max; if (is_edge && vtd1->loc != NULL) { maxfactor = vtd1->maxfactor; } else { maxfactor = scale*BME_bevel_project_vec(vec1,vec2,up_vec,forward,td); if (vtd->maxfactor > 0 && vtd->maxfactor < maxfactor) { maxfactor = vtd->maxfactor; } } dis = (v1->tflag1 & BME_BEVEL_ORIG)? len/3 : len/2; if (is_edge || dis > maxfactor*value) { dis = maxfactor*value; } VECADDFAC(sv->co,v->co,vec1,dis); VECSUB(vec1,sv->co,vtd1->org); dis = len_v3(vec1); normalize_v3(vec1); BME_assign_transdata(td, bm, sv, vtd1->org, vtd1->org, vec1, sv->co, dis, scale, maxfactor, vtd->max); return sv; }
static int chunk_object(Mesh *ret, FPOS *pfo, Mesh::Coord scale, struct Bone ***bones, int num){ char *s, *name = NULL; int n, i, j; Mesh::Attrib *patr; char line[512], *cur; Mesh::Index atr = (Mesh::Index)-1; int shading = 0; double facet = 0.; struct Bone *bone = NULL; int mirror = 0, mirror_axis = 0, mirrors = 0; int mirrornv[3]; pfo->is->getline(line, sizeof line); s = line; if(!s) return NULL; cur = s; s = quotok(&cur); name = (char*)malloc(strlen(s) + 1); strcpy(name, s); if(bones && *bones){ // (*bones)[num] = malloc(sizeof(struct Bone)); bone = (*bones)[num]; // VECNULL(bone->joint); // bone->depth = 0; // bone->parent = NULL; } /* forward until vertex chunk */ while((pfo->is->getline(line, sizeof line), !pfo->is->eof()) && !(cur = line, (s = quotok(&cur)) && !stricmp(s, "vertex"))){ if(!stricmp(s, "shading")) shading = atoi(quotok(&cur)); else if(!stricmp(s, "facet")) facet = atof(quotok(&cur)); else if(!stricmp(s, "depth")){ if(bone){ bone->depth = atoi(quotok(&cur)); if(num){ int j; for(j = num - 1; 0 <= j; j--){ if((*bones)[j]->depth < bone->depth){ bone->parent = (*bones)[j]; bone->nextSibling = (*bones)[j]->children; (*bones)[j]->children = bone; break; } } } else bone->parent = NULL; } } else if(!stricmp(s, "mirror")){ mirror = atoi(quotok(&cur)); } else if(!stricmp(s, "mirror_axis")){ mirror_axis = atoi(quotok(&cur)); // There could be multiple mirrors for a object, so we count it for allocating space. mirrors = 0; for(int m = 0; m < 3; m++) if(mirror_axis & (1 << m)) mirrors++; } } if(!s) return 0; /* multiple vertex chunks leads to an error. */ if(ret->v) return 0; s = quotok(&cur); ret->nv = n = atoi(s); // Mirroring generates twice as many vertices for each mirror, i.e. 2 power count of mirrors. ret->v = (Mesh::Coord(*)[3])malloc(n * (mirror ? 1 << mirrors : 1) * sizeof *ret->v); i = 0; while(i < n && (pfo->is->getline(line, sizeof line), s = line, !pfo->is->eof())){ if(!s) return NULL; if(*s == '{') break; cur = line; for(j = 0; j < 3 && (s = quotok(&cur)); j++) ret->v[i][j] = (Mesh::Coord)atof(s) * (scale); i++; } if(mirror){ for(int m = 0; m < 3; m++){ // Check for each axis if it's flagged for mirroring. if(mirror_axis & (1 << m)){ // Mirrored vertices have simply negated coordinate along axis perpendicular to the mirror. for(i = 0; i < n; i++){ VECCPY(ret->v[i+n], ret->v[i]); ret->v[i+n][m] *= -1; } mirrornv[m] = n; n = ret->nv *= 2; } } } /* forward until face chunk */ while((pfo->is->getline(line, sizeof line), !pfo->is->eof()) && !(cur = line, (s = quotok(&cur)) && !stricmp(s, "face"))); /* multiple face chunks leads to an error. */ if(ret->p) return 0; s = quotok(&cur); ret->np = n = atoi(s); // Mirroring generates twice as many vertices for each mirror, i.e. 2 power count of mirrors. ret->p = (Mesh::Primitive**)malloc(n * (mirror ? 1 << mirrors : 1) * sizeof *ret->p); i = 0; while(i <= n && (pfo->is->getline(line, sizeof line), s = line, !pfo->is->eof())){ int polys; Mesh::ElemType type = Mesh::ET_Polygon; Mesh::Index verts[4], norms[4], uvs[4]; /* vertex count is capped at 4 in Metasequoia */ if(!s) return NULL; if(*s == '{') break; else if(strchr(s, '}')) break; cur = line; s = quotok(&cur); polys = atoi(s); // Polygons with two vertices (edges) are treated as bone segments. if(polys == 2){ while(s = quotok(&cur)) if(!strnicmp(s, "V(", sizeof"V("-1)){ char *p = &s[sizeof"V("-1]; if(bone){ int vind[2]; avec3_t org; double sd; vind[0] = atoi(p); quotok(&p); vind[1] = atoi(p); // Set to measure distance from parent bonee's joint position. if(bone->parent){ VECCPY(org, bone->parent->joint); } else{ VECNULL(org); } // Choose the farther vertex of the edge as the bone joint, since the user of Metasequoia has no // way to figure out which is earlier in the data structure. if(VECSDIST(org, ret->v[vind[0]]) < VECSDIST(org, ret->v[vind[1]])){ VECCPY(bone->joint, ret->v[vind[1]]); } else{ VECCPY(bone->joint, ret->v[vind[0]]); } } } // Exclude this polygon (line) from drawing n--; ret->np--; continue; } else while(s = quotok(&cur)){ /* cache vertex indices temporarily until presence of UV map is determined. */ if(!strnicmp(s, "V(", sizeof"V("-1)){ char *p = &s[sizeof"V("-1]; /* face direction conversion */ for(j = 0; j < polys; j++) verts[polys - j - 1] = (Mesh::Coord)strtol(p, &p, 10); /* Metasequoia never writes normal vector directions as part of data file, so we always need to calculate them, regardless of whether smoothshading is enabled or not. For drawing performance, we choose to calculate normal vectors here, not rendering or loading time of actual use. Sure we could add another polygon type to inform renderer to calculate them on runtime, but I prefer leaving runtime routine simpler (thus hopefully faster). The following code fragment is just the same as standard suf.c.*/ { unsigned short a, b, c, vvi; double vv[3]; int i = polys; /* there's an occasion that three consequative vertices lie on a line, so we need to find the valid triplet from all possible cases. note that polygon normal is calculated the same direction, as long as the polygon is convex. */ for(a = 0; a < i; a++) for(b = a+1; b < i; b++) for(c = b+1; c < i; c++){ double *v0, *v1, *v2; double v01[3], v02[3]; v0 = ret->v[verts[a]]; v1 = ret->v[verts[b]]; v2 = ret->v[verts[c]]; VECSUB(v01, v0, v1); VECSUB(v02, v0, v2); VECVP(vv, v01, v02); if(vv[0] != 0. || vv[1] != 0. || vv[2] != 0.) goto abc_break; } abc_break: /* polygon on a line */ if(a == i){ Mesh::Coord nullvec[3]; VECNULL(nullvec); vvi = ret->add_vertex(nullvec); for(j = 0; j < i; j++) norms[j] = vvi; break; } /* this normalization isn't necessary, but it would improve memory space efficiency, for normal vectors tend to point the same direction with different length. */ VECNORMIN(vv); vvi = ret->add_vertex(vv); for(j = 0; j < i; j++) norms[j] = vvi; } } else if(!strnicmp(s, "M(", sizeof"M("-1)){ atr = (Mesh::Index)atoi(&s[sizeof"M("-1]); assert(atr < 30000); } else if(!strnicmp(s, "UV(", sizeof"UV("-1)){ char *q = &s[sizeof"UV("-1]; Mesh::Coord uv[3]; type = Mesh::ET_UVPolygon; for(j = 0; j < polys; j++){ uv[0] = strtod(q, &q); uv[1] = strtod(q, &q); uv[2] = 0.; uvs[polys - j - 1] = ret->add_vertex(uv); } } } if(atr == (Mesh::Index)-1){ fprintf(stderr, "Error: Material is not specified! poly %d\n", i); return 0; } if(type == Mesh::ET_UVPolygon){ struct Mesh::UVPolygon *p; type = Mesh::ET_UVPolygon; ret->p[i] = (Mesh::Primitive*)malloc(offsetof(Mesh::UVPolygon, v) + polys * sizeof(struct Mesh::UVPolygon::Vertex)); p = &ret->p[i]->uv; p->t = Mesh::ET_UVPolygon; p->n = polys; p->atr = atr; for(j = 0; j < polys; j++){ p->v[j].pos = verts[j]; p->v[j].nrm = norms[j]; p->v[j].tex = uvs[j]; } } else{ Mesh::Polygon *p; ret->p[i] = (Mesh::Primitive*)malloc(offsetof(Mesh::UVPolygon, v) + polys * sizeof(Mesh::Index[2])); p = &ret->p[i]->p; p->t = Mesh::ET_Polygon; p->n = polys; p->atr = atr; assert(p->atr < 30000); for(j = 0; j < polys; j++){ p->v[j].pos = verts[j]; p->v[j].nrm = norms[j]; } } i++; } for(int m = 0; m < 3; m++) if(mirror_axis & (1 << m)){ n = ret->np; for(i = 0; i < n; i++){ if(ret->p[i]->t == Mesh::ET_UVPolygon){ Mesh::UVPolygon *p, *p0 = &ret->p[i]->uv; ret->p[i+n] = (Mesh::Primitive*)malloc(offsetof(Mesh::UVPolygon, v) + p0->n * sizeof(Mesh::UVPolygon::Vertex)); p = &ret->p[i+n]->uv; p->t = Mesh::ET_UVPolygon; p->n = p0->n; p->atr = p0->atr; for(j = 0; j < p0->n; j++){ avec3_t vecn; // Flip face direction because it's mirrored. p->v[j].pos = p0->v[p0->n-j-1].pos + mirrornv[m]; VECCPY(vecn, ret->v[p0->v[p0->n-j-1].nrm]); // Normal vector's coordinate along mirror axis must be negated just like position vector. vecn[m] *= -1; p->v[j].nrm = ret->add_vertex(vecn); p->v[j].tex = p0->v[p0->n-j-1].tex; // Keep texture coord to the same. } } else{ Mesh::Polygon *p, *p0 = &ret->p[i]->p; ret->p[i+n] = (Mesh::Primitive*)malloc(offsetof(Mesh::Polygon, v) + p0->n * sizeof(Mesh::Index[2])); p = &ret->p[i+n]->p; p->t = Mesh::ET_Polygon; p->n = p0->n; p->atr = p0->atr; for(j = 0; j < p0->n; j++){ avec3_t vecn; // Flip face direction because it's mirrored. p->v[j].pos = p0->v[p0->n-j-1].pos + mirrornv[m]; VECCPY(vecn, ret->v[p0->v[p0->n-j-1].nrm]); // Normal vector's coordinate along mirror axis must be negated just like position vector. vecn[m] *= -1; p->v[j].nrm = ret->add_vertex(vecn); } } } ret->np *= 2; } if(shading){ double cf; cf = cos(facet / deg_per_rad); for(i = 0; i < ret->np; i++) for(j = 0; j < ret->p[i]->uv.n; j++){ int k, l, is = 0; Mesh::Polygon::Vertex *shares[32]; Mesh::Polygon::Vertex &vertex = ret->p[i]->t == Mesh::ET_Polygon ? ret->p[i]->p.v[j] : ret->p[i]->uv.v[j]; avec3_t norm; for(k = 0; k < ret->np; k++) for(l = 0; l < ret->p[k]->uv.n; l++){ Mesh::Polygon::Vertex &vertex2 = ret->p[k]->t == Mesh::ET_Polygon ? ret->p[k]->p.v[l] : ret->p[k]->uv.v[l]; if(vertex.pos == vertex2.pos && cf < VECSP(ret->v[vertex2.nrm], ret->v[vertex.nrm])){ if(is == numof(shares)) break; shares[is++] = &vertex2; } } for(k = 0; k < is; k++) if(shares[k]->nrm != vertex.nrm) break; if(k == is) continue; VECNULL(norm); for(k = 0; k < is; k++) VECADDIN(norm, ret->v[shares[k]->nrm]); VECNORMIN(norm); l = ret->add_vertex(norm); for(k = 0; k < is; k++) shares[k]->nrm = l; } } if(!(s = ftok(pfo)) || s[0] != '}') return 0; return 1; }
/* * Function adapted from David Eberly's distance tools (LGPL) * http://www.geometrictools.com/LibFoundation/Distance/Distance.html */ static float nearest_point_in_tri_surface(const float *v0,const float *v1,const float *v2,const float *p, int *v, int *e, float *nearest ) { float diff[3]; float e0[3]; float e1[3]; float A00; float A01; float A11; float B0; float B1; float C; float Det; float S; float T; float sqrDist; int lv = -1, le = -1; VECSUB(diff, v0, p); VECSUB(e0, v1, v0); VECSUB(e1, v2, v0); A00 = INPR ( e0, e0 ); A01 = INPR( e0, e1 ); A11 = INPR ( e1, e1 ); B0 = INPR( diff, e0 ); B1 = INPR( diff, e1 ); C = INPR( diff, diff ); Det = fabs( A00 * A11 - A01 * A01 ); S = A01 * B1 - A11 * B0; T = A01 * B0 - A00 * B1; if ( S + T <= Det ) { if ( S < 0.0f ) { if ( T < 0.0f ) // Region 4 { if ( B0 < 0.0f ) { T = 0.0f; if ( -B0 >= A00 ) { S = (float)1.0; sqrDist = A00 + 2.0f * B0 + C; lv = 1; } else { if(fabsf(A00) > FLT_EPSILON) S = -B0/A00; else S = 0.0f; sqrDist = B0 * S + C; le = 0; } } else { S = 0.0f; if ( B1 >= 0.0f ) { T = 0.0f; sqrDist = C; lv = 0; } else if ( -B1 >= A11 ) { T = 1.0f; sqrDist = A11 + 2.0f * B1 + C; lv = 2; } else { if(fabsf(A11) > FLT_EPSILON) T = -B1 / A11; else T = 0.0f; sqrDist = B1 * T + C; le = 1; } } } else // Region 3 { S = 0.0f; if ( B1 >= 0.0f ) { T = 0.0f; sqrDist = C; lv = 0; } else if ( -B1 >= A11 ) { T = 1.0f; sqrDist = A11 + 2.0f * B1 + C; lv = 2; } else { if(fabsf(A11) > FLT_EPSILON) T = -B1 / A11; else T = 0.0; sqrDist = B1 * T + C; le = 1; } } } else if ( T < 0.0f ) // Region 5 { T = 0.0f; if ( B0 >= 0.0f ) { S = 0.0f; sqrDist = C; lv = 0; } else if ( -B0 >= A00 ) { S = 1.0f; sqrDist = A00 + 2.0f * B0 + C; lv = 1; } else { if(fabsf(A00) > FLT_EPSILON) S = -B0 / A00; else S = 0.0f; sqrDist = B0 * S + C; le = 0; } } else // Region 0 { // Minimum at interior lv float invDet; if(fabsf(Det) > FLT_EPSILON) invDet = 1.0f / Det; else invDet = 0.0f; S *= invDet; T *= invDet; sqrDist = S * ( A00 * S + A01 * T + 2.0f * B0) + T * ( A01 * S + A11 * T + 2.0f * B1 ) + C; } } else { float tmp0, tmp1, numer, denom; if ( S < 0.0f ) // Region 2 { tmp0 = A01 + B0; tmp1 = A11 + B1; if ( tmp1 > tmp0 ) { numer = tmp1 - tmp0; denom = A00 - 2.0f * A01 + A11; if ( numer >= denom ) { S = 1.0f; T = 0.0f; sqrDist = A00 + 2.0f * B0 + C; lv = 1; } else { if(fabsf(denom) > FLT_EPSILON) S = numer / denom; else S = 0.0f; T = 1.0f - S; sqrDist = S * ( A00 * S + A01 * T + 2.0f * B0 ) + T * ( A01 * S + A11 * T + 2.0f * B1 ) + C; le = 2; } } else { S = 0.0f; if ( tmp1 <= 0.0f ) { T = 1.0f; sqrDist = A11 + 2.0f * B1 + C; lv = 2; } else if ( B1 >= 0.0f ) { T = 0.0f; sqrDist = C; lv = 0; } else { if(fabsf(A11) > FLT_EPSILON) T = -B1 / A11; else T = 0.0f; sqrDist = B1 * T + C; le = 1; } } } else if ( T < 0.0f ) // Region 6 { tmp0 = A01 + B1; tmp1 = A00 + B0; if ( tmp1 > tmp0 ) { numer = tmp1 - tmp0; denom = A00 - 2.0f * A01 + A11; if ( numer >= denom ) { T = 1.0f; S = 0.0f; sqrDist = A11 + 2.0f * B1 + C; lv = 2; } else { if(fabsf(denom) > FLT_EPSILON) T = numer / denom; else T = 0.0f; S = 1.0f - T; sqrDist = S * ( A00 * S + A01 * T + 2.0f * B0 ) + T * ( A01 * S + A11 * T + 2.0f * B1 ) + C; le = 2; } } else { T = 0.0f; if ( tmp1 <= 0.0f ) { S = 1.0f; sqrDist = A00 + 2.0f * B0 + C; lv = 1; } else if ( B0 >= 0.0f ) { S = 0.0f; sqrDist = C; lv = 0; } else { if(fabsf(A00) > FLT_EPSILON) S = -B0 / A00; else S = 0.0f; sqrDist = B0 * S + C; le = 0; } } } else // Region 1 { numer = A11 + B1 - A01 - B0; if ( numer <= 0.0f ) { S = 0.0f; T = 1.0f; sqrDist = A11 + 2.0f * B1 + C; lv = 2; } else { denom = A00 - 2.0f * A01 + A11; if ( numer >= denom ) { S = 1.0f; T = 0.0f; sqrDist = A00 + 2.0f * B0 + C; lv = 1; } else { if(fabsf(denom) > FLT_EPSILON) S = numer / denom; else S = 0.0f; T = 1.0f - S; sqrDist = S * ( A00 * S + A01 * T + 2.0f * B0 ) + T * ( A01 * S + A11 * T + 2.0f * B1 ) + C; le = 2; } } } } // Account for numerical round-off error if ( sqrDist < FLT_EPSILON ) sqrDist = 0.0f; { float w[3], x[3], y[3], z[3]; VECCOPY(w, v0); VECCOPY(x, e0); mul_v3_fl(x, S); VECCOPY(y, e1); mul_v3_fl(y, T); VECADD(z, w, x); VECADD(z, z, y); //VECSUB(d, p, z); VECCOPY(nearest, z); // d = p - ( v0 + S * e0 + T * e1 ); } *v = lv; *e = le; return sqrDist; }
void draw_volume(ARegion *ar, GPUTexture *tex, float *min, float *max, int res[3], float dx, GPUTexture *tex_shadow) { RegionView3D *rv3d= ar->regiondata; float viewnormal[3]; int i, j, n, good_index; float d, d0, dd, ds; float *points = NULL; int numpoints = 0; float cor[3] = {1.,1.,1.}; int gl_depth = 0, gl_blend = 0; /* draw slices of smoke is adapted from c++ code authored by: Johannes Schmid and Ingemar Rask, 2006, [email protected] */ float cv[][3] = { {1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, {1.0f, -1.0f, 1.0f}, {1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}, {1.0f, -1.0f, -1.0f} }; // edges have the form edges[n][0][xyz] + t*edges[n][1][xyz] float edges[12][2][3] = { {{1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}}, {{-1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}}, {{-1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}}, {{1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}}, {{-1.0f, 1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}}, {{-1.0f, -1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}}, {{-1.0f, -1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}}, {{-1.0f, 1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}} }; /* Fragment program to calculate the view3d of smoke */ /* using 2 textures, density and shadow */ const char *text = "!!ARBfp1.0\n" "PARAM dx = program.local[0];\n" "PARAM darkness = program.local[1];\n" "PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01};\n" "TEMP temp, shadow, value;\n" "TEX temp, fragment.texcoord[0], texture[0], 3D;\n" "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n" "MUL value, temp, darkness;\n" "MUL value, value, dx;\n" "MUL value, value, f;\n" "EX2 temp, -value.r;\n" "SUB temp.a, 1.0, temp.r;\n" "MUL temp.r, temp.r, shadow.r;\n" "MUL temp.g, temp.g, shadow.r;\n" "MUL temp.b, temp.b, shadow.r;\n" "MOV result.color, temp;\n" "END\n"; GLuint prog; float size[3]; if(!tex) { printf("Could not allocate 3D texture for 3D View smoke drawing.\n"); return; } tstart(); VECSUB(size, max, min); // maxx, maxy, maxz cv[0][0] = max[0]; cv[0][1] = max[1]; cv[0][2] = max[2]; // minx, maxy, maxz cv[1][0] = min[0]; cv[1][1] = max[1]; cv[1][2] = max[2]; // minx, miny, maxz cv[2][0] = min[0]; cv[2][1] = min[1]; cv[2][2] = max[2]; // maxx, miny, maxz cv[3][0] = max[0]; cv[3][1] = min[1]; cv[3][2] = max[2]; // maxx, maxy, minz cv[4][0] = max[0]; cv[4][1] = max[1]; cv[4][2] = min[2]; // minx, maxy, minz cv[5][0] = min[0]; cv[5][1] = max[1]; cv[5][2] = min[2]; // minx, miny, minz cv[6][0] = min[0]; cv[6][1] = min[1]; cv[6][2] = min[2]; // maxx, miny, minz cv[7][0] = max[0]; cv[7][1] = min[1]; cv[7][2] = min[2]; VECCOPY(edges[0][0], cv[4]); // maxx, maxy, minz VECCOPY(edges[1][0], cv[5]); // minx, maxy, minz VECCOPY(edges[2][0], cv[6]); // minx, miny, minz VECCOPY(edges[3][0], cv[7]); // maxx, miny, minz VECCOPY(edges[4][0], cv[3]); // maxx, miny, maxz VECCOPY(edges[5][0], cv[2]); // minx, miny, maxz VECCOPY(edges[6][0], cv[6]); // minx, miny, minz VECCOPY(edges[7][0], cv[7]); // maxx, miny, minz VECCOPY(edges[8][0], cv[1]); // minx, maxy, maxz VECCOPY(edges[9][0], cv[2]); // minx, miny, maxz VECCOPY(edges[10][0], cv[6]); // minx, miny, minz VECCOPY(edges[11][0], cv[5]); // minx, maxy, minz // printf("size x: %f, y: %f, z: %f\n", size[0], size[1], size[2]); // printf("min[2]: %f, max[2]: %f\n", min[2], max[2]); edges[0][1][2] = size[2]; edges[1][1][2] = size[2]; edges[2][1][2] = size[2]; edges[3][1][2] = size[2]; edges[4][1][1] = size[1]; edges[5][1][1] = size[1]; edges[6][1][1] = size[1]; edges[7][1][1] = size[1]; edges[8][1][0] = size[0]; edges[9][1][0] = size[0]; edges[10][1][0] = size[0]; edges[11][1][0] = size[0]; glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend); glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth); glLoadMatrixf(rv3d->viewmat); // glMultMatrixf(ob->obmat); glDepthMask(GL_FALSE); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /* printf("Viewinv:\n"); printf("%f, %f, %f\n", rv3d->viewinv[0][0], rv3d->viewinv[0][1], rv3d->viewinv[0][2]); printf("%f, %f, %f\n", rv3d->viewinv[1][0], rv3d->viewinv[1][1], rv3d->viewinv[1][2]); printf("%f, %f, %f\n", rv3d->viewinv[2][0], rv3d->viewinv[2][1], rv3d->viewinv[2][2]); */ // get view vector VECCOPY(viewnormal, rv3d->viewinv[2]); normalize_v3(viewnormal); // find cube vertex that is closest to the viewer for (i=0; i<8; i++) { float x,y,z; x = cv[i][0] - viewnormal[0]; y = cv[i][1] - viewnormal[1]; z = cv[i][2] - viewnormal[2]; if ((x>=min[0])&&(x<=max[0]) &&(y>=min[1])&&(y<=max[1]) &&(z>=min[2])&&(z<=max[2])) { break; } } if(i >= 8) { /* fallback, avoid using buffer over-run */ i= 0; } // printf("i: %d\n", i); // printf("point %f, %f, %f\n", cv[i][0], cv[i][1], cv[i][2]); if (GL_TRUE == glewIsSupported("GL_ARB_fragment_program")) { glEnable(GL_FRAGMENT_PROGRAM_ARB); glGenProgramsARB(1, &prog); glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, prog); glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(text), text); // cell spacing glProgramLocalParameter4fARB (GL_FRAGMENT_PROGRAM_ARB, 0, dx, dx, dx, 1.0); // custom parameter for smoke style (higher = thicker) glProgramLocalParameter4fARB (GL_FRAGMENT_PROGRAM_ARB, 1, 7.0, 7.0, 7.0, 1.0); } else printf("Your gfx card does not support 3D View smoke drawing.\n"); GPU_texture_bind(tex, 0); if(tex_shadow) GPU_texture_bind(tex_shadow, 1); else printf("No volume shadow\n"); if (!GPU_non_power_of_two_support()) { cor[0] = (float)res[0]/(float)larger_pow2(res[0]); cor[1] = (float)res[1]/(float)larger_pow2(res[1]); cor[2] = (float)res[2]/(float)larger_pow2(res[2]); } // our slices are defined by the plane equation a*x + b*y +c*z + d = 0 // (a,b,c), the plane normal, are given by viewdir // d is the parameter along the view direction. the first d is given by // inserting previously found vertex into the plane equation d0 = (viewnormal[0]*cv[i][0] + viewnormal[1]*cv[i][1] + viewnormal[2]*cv[i][2]); ds = (ABS(viewnormal[0])*size[0] + ABS(viewnormal[1])*size[1] + ABS(viewnormal[2])*size[2]); dd = 0.05; // ds/512.0f; n = 0; good_index = i; // printf("d0: %f, dd: %f, ds: %f\n\n", d0, dd, ds); points = MEM_callocN(sizeof(float)*12*3, "smoke_points_preview"); while(1) { float p0[3]; float tmp_point[3], tmp_point2[3]; if(dd*(float)n > ds) break; VECCOPY(tmp_point, viewnormal); mul_v3_fl(tmp_point, -dd*((ds/dd)-(float)n)); VECADD(tmp_point2, cv[good_index], tmp_point); d = INPR(tmp_point2, viewnormal); // printf("my d: %f\n", d); // intersect_edges returns the intersection points of all cube edges with // the given plane that lie within the cube numpoints = intersect_edges(points, viewnormal[0], viewnormal[1], viewnormal[2], -d, edges); // printf("points: %d\n", numpoints); if (numpoints > 2) { VECCOPY(p0, points); // sort points to get a convex polygon for(i = 1; i < numpoints - 1; i++) { for(j = i + 1; j < numpoints; j++) { if(!convex(p0, viewnormal, &points[j * 3], &points[i * 3])) { float tmp2[3]; VECCOPY(tmp2, &points[j * 3]); VECCOPY(&points[j * 3], &points[i * 3]); VECCOPY(&points[i * 3], tmp2); } } } // printf("numpoints: %d\n", numpoints); glBegin(GL_POLYGON); glColor3f(1.0, 1.0, 1.0); for (i = 0; i < numpoints; i++) { glTexCoord3d((points[i * 3 + 0] - min[0] )*cor[0]/size[0], (points[i * 3 + 1] - min[1])*cor[1]/size[1], (points[i * 3 + 2] - min[2])*cor[2]/size[2]); glVertex3f(points[i * 3 + 0], points[i * 3 + 1], points[i * 3 + 2]); } glEnd(); } n++; } tend(); // printf ( "Draw Time: %f\n",( float ) tval() ); if(tex_shadow) GPU_texture_unbind(tex_shadow); GPU_texture_unbind(tex); if(GLEW_ARB_fragment_program) { glDisable(GL_FRAGMENT_PROGRAM_ARB); glDeleteProgramsARB(1, &prog); } MEM_freeN(points); if(!gl_blend) glDisable(GL_BLEND); if(gl_depth) { glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); } }
int Fbonded_eval_impr_term(Fbonded *p, const ImprPrm *prm, const dvec *pos_i, const dvec *pos_j, const dvec *pos_k, const dvec *pos_l, dvec *f_i, dvec *f_j, dvec *f_k, dvec *f_l, dreal *u, dreal virial[NELEMS_VIRIAL]) { dvec r12, r23, r34; dvec A, B, C; dreal rA, rB, rC; dreal cos_phi, sin_phi, phi; dreal K, K1; dvec f1, f2, f3; dreal k = prm->k_impr; dreal delta = prm->psi0; dreal diff; Domain_shortest_vec(p->domain, &r12, pos_i, pos_j); Domain_shortest_vec(p->domain, &r23, pos_j, pos_k); Domain_shortest_vec(p->domain, &r34, pos_k, pos_l); VECCROSS(A, r12, r23); VECCROSS(B, r23, r34); VECCROSS(C, r23, A); rA = 1 / sqrt(VECLEN2(A)); rB = 1 / sqrt(VECLEN2(B)); rC = 1 / sqrt(VECLEN2(C)); VECMUL(B, rB, B); /* normalize B */ cos_phi = VECDOT(A, B) * rA; sin_phi = VECDOT(C, B) * rC; phi = -atan2(sin_phi, cos_phi); diff = phi - delta; if (diff < -M_PI) diff += 2.0 * M_PI; else if (diff > M_PI) diff -= 2.0 * M_PI; K = k * diff * diff; K1 = 2.0 * k * diff; if (fabs(sin_phi) > 0.1) { dvec dcosdA, dcosdB; dvec tv1, tv2; /* use sine version to avoid 1/cos terms */ VECMUL(A, rA, A); /* normalize A */ VECMSUB(dcosdA, cos_phi, A, B); VECMUL(dcosdA, rA, dcosdA); VECMSUB(dcosdB, cos_phi, B, A); VECMUL(dcosdB, rB, dcosdB); K1 /= sin_phi; VECCROSS(f1, r23, dcosdA); VECMUL(f1, K1, f1); VECCROSS(f3, dcosdB, r23); VECMUL(f3, K1, f3); VECCROSS(tv1, dcosdA, r12); VECCROSS(tv2, r34, dcosdB); VECADD(f2, tv1, tv2); VECMUL(f2, K1, f2); } else { dvec dsindB, dsindC; /* phi is too close to 0 or pi, use cos version to avoid 1/sin */ VECMUL(C, rC, C); /* normalize C */ VECMSUB(dsindC, sin_phi, C, B); VECMUL(dsindC, rC, dsindC); VECMSUB(dsindB, sin_phi, B, C); VECMUL(dsindB, rB, dsindB); K1 /= -cos_phi; f1.x = K1 * ((r23.y * r23.y + r23.z * r23.z) * dsindC.x - r23.x * r23.y * dsindC.y - r23.x * r23.z * dsindC.z); f1.y = K1 * ((r23.z * r23.z + r23.x * r23.x) * dsindC.y - r23.y * r23.z * dsindC.z - r23.y * r23.x * dsindC.x); f1.z = K1 * ((r23.x * r23.x + r23.y * r23.y) * dsindC.z - r23.z * r23.x * dsindC.x - r23.z * r23.y * dsindC.y); VECCROSS(f3, dsindB, r23); VECMUL(f3, K1, f3); f2.x = K1 * (-(r23.y * r12.y + r23.z * r12.z) * dsindC.x + (2.0 * r23.x * r12.y - r12.x * r23.y) * dsindC.y + (2.0 * r23.x * r12.z - r12.x * r23.z) * dsindC.z + dsindB.z * r34.y - dsindB.y * r34.z); f2.y = K1 * (-(r23.z * r12.z + r23.x * r12.x) * dsindC.y + (2.0 * r23.y * r12.z - r12.y * r23.z) * dsindC.z + (2.0 * r23.y * r12.x - r12.y * r23.x) * dsindC.x + dsindB.x * r34.z - dsindB.z * r34.x); f2.z = K1 * (-(r23.x * r12.x + r23.y * r12.y) * dsindC.z + (2.0 * r23.z * r12.x - r12.z * r23.x) * dsindC.x + (2.0 * r23.z * r12.y - r12.z * r23.y) * dsindC.y + dsindB.y * r34.x - dsindB.x * r34.y); } *u += K; VECADD(*f_i, *f_i, f1); f_j->x += f2.x - f1.x; f_j->y += f2.y - f1.y; f_j->z += f2.z - f1.z; f_k->x += f3.x - f2.x; f_k->y += f3.y - f2.y; f_k->z += f3.z - f2.z; VECSUB(*f_l, *f_l, f3); virial[VIRIAL_XX] += (f1.x * r12.x + f2.x * r23.x + f3.x * r34.x); virial[VIRIAL_XY] += (f1.x * r12.y + f2.x * r23.y + f3.x * r34.y); virial[VIRIAL_XZ] += (f1.x * r12.z + f2.x * r23.z + f3.x * r34.z); virial[VIRIAL_YY] += (f1.y * r12.y + f2.y * r23.y + f3.y * r34.y); virial[VIRIAL_YZ] += (f1.y * r12.z + f2.y * r23.z + f3.y * r34.z); virial[VIRIAL_ZZ] += (f1.z * r12.z + f2.z * r23.z + f3.z * r34.z); return OK; }
static void connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) { ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys); ParticleData *pa; PTCacheEdit *edit; PTCacheEditPoint *point; PTCacheEditKey *ekey = NULL; HairKey *key; BVHTreeFromMesh bvhtree= {NULL}; BVHTreeNearest nearest; MFace *mface; DerivedMesh *dm = NULL; int numverts; int i, k; float hairmat[4][4], imat[4][4]; float v[4][3], vec[3]; if(!psys || !psys->part || psys->part->type != PART_HAIR) return; edit= psys->edit; point= edit ? edit->points : NULL; if(psmd->dm->deformedOnly) /* we don't want to mess up psmd->dm when converting to global coordinates below */ dm= CDDM_copy(psmd->dm); else dm= mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); numverts = dm->getNumVerts (dm); /* convert to global coordinates */ for (i=0; i<numverts; i++) mul_m4_v3(ob->obmat, CDDM_get_vert(dm, i)->co); bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6); for(i=0, pa= psys->particles; i<psys->totpart; i++,pa++) { key = pa->hair; nearest.index = -1; nearest.dist = FLT_MAX; BLI_bvhtree_find_nearest(bvhtree.tree, key->co, &nearest, bvhtree.nearest_callback, &bvhtree); if(nearest.index == -1) { if (G.f & G_DEBUG) printf("No nearest point found for hair root!"); continue; } mface = CDDM_get_face(dm,nearest.index); copy_v3_v3(v[0], CDDM_get_vert(dm,mface->v1)->co); copy_v3_v3(v[1], CDDM_get_vert(dm,mface->v2)->co); copy_v3_v3(v[2], CDDM_get_vert(dm,mface->v3)->co); if(mface->v4) { copy_v3_v3(v[3], CDDM_get_vert(dm,mface->v4)->co); interp_weights_poly_v3( pa->fuv,v, 4, nearest.co); } else interp_weights_poly_v3( pa->fuv,v, 3, nearest.co); pa->num = nearest.index; pa->num_dmcache = psys_particle_dm_face_lookup(ob,psmd->dm,pa->num,pa->fuv,NULL); psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); invert_m4_m4(imat,hairmat); VECSUB(vec, nearest.co, key->co); if(point) { ekey = point->keys; point++; } for(k=0,key=pa->hair; k<pa->totkey; k++,key++) { VECADD(key->co, key->co, vec); mul_m4_v3(imat,key->co); if(ekey) { ekey->flag |= PEK_USE_WCO; ekey++; } } } free_bvhtree_from_mesh(&bvhtree); dm->release(dm); psys_free_path_cache(psys, psys->edit); psys->flag &= ~PSYS_GLOBAL_HAIR; PE_update_object(scene, ob, 0); }
// set the currently used goal position --------------------------------------- // void BOT_AI::_GoalCheck_AgentMode_Attack() { //FIXME: push current goal onto goal stack BOT_Goal* pGoal = m_State.GetCurGoal(); ASSERT( pGoal != NULL ); //FIXME: here we should also evaluate whether we pick another target // select a target, if none, or no ship selected as target GenObject* pTargetObject = pGoal->GetTargetObject(); Vector3* pGoalPos = pGoal->GetGoalPosition(); if( ( pTargetObject == NULL ) || ( OBJECT_TYPE_SHIP( pTargetObject) == FALSE ) ){ // let the character select a target pTargetObject = m_Character.SelectAttackTarget( m_pShip ); // no target if ( pTargetObject == NULL ) { //FIXME: transition function m_nAgentMode = AGENTMODE_IDLE; pGoal->SetTargetObject(NULL); #ifdef BOT_LOGFILES BOT_MsgOut( "switching from ATTACK to IDLE" ); #endif // BOT_LOGFILES return; } // set the target object pGoal->SetTargetObject( pTargetObject ); // set the goal position to where the target is FetchTVector( pTargetObject->ObjPosition, pGoalPos ); #ifdef BOT_LOGFILES BOT_MsgOut( "found new ATTACK target %d", pTargetObject->HostObjNumber ); #endif // BOT_LOGFILES } Vector3 TargetPos; FetchTVector( pTargetObject->ObjPosition, &TargetPos ); // get vector to target Vector3 vec2Target; VECSUB( &vec2Target, &TargetPos, &m_AgentPos ); float len = VctLenX( &vec2Target ); #ifdef BOT_LOGFILES BOT_MsgOut( "BOT: distance to target: %f", len ); #endif #define MIN_DISTANCE_TO_TARGET 100.0f if ( len < 500.0F) { if ( FireRepeat > 0 ) { FireRepeat -= CurScreenRefFrames; } if ( ( FireRepeat > 0 ) || ( FireDisable > 0 ) ) { //do nothing! } else { // create laser OBJ_ShootLaser( m_pShip ); if ( ( FireRepeat += MyShip->FireRepeatDelay ) <= 0 ) { FireRepeat = 1; } if ( ( FireDisable += MyShip->FireDisableDelay ) <= 0 ) { FireDisable = 1; } } } if ( len < MIN_DISTANCE_TO_TARGET ) { // if nearby goal, we stay where we are memcpy( pGoalPos, &m_AgentPos, sizeof( Vector3 ) ); } else { // set the goal position to the position of the target ASSERT( pTargetObject != NULL ); FetchTVector( pTargetObject->ObjPosition, pGoalPos ); } #ifdef BOT_LOGFILES BOT_MsgOut( "ATTACK goal is at %f %f %f", pGoalPos->X, pGoalPos->Y, pGoalPos->Z ); #endif // BOT_LOGFILES }
static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) { Cloth *cloth = clmd->clothObject; ClothSpring *spring = NULL, *tspring = NULL, *tspring2 = NULL; unsigned int struct_springs = 0, shear_springs=0, bend_springs = 0; unsigned int i = 0; unsigned int numverts = (unsigned int)dm->getNumVerts ( dm ); unsigned int numedges = (unsigned int)dm->getNumEdges ( dm ); unsigned int numfaces = (unsigned int)dm->getNumFaces ( dm ); MEdge *medge = dm->getEdgeArray ( dm ); MFace *mface = dm->getFaceArray ( dm ); int index2 = 0; // our second vertex index LinkNode **edgelist = NULL; EdgeHash *edgehash = NULL; LinkNode *search = NULL, *search2 = NULL; float temp[3]; // error handling if ( numedges==0 ) return 0; cloth->springs = NULL; edgelist = MEM_callocN ( sizeof ( LinkNode * ) * numverts, "cloth_edgelist_alloc" ); if(!edgelist) return 0; for ( i = 0; i < numverts; i++ ) { edgelist[i] = NULL; } if ( cloth->springs ) MEM_freeN ( cloth->springs ); // create spring network hash edgehash = BLI_edgehash_new(); // structural springs for ( i = 0; i < numedges; i++ ) { spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if ( spring ) { spring->ij = MIN2(medge[i].v1, medge[i].v2); spring->kl = MAX2(medge[i].v2, medge[i].v1); VECSUB ( temp, cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest ); spring->restlen = sqrt ( INPR ( temp, temp ) ); clmd->sim_parms->avg_spring_len += spring->restlen; cloth->verts[spring->ij].avg_spring_len += spring->restlen; cloth->verts[spring->kl].avg_spring_len += spring->restlen; cloth->verts[spring->ij].spring_count++; cloth->verts[spring->kl].spring_count++; spring->type = CLOTH_SPRING_TYPE_STRUCTURAL; spring->flags = 0; spring->stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0; struct_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } else { cloth_free_errorsprings(cloth, edgehash, edgelist); return 0; } } if(struct_springs > 0) clmd->sim_parms->avg_spring_len /= struct_springs; for(i = 0; i < numverts; i++) { cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49 / ((float)cloth->verts[i].spring_count); } // shear springs for ( i = 0; i < numfaces; i++ ) { // triangle faces already have shear springs due to structural geometry if ( !mface[i].v4 ) continue; spring = ( ClothSpring *) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if(!spring) { cloth_free_errorsprings(cloth, edgehash, edgelist); return 0; } spring->ij = MIN2(mface[i].v1, mface[i].v3); spring->kl = MAX2(mface[i].v3, mface[i].v1); VECSUB ( temp, cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest ); spring->restlen = sqrt ( INPR ( temp, temp ) ); spring->type = CLOTH_SPRING_TYPE_SHEAR; spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0; BLI_linklist_append ( &edgelist[spring->ij], spring ); BLI_linklist_append ( &edgelist[spring->kl], spring ); shear_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); // if ( mface[i].v4 ) --> Quad face spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if(!spring) { cloth_free_errorsprings(cloth, edgehash, edgelist); return 0; } spring->ij = MIN2(mface[i].v2, mface[i].v4); spring->kl = MAX2(mface[i].v4, mface[i].v2); VECSUB ( temp, cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest ); spring->restlen = sqrt ( INPR ( temp, temp ) ); spring->type = CLOTH_SPRING_TYPE_SHEAR; spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0; BLI_linklist_append ( &edgelist[spring->ij], spring ); BLI_linklist_append ( &edgelist[spring->kl], spring ); shear_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } if(numfaces) { // bending springs search2 = cloth->springs; for ( i = struct_springs; i < struct_springs+shear_springs; i++ ) { if ( !search2 ) break; tspring2 = search2->link; search = edgelist[tspring2->kl]; while ( search ) { tspring = search->link; index2 = ( ( tspring->ij==tspring2->kl ) ? ( tspring->kl ) : ( tspring->ij ) ); // check for existing spring // check also if startpoint is equal to endpoint if ( !BLI_edgehash_haskey ( edgehash, MIN2(tspring2->ij, index2), MAX2(tspring2->ij, index2) ) && ( index2!=tspring2->ij ) ) { spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if(!spring) { cloth_free_errorsprings(cloth, edgehash, edgelist); return 0; } spring->ij = MIN2(tspring2->ij, index2); spring->kl = MAX2(tspring2->ij, index2); VECSUB ( temp, cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest ); spring->restlen = sqrt ( INPR ( temp, temp ) ); spring->type = CLOTH_SPRING_TYPE_BENDING; spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0; BLI_edgehash_insert ( edgehash, spring->ij, spring->kl, NULL ); bend_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } search = search->next; } search2 = search2->next; } } else if(struct_springs > 2) { /* bending springs for hair strands */ /* The current algorightm only goes through the edges in order of the mesh edges list */ /* and makes springs between the outer vert of edges sharing a vertice. This works just */ /* fine for hair, but not for user generated string meshes. This could/should be later */ /* extended to work with non-ordered edges so that it can be used for general "rope */ /* dynamics" without the need for the vertices or edges to be ordered through the length*/ /* of the strands. -jahka */ search = cloth->springs; search2 = search->next; while(search && search2) { tspring = search->link; tspring2 = search2->link; if(tspring->ij == tspring2->kl) { spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if(!spring) { cloth_free_errorsprings(cloth, edgehash, edgelist); return 0; } spring->ij = tspring2->ij; spring->kl = tspring->kl; VECSUB ( temp, cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest ); spring->restlen = sqrt ( INPR ( temp, temp ) ); spring->type = CLOTH_SPRING_TYPE_BENDING; spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0; bend_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } search = search->next; search2 = search2->next; } } /* insert other near springs in edgehash AFTER bending springs are calculated (for selfcolls) */ for ( i = 0; i < numedges; i++ ) // struct springs BLI_edgehash_insert ( edgehash, MIN2(medge[i].v1, medge[i].v2), MAX2(medge[i].v2, medge[i].v1), NULL ); for ( i = 0; i < numfaces; i++ ) // edge springs { if(mface[i].v4) { BLI_edgehash_insert ( edgehash, MIN2(mface[i].v1, mface[i].v3), MAX2(mface[i].v3, mface[i].v1), NULL ); BLI_edgehash_insert ( edgehash, MIN2(mface[i].v2, mface[i].v4), MAX2(mface[i].v2, mface[i].v4), NULL ); } } cloth->numsprings = struct_springs + shear_springs + bend_springs; if ( edgelist ) { for ( i = 0; i < numverts; i++ ) { BLI_linklist_free ( edgelist[i],NULL ); } MEM_freeN ( edgelist ); } cloth->edgehash = edgehash; if(G.rt>0) printf("avg_len: %f\n",clmd->sim_parms->avg_spring_len); return 1; } /* cloth_build_springs */
int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, DerivedMesh *dm) { if((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid) { size_t i; float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX}; float size[3]; MVert *verts = dm->getVertArray(dm); float scale = 0.0; int res; res = smd->domain->maxres; // get BB of domain for(i = 0; i < dm->getNumVerts(dm); i++) { float tmp[3]; VECCOPY(tmp, verts[i].co); Mat4MulVecfl(ob->obmat, tmp); // min BB min[0] = MIN2(min[0], tmp[0]); min[1] = MIN2(min[1], tmp[1]); min[2] = MIN2(min[2], tmp[2]); // max BB max[0] = MAX2(max[0], tmp[0]); max[1] = MAX2(max[1], tmp[1]); max[2] = MAX2(max[2], tmp[2]); } VECCOPY(smd->domain->p0, min); VECCOPY(smd->domain->p1, max); // calc other res with max_res provided VECSUB(size, max, min); // printf("size: %f, %f, %f\n", size[0], size[1], size[2]); // prevent crash when initializing a plane as domain if((size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) || (size[2] < FLT_EPSILON)) return 0; if(size[0] > size[1]) { if(size[0] > size[1]) { scale = res / size[0]; smd->domain->dx = size[0] / res; smd->domain->res[0] = res; smd->domain->res[1] = (int)(size[1] * scale + 0.5); smd->domain->res[2] = (int)(size[2] * scale + 0.5); } else { scale = res / size[1]; smd->domain->dx = size[1] / res; smd->domain->res[1] = res; smd->domain->res[0] = (int)(size[0] * scale + 0.5); smd->domain->res[2] = (int)(size[2] * scale + 0.5); } } else { if(size[1] > size[2]) { scale = res / size[1]; smd->domain->dx = size[1] / res; smd->domain->res[1] = res; smd->domain->res[0] = (int)(size[0] * scale + 0.5); smd->domain->res[2] = (int)(size[2] * scale + 0.5); } else { scale = res / size[2]; smd->domain->dx = size[2] / res; smd->domain->res[2] = res; smd->domain->res[0] = (int)(size[0] * scale + 0.5); smd->domain->res[1] = (int)(size[1] * scale + 0.5); } } // printf("smd->domain->dx: %f\n", smd->domain->dx); // TODO: put in failsafe if res<=0 - dg // printf("res[0]: %d, res[1]: %d, res[2]: %d\n", smd->domain->res[0], smd->domain->res[1], smd->domain->res[2]); // dt max is 0.1 smd->domain->fluid = smoke_init(smd->domain->res, smd->domain->p0, 0.1); smd->time = scene->r.cfra; if(smd->domain->flags & MOD_SMOKE_HIGHRES) { smd->domain->wt = smoke_turbulence_init(smd->domain->res, smd->domain->amplify + 1, smd->domain->noise); smd->domain->res_wt[0] = smd->domain->res[0] * (smd->domain->amplify + 1); smd->domain->res_wt[1] = smd->domain->res[1] * (smd->domain->amplify + 1); smd->domain->res_wt[2] = smd->domain->res[2] * (smd->domain->amplify + 1); smd->domain->dx_wt = smd->domain->dx / (smd->domain->amplify + 1); // printf("smd->domain->amplify: %d\n", smd->domain->amplify); // printf("(smd->domain->flags & MOD_SMOKE_HIGHRES)\n"); } if(!smd->domain->shadow) smd->domain->shadow = MEM_callocN(sizeof(float) * smd->domain->res[0] * smd->domain->res[1] * smd->domain->res[2], "SmokeDomainShadow"); smoke_initBlenderRNA(smd->domain->fluid, &(smd->domain->alpha), &(smd->domain->beta)); if(smd->domain->wt) { smoke_initWaveletBlenderRNA(smd->domain->wt, &(smd->domain->strength)); // printf("smoke_initWaveletBlenderRNA\n"); } return 1; } else if((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) { // handle flow object here // XXX TODO smd->time = scene->r.cfra; // update particle lifetime to be one frame // smd->flow->psys->part->lifetime = scene->r.efra + 1; /* if(!smd->flow->bvh) { // smd->flow->bvh = MEM_callocN(sizeof(BVHTreeFromMesh), "smoke_bvhfromfaces"); // bvhtree_from_mesh_faces(smd->flow->bvh, dm, 0.0, 2, 6); // copy obmat // Mat4CpyMat4(smd->flow->mat, ob->obmat); // Mat4CpyMat4(smd->flow->mat_old, ob->obmat); } */ return 1; } else if((smd->type & MOD_SMOKE_TYPE_COLL)) { smd->time = scene->r.cfra; // todo: delete this when loading colls work -dg if(!smd->coll) smokeModifier_createType(smd); if(!smd->coll->points) { // init collision points SmokeCollSettings *scs = smd->coll; // copy obmat Mat4CpyMat4(scs->mat, ob->obmat); Mat4CpyMat4(scs->mat_old, ob->obmat); fill_scs_points(ob, dm, scs); } if(!smd->coll->bvhtree) { smd->coll->bvhtree = NULL; // bvhtree_build_from_smoke ( ob->obmat, dm->getFaceArray(dm), dm->getNumFaces(dm), dm->getVertArray(dm), dm->getNumVerts(dm), 0.0 ); } return 1; } return 1; }
static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs) { MVert *mvert = dm->getVertArray(dm); MFace *mface = dm->getFaceArray(dm); int i = 0, divs = 0; int *tridivs = NULL; float cell_len = 1.0 / 50.0; // for res = 50 int newdivs = 0; int quads = 0, facecounter = 0; // count quads for(i = 0; i < dm->getNumFaces(dm); i++) { if(mface[i].v4) quads++; } calcTriangleDivs(ob, mvert, dm->getNumVerts(dm), mface, dm->getNumFaces(dm), dm->getNumFaces(dm) + quads, &tridivs, cell_len); // count triangle divisions for(i = 0; i < dm->getNumFaces(dm) + quads; i++) { divs += (tridivs[3 * i] + 1) * (tridivs[3 * i + 1] + 1) * (tridivs[3 * i + 2] + 1); } // printf("divs: %d\n", divs); scs->points = MEM_callocN(sizeof(float) * (dm->getNumVerts(dm) + divs) * 3, "SmokeCollPoints"); for(i = 0; i < dm->getNumVerts(dm); i++) { float tmpvec[3]; VECCOPY(tmpvec, mvert[i].co); Mat4MulVecfl (ob->obmat, tmpvec); VECCOPY(&scs->points[i * 3], tmpvec); } for(i = 0, facecounter = 0; i < dm->getNumFaces(dm); i++) { int again = 0; do { int j, k; int divs1 = tridivs[3 * facecounter + 0]; int divs2 = tridivs[3 * facecounter + 1]; //int divs3 = tridivs[3 * facecounter + 2]; float side1[3], side2[3], trinormorg[3], trinorm[3]; if(again == 1 && mface[i].v4) { VECSUB(side1, mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co); VECSUB(side2, mvert[ mface[i].v4 ].co, mvert[ mface[i].v1 ].co); } else { VECSUB(side1, mvert[ mface[i].v2 ].co, mvert[ mface[i].v1 ].co); VECSUB(side2, mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co); } Crossf(trinormorg, side1, side2); Normalize(trinormorg); VECCOPY(trinorm, trinormorg); VecMulf(trinorm, 0.25 * cell_len); for(j = 0; j <= divs1; j++) { for(k = 0; k <= divs2; k++) { float p1[3], p2[3], p3[3], p[3]={0,0,0}; const float uf = (float)(j + TRI_UVOFFSET) / (float)(divs1 + 0.0); const float vf = (float)(k + TRI_UVOFFSET) / (float)(divs2 + 0.0); float tmpvec[3]; if(uf+vf > 1.0) { // printf("bigger - divs1: %d, divs2: %d\n", divs1, divs2); continue; } VECCOPY(p1, mvert[ mface[i].v1 ].co); if(again == 1 && mface[i].v4) { VECCOPY(p2, mvert[ mface[i].v3 ].co); VECCOPY(p3, mvert[ mface[i].v4 ].co); } else { VECCOPY(p2, mvert[ mface[i].v2 ].co); VECCOPY(p3, mvert[ mface[i].v3 ].co); } VecMulf(p1, (1.0-uf-vf)); VecMulf(p2, uf); VecMulf(p3, vf); VECADD(p, p1, p2); VECADD(p, p, p3); if(newdivs > divs) printf("mem problem\n"); // mMovPoints.push_back(p + trinorm); VECCOPY(tmpvec, p); VECADD(tmpvec, tmpvec, trinorm); Mat4MulVecfl (ob->obmat, tmpvec); VECCOPY(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec); newdivs++; if(newdivs > divs) printf("mem problem\n"); // mMovPoints.push_back(p - trinorm); VECCOPY(tmpvec, p); VECSUB(tmpvec, tmpvec, trinorm); Mat4MulVecfl (ob->obmat, tmpvec); VECCOPY(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec); newdivs++; } } if(again == 0 && mface[i].v4) again++; else again = 0; facecounter++; } while(again!=0); } scs->numpoints = dm->getNumVerts(dm) + newdivs; MEM_freeN(tridivs); }