// check whether a ship is in range of a stargate ----------------------------- // PRIVATE int ShipInStargateRange( Stargate *stargate, ShipObject *ship, geomv_t range ) { ASSERT( stargate != NULL ); ASSERT( ship != NULL ); //NOTE: // the ship is treated as a sphere for activation // 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; // bounding sphere touching in negative halfspace is still ok distance += ship->BoundingSphere; // not in range if ship in wrong halfspace if ( GEOMV_NEGATIVE( distance ) ) { return FALSE; } // in range if ship bounding sphere intersects gate range hemisphere range += ship->BoundingSphere * 2; return ( distance < range ); }
// 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; }
int BSphereBSphereIntersect(BSphere *bsa, BSphere *bsb ) { float lx, ly, lz; float ls, rs; lx = bsa->sphereX - bsb->sphereX; ly = bsa->sphereY - bsb->sphereY; lz = bsa->sphereZ - bsb->sphereZ; ls = DOT_PRODUCT(lx, ly, lz, lx, ly, lz); rs = bsa->radius + bsb->radius; if (ls > (rs * rs)) return IREJECT; // Disjoint return IINTERSECT; // Intersect }
void PickShell (vector *v, real radius) { real temp_r; real r_scale; do { v->x = XRand(-1.0, 1.0); v->y = XRand(-1.0, 1.0); temp_r = DOT_PRODUCT((*v), (*v)); } while (temp_r >1.0); r_scale = radius / (real) sqrt(temp_r); VECTOR_MUL((*v), (*v), r_scale); }
/* * La procedure "norm_vector" normalise le vecteur. * Si la norme est nulle la normalisation n'est pas effectuee. * Entree : * vp Le vecteur a norme. * Sortie : * La norme du vecteur. */ float norm_vector (Vector *vp) { float norm; /* norme du vecteur */ if ((norm = (float) sqrt ((double) DOT_PRODUCT(*vp,*vp))) > M_EPSILON) { vp->x /= norm; vp->y /= norm; vp->z /= norm; } else { static char proc_name[] = "norm_vector"; fprintf (stderr, "%s: nul vector\n", proc_name); } return (norm); }
/* * La procedure "rotate_vector" transforme le vecteur * par la rotation de sens trigonometrique d'angle et d'axe donnes. * Entree : * vp Vecteur a transformer. * a Angle de rotation en degres. * axis Vecteur directeur de l'axe de rotation. */ void rotate_vector (Vector *vp, float a, Vector *axis) { Vector n, u, v, cross; float f; a *= (float)M_PI / (float)180.0; /* passage en radians */ n = *axis; /* norme le vecteur directeur */ norm_vector (&n); /* * Avant rotation, vp vaut : * u + v * Apres rotation, vp vaut : * u + cos(a) * v + sin(a) * (n^vp) * = u + cos(a) * v + sin(a) * (n^v) * avec u = (vp.n) * n, v = vp-u; * ou "u" est la projection de "vp" sur l'axe "axis", * et "v" est la composante de "vp" perpendiculaire a "axis". */ f = DOT_PRODUCT(*vp, n); u = n; MUL_COORD3(u,f,f,f); /* (vp.n) * n */ DIF_COORD3(v,*vp,u); /* calcule "v" */ f = (float) cos ((double) a); MUL_COORD3(v,f,f,f); /* v * cos(a) */ CROSS_PRODUCT(cross,n,*vp); f = (float) sin ((double) a); MUL_COORD3(cross,f,f,f); /* (n^v) * sin(a) */ SET_COORD3(*vp, u.x + v.x + cross.x, u.y + v.y + cross.y, u.z + v.z + cross.z); }
int TexinfoForBrushTexture (plane_t *plane, brush_texture_t *bt, const Vector& origin) { Vector vecs[2]; int sv, tv; vec_t ang, sinv, cosv; vec_t ns, nt; texinfo_t tx; int i, j; if (!bt->name[0]) return 0; memset (&tx, 0, sizeof(tx)); // HLTOOLS - add support for texture vectors stored in the map file if (g_nMapFileVersion < 220) { TextureAxisFromPlane(plane, vecs[0], vecs[1]); } if (!bt->textureWorldUnitsPerTexel[0]) bt->textureWorldUnitsPerTexel[0] = 1; if (!bt->textureWorldUnitsPerTexel[1]) bt->textureWorldUnitsPerTexel[1] = 1; float shiftScaleU = 1.0f / 16.0f; float shiftScaleV = 1.0f / 16.0f; if (g_nMapFileVersion < 220) { // rotate axis if (bt->rotate == 0) { sinv = 0 ; cosv = 1; } else if (bt->rotate == 90) { sinv = 1 ; cosv = 0; } else if (bt->rotate == 180) { sinv = 0 ; cosv = -1; } else if (bt->rotate == 270) { sinv = -1 ; cosv = 0; } else { ang = bt->rotate / 180 * M_PI; sinv = sin(ang); cosv = cos(ang); } if (vecs[0][0]) sv = 0; else if (vecs[0][1]) sv = 1; else sv = 2; if (vecs[1][0]) tv = 0; else if (vecs[1][1]) tv = 1; else tv = 2; for (i=0 ; i<2 ; i++) { ns = cosv * vecs[i][sv] - sinv * vecs[i][tv]; nt = sinv * vecs[i][sv] + cosv * vecs[i][tv]; vecs[i][sv] = ns; vecs[i][tv] = nt; } for (i=0 ; i<2 ; i++) { for (j=0 ; j<3 ; j++) { tx.textureVecsTexelsPerWorldUnits[i][j] = vecs[i][j] / bt->textureWorldUnitsPerTexel[i]; tx.lightmapVecsLuxelsPerWorldUnits[i][j] = tx.textureVecsTexelsPerWorldUnits[i][j] / 16.0f; } } } else { tx.textureVecsTexelsPerWorldUnits[0][0] = bt->UAxis[0] / bt->textureWorldUnitsPerTexel[0]; tx.textureVecsTexelsPerWorldUnits[0][1] = bt->UAxis[1] / bt->textureWorldUnitsPerTexel[0]; tx.textureVecsTexelsPerWorldUnits[0][2] = bt->UAxis[2] / bt->textureWorldUnitsPerTexel[0]; tx.textureVecsTexelsPerWorldUnits[1][0] = bt->VAxis[0] / bt->textureWorldUnitsPerTexel[1]; tx.textureVecsTexelsPerWorldUnits[1][1] = bt->VAxis[1] / bt->textureWorldUnitsPerTexel[1]; tx.textureVecsTexelsPerWorldUnits[1][2] = bt->VAxis[2] / bt->textureWorldUnitsPerTexel[1]; tx.lightmapVecsLuxelsPerWorldUnits[0][0] = bt->UAxis[0] / bt->lightmapWorldUnitsPerLuxel; tx.lightmapVecsLuxelsPerWorldUnits[0][1] = bt->UAxis[1] / bt->lightmapWorldUnitsPerLuxel; tx.lightmapVecsLuxelsPerWorldUnits[0][2] = bt->UAxis[2] / bt->lightmapWorldUnitsPerLuxel; tx.lightmapVecsLuxelsPerWorldUnits[1][0] = bt->VAxis[0] / bt->lightmapWorldUnitsPerLuxel; tx.lightmapVecsLuxelsPerWorldUnits[1][1] = bt->VAxis[1] / bt->lightmapWorldUnitsPerLuxel; tx.lightmapVecsLuxelsPerWorldUnits[1][2] = bt->VAxis[2] / bt->lightmapWorldUnitsPerLuxel; shiftScaleU = bt->textureWorldUnitsPerTexel[0] / bt->lightmapWorldUnitsPerLuxel; shiftScaleV = bt->textureWorldUnitsPerTexel[1] / bt->lightmapWorldUnitsPerLuxel; } tx.textureVecsTexelsPerWorldUnits[0][3] = bt->shift[0] + DOT_PRODUCT( origin, tx.textureVecsTexelsPerWorldUnits[0] ); tx.textureVecsTexelsPerWorldUnits[1][3] = bt->shift[1] + DOT_PRODUCT( origin, tx.textureVecsTexelsPerWorldUnits[1] ); tx.lightmapVecsLuxelsPerWorldUnits[0][3] = shiftScaleU * bt->shift[0] + DOT_PRODUCT( origin, tx.lightmapVecsLuxelsPerWorldUnits[0] ); tx.lightmapVecsLuxelsPerWorldUnits[1][3] = shiftScaleV * bt->shift[1] + DOT_PRODUCT( origin, tx.lightmapVecsLuxelsPerWorldUnits[1] ); tx.flags = bt->flags; tx.texdata = FindOrCreateTexData( bt->name ); // find the texinfo return FindOrCreateTexInfo( tx ); }
int IntersectTriangleRay(float P0x, float P0y, float P0z, float P1x, float P1y, float P1z, float P2x, float P2y, float P2z, line *l, float *u, float *v, float *t) { float e1[3]; float e2[3]; float p[3]; float s[3]; float q[3]; float a, f; float lu, lv, lt; *u=0; *v=0; *t=0; // e1 = P1 - P0 e1[0] = P1x - P0x; e1[1] = P1y - P0x; e1[2] = P1z - P0z; // e2 = P2 - P0 e2[0] = P2x - P0x; e2[1] = P2y - P0y; e2[2] = P2z - P0z; crossVV(&p[0], &p[1], &p[2], l->dx, l->dy, l->dz, e2[0], e2[1], e2[2]); a = DOT_PRODUCT(e1[0], e1[1], e1[2], p[0], p[1], p[2]); if (a > -DISTANCE_EPSILON && a < DISTANCE_EPSILON) return IREJECT; f = 1.0 / a; // s = l->o - P0 s[0] = l->ox - P0x; s[1] = l->oy - P0y; s[2] = l->oz - P0z; lu = f * DOT_PRODUCT(s[0], s[1], s[2], p[0], p[1], p[2]); if (lu < 0.0 || lu > 1.0) return IREJECT; crossVV(&q[0], &q[1], &q[2], s[0], s[1], s[2], e1[0], e1[1], e1[2]); lv = f * DOT_PRODUCT(l->dx, l->dy, l->dz, q[0], q[1], q[2]); if (lv < 0.0 || lv > 1.0) return IREJECT; lt = f * DOT_PRODUCT(e2[0], e2[1], e2[2], q[0], q[1], q[2]); *u = lu; *v = lv; *t = lt; return IINTERSECT; }
void CreateDistribution (cluster_type cluster, model_type model) { particle *particle_array; int global_num_particles; particle *new_particle; char particle_state[RANDOM_SIZE]; real charge; real r_scale; real v_scale; vector r_sum; vector v_sum; int end_limit; int i; int j; real temp_r; real radius; real x_vel; real y_vel; real vel; real offset; particle *twin_particle; particle_array = (particle *) G_MALLOC(Total_Particles * sizeof(particle)); Particle_List = (particle **) G_MALLOC(Total_Particles * sizeof(particle *)); for (i = 0; i < Total_Particles; i++) Particle_List[i] = &particle_array[i]; r_scale = 3 * M_PI / 16; v_scale = (real) sqrt(1.0 / (double) r_scale); r_sum.x = (real) 0.0; r_sum.y = (real) 0.0; v_sum.x = (real) 0.0; v_sum.y = (real) 0.0; initstate(0, particle_state, RANDOM_SIZE); switch (cluster) { case ONE_CLUSTER: end_limit = Total_Particles; switch (model) { case UNIFORM: printf("Creating a one cluster, uniform distribution for %d ", Total_Particles); printf("particles\n"); break; case PLUMMER: printf("Creating a one cluster, non uniform distribution for %d ", Total_Particles); printf("particles\n"); break; } break; case TWO_CLUSTER: end_limit = (Total_Particles / 2) + (Total_Particles & 0x1); switch (model) { case UNIFORM: printf("Creating a two cluster, uniform distribution for %d ", Total_Particles); printf("particles\n"); break; case PLUMMER: printf("Creating a two cluster, non uniform distribution for %d ", Total_Particles); printf("particles\n"); break; } break; } setstate(particle_state); global_num_particles = 0; charge = 1.0 / Total_Particles; charge /= Total_Particles; for (i = 0; i < end_limit; i++) { new_particle = InitParticle(charge, charge); switch (model) { case UNIFORM: do { new_particle->pos.x = XRand(-1.0, 1.0); new_particle->pos.y = XRand(-1.0, 1.0); temp_r = DOT_PRODUCT((new_particle->pos), (new_particle->pos)); } while (temp_r > (real) 1.0); radius = sqrt(temp_r); break; case PLUMMER: do radius = (real) 1.0 / (real) sqrt(pow(XRand(0.0, MAX_FRAC), -2.0/3.0) - 1); while (radius > 9.0); PickShell(&(new_particle->pos), r_scale * radius); break; } VECTOR_ADD(r_sum, r_sum, (new_particle->pos)); do { x_vel = XRand(0.0, 1.0); y_vel = XRand(0.0, 0.1); } while (y_vel > x_vel * x_vel * (real) pow(1.0 - (x_vel * x_vel), 3.5)); vel = (real) sqrt(2.0) * x_vel / pow(1.0 + (radius * radius), 0.25); PickShell(&(new_particle->vel), v_scale * vel); VECTOR_ADD(v_sum, v_sum, (new_particle->vel)); } if (cluster == TWO_CLUSTER) { switch (model) { case UNIFORM: offset = 1.5; break; case PLUMMER: offset = 2.0; break; } for (i = end_limit; i < Total_Particles; i++) { new_particle = InitParticle(charge, charge); twin_particle = Particle_List[i - end_limit]; new_particle->pos.x = twin_particle->pos.x + offset; new_particle->pos.y = twin_particle->pos.y + offset; VECTOR_ADD(r_sum, r_sum, (new_particle->pos)); new_particle->vel.x = twin_particle->vel.x; new_particle->vel.y = twin_particle->vel.y; VECTOR_ADD(v_sum, v_sum, (new_particle->vel)); } } VECTOR_DIV(r_sum, r_sum, (real) Total_Particles); VECTOR_DIV(v_sum, v_sum, (real) Total_Particles); for (i = 0; i < Total_Particles; i++) { new_particle = Particle_List[i]; VECTOR_SUB((new_particle->pos), (new_particle->pos), r_sum); VECTOR_SUB((new_particle->vel), (new_particle->vel), v_sum); } }
// collision detection helper function ---------------------------------------- // int G_CollDet::_CheckShipProjectileDisjoint() { // extend sphere for point sampling geomv_t hugesphere = bd_sphere * CONSERVATIVE_POINTSAMPLE_EXPANSION; // vector to center Vector3 vectest; vectest.X = obj_pos.X - test_pos.X; vectest.Y = obj_pos.Y - test_pos.Y; vectest.Z = obj_pos.Z - test_pos.Z; // check enlarged vicinity for early-out if ( vectest.X >= hugesphere ) return TRUE; if ( vectest.Y >= hugesphere ) return TRUE; if ( vectest.Z >= hugesphere ) return TRUE; hugesphere = -hugesphere; if ( vectest.X <= hugesphere ) return TRUE; if ( vectest.Y <= hugesphere ) return TRUE; if ( vectest.Z <= hugesphere ) return TRUE; // test shield (bounding sphere) if ( test_shield ) { // squared distance to current position geomv_t vectestl2 = DOT_PRODUCT( &vectest, &vectest ); // trivial intersect if ( vectestl2 < bd_sphere2 ) return FALSE; // squared distance to previous position Vector3 vecprev; vecprev.X = obj_pos.X - prev_pos.X; vecprev.Y = obj_pos.Y - prev_pos.Y; vecprev.Z = obj_pos.Z - prev_pos.Z; geomv_t vecprevl2 = DOT_PRODUCT( &vecprev, &vecprev ); // trivial intersect if ( vecprevl2 < bd_sphere2 ) return FALSE; // calc nearest point on line to center Vector3 vecline; vecline.X = test_pos.X - prev_pos.X; vecline.Y = test_pos.Y - prev_pos.Y; vecline.Z = test_pos.Z - prev_pos.Z; geomv_t scaledt = DOT_PRODUCT( &vecline, &vecprev ); // ray pointing away from sphere? if ( GEOMV_NEGATIVE( scaledt ) ) return TRUE; // ray not yet at the sphere? geomv_t veclinel2 = DOT_PRODUCT( &vecline, &vecline ); if ( scaledt >= veclinel2 ) return TRUE; ASSERT( veclinel2 > GEOMV_VANISHING ); // calc squared distance of nearest point geomv_t dot2 = GEOMV_MUL( scaledt, scaledt ); geomv_t tlen2 = GEOMV_DIV( dot2, veclinel2 ); //NOTE: // the actual point of impact could now be // easily calculated without a sqrt(). // collision if nearest point inside return ( ( vecprevl2 - tlen2 ) >= bd_sphere2 ); } else { ASSERT( FALSE ); /* // shield is down: test actual object #ifdef CHECK_BOX_BEFORE_BSP_COLLISION // clip lineseg into box geomv_t isect; geomv_t seglen; geomv_t vtx0t = GEOMV_0; geomv_t vtx1t = GEOMV_1; int collside = -1; static geomv_t vanish = FLOAT_TO_GEOMV( 0.00001 ); // cull/clip against +Z geomv_t curax = obj_pos.Z + bd_sphere; geomv_t dist0 = prev_pos.Z - curax; geomv_t dist1 = test_pos.Z - curax; dword outcode = ( ( DW32( dist0 ) & 0x80000000 ) >> 1 ) | ( DW32( dist1 ) & 0x80000000 ); // both outside? if ( outcode == 0x00000000 ) return TRUE; // at least one outside? if ( outcode != 0xc0000000 ) { if ( outcode == 0x40000000 ) { // v0 inside, v1 outside ABS_GEOMV( dist0 ); seglen = dist0 + dist1; if ( seglen <= vanish ) return TRUE; vtx1t = GEOMV_DIV( dist0, seglen ); } else { // v0 outside, v1 inside ABS_GEOMV( dist1 ); seglen = dist0 + dist1; if ( seglen <= vanish ) return TRUE; vtx0t = GEOMV_DIV( dist0, seglen ); collside = 0; } } #define AXIAL_CLIP_T(s) { \ \ outcode = ( ( DW32( dist0 ) & 0x80000000 ) >> 1 ) | \ ( DW32( dist1 ) & 0x80000000 ); \ if ( outcode == 0x00000000 ) \ return TRUE; \ if ( outcode != 0xc0000000 ) { \ if ( outcode == 0x40000000 ) { \ ABS_GEOMV( dist0 ); \ seglen = dist0 + dist1; \ if ( seglen <= vanish ) \ return TRUE; \ isect = GEOMV_DIV( dist0, seglen ); \ if ( isect <= vtx0t ) \ return TRUE; \ if ( isect < vtx1t ) \ vtx1t = isect; \ } else { \ ABS_GEOMV( dist1 ); \ seglen = dist0 + dist1; \ if ( seglen <= vanish ) \ return TRUE; \ isect = GEOMV_DIV( dist0, seglen ); \ if ( isect >= vtx1t ) \ return TRUE; \ if ( isect > vtx0t ) { \ vtx0t = isect; \ collside = (s); \ } \ } \ } \ } // cull/clip against -Z curax = obj_pos.Z - bd_sphere; dist0 = curax - prev_pos.Z; dist1 = curax - test_pos.Z; AXIAL_CLIP_T( 1 ); // cull/clip against +X curax = obj_pos.X + bd_sphere; dist0 = prev_pos.X - curax; dist1 = test_pos.X - curax; AXIAL_CLIP_T( 2 ); // cull/clip against -X curax = obj_pos.X - bd_sphere; dist0 = curax - prev_pos.X; dist1 = curax - test_pos.X; AXIAL_CLIP_T( 3 ); // cull/clip against +Y curax = obj_pos.Y + bd_sphere; dist0 = prev_pos.Y - curax; dist1 = test_pos.Y - curax; AXIAL_CLIP_T( 4 ); // cull/clip against -Y curax = obj_pos.Y - bd_sphere; dist0 = curax - prev_pos.Y; dist1 = curax - test_pos.Y; AXIAL_CLIP_T( 5 ); //NOTE: // collside now contains the code of the collider side // (-1 means the lineseg starts in the bounding box) //TODO: // use already clipped segment in BSP test? #endif // CHECK_BOX_BEFORE_BSP_COLLISION // test actual object (polygon accurate) // transform line vertices into object-space CalcOrthoInverse( cur_ship->ObjPosition, DestXmatrx ); Vertex3 v0; MtxVctMUL( DestXmatrx, &prev_pos, &v0 ); Vertex3 v1; MtxVctMUL( DestXmatrx, &test_pos, &v1 ); // assume collision if no bsp tree CullBSPNode *node = cur_ship->AuxBSPTree; if ( node == NULL ) return FALSE; dword nodeid = 0; geomv_t impact_t; int collided = BSP_FindColliderLine( node, &v0, &v1, &nodeid, &impact_t ); // no collision? if ( !collided ) return TRUE; // react only if not started in solid leaf if ( nodeid > 0 ) { // fetch collider node = &cur_ship->AuxBSPTree[ nodeid ]; // calc collision position (object-space) v1.X -= v0.X; v1.Y -= v0.Y; v1.Z -= v0.Z; v1.X = v0.X + GEOMV_MUL( v1.X, impact_t ); v1.Y = v0.Y + GEOMV_MUL( v1.Y, impact_t ); v1.Z = v0.Z + GEOMV_MUL( v1.Z, impact_t ); // create hull impact particles SFX_HullImpact( cur_ship, &v1, &node->plane ); } // disable shield test_shield = FALSE; */ } return FALSE; }
// ---------------------------------------------------------------------------- // void UTL_LocomotionController::ControlOjbect( object_control_s* pObjctl, Vector3* pDesiredVelocity, fixed_t _DesiredSpeed ) { ASSERT( pObjctl != NULL ); ASSERT( pDesiredVelocity != NULL ); Vector3 xDir, yDir, zDir; FetchXVector( pObjctl->pShip->ObjPosition, &xDir ); FetchYVector( pObjctl->pShip->ObjPosition, &yDir ); FetchZVector( pObjctl->pShip->ObjPosition, &zDir ); geomv_t len = VctLenX( pDesiredVelocity ); // stop control if desired velocity is zero if ( len <= GEOMV_VANISHING ) { pObjctl->rot_x = 0; pObjctl->rot_y = 0; pObjctl->accel = -0.82; #ifdef BOT_LOGFILES BOT_MsgOut( "ControlOjbect() got dimishing desired velocity" ); #endif // BOT_LOGFILES return; } else { Vector3 DesVelNorm; DesVelNorm.X = FLOAT_TO_GEOMV( pDesiredVelocity->X / len ); DesVelNorm.Y = FLOAT_TO_GEOMV( pDesiredVelocity->Y / len ); DesVelNorm.Z = FLOAT_TO_GEOMV( pDesiredVelocity->Z / len ); geomv_t yaw_dot = DOT_PRODUCT( &DesVelNorm, &xDir ); geomv_t pitch_dot = DOT_PRODUCT( &DesVelNorm, &yDir ); geomv_t heading_dot = DOT_PRODUCT( &DesVelNorm, &zDir ); float fDesiredSpeed = FIXED_TO_FLOAT( _DesiredSpeed ); float fCurSpeed = FIXED_TO_FLOAT( pObjctl->pShip->CurSpeed ); float pitch = 0; float yaw = 0; // target is behind us sincosval_s fullturn; GetSinCos( DEG_TO_BAMS( 2 * m_nRelaxedHeadingAngle ), &fullturn ); //if ( heading_dot < 0.0f ) { if ( heading_dot < -fullturn.cosval ) { // we must initiate a turn, if not already in a turn if ( !pObjctl->IsYaw() || !pObjctl->IsPitch() ) { // default to random yaw = (float)( RAND() % 3 ) - 1; pitch = (float)( RAND() % 3 ) - 1; // steer towards goal if ( yaw_dot < -GEOMV_VANISHING ) { yaw = OCT_YAW_LEFT; } else if ( yaw_dot > GEOMV_VANISHING ) { yaw = OCT_YAW_RIGHT; } if ( pitch_dot < -GEOMV_VANISHING ) { pitch = OCT_PITCH_UP; } else if ( pitch_dot > GEOMV_VANISHING ) { pitch = OCT_PITCH_DOWN; } } else { // reuse prev. turn information pitch = pObjctl->rot_x; yaw = pObjctl->rot_y; } // slow down, until in direction of target // pObjctl->accel = heading_dot; //pObjctl->accel = OCT_DECELERATE; // also maintain min. speed during turns if ( fCurSpeed > m_fMinSpeedTurn ) { pObjctl->accel = -0.42; } } else { // determine accel if ( fDesiredSpeed > fCurSpeed ) { // accelerate towards target pObjctl->accel = OCT_ACCELERATE; } else if ( fDesiredSpeed < fCurSpeed ) { // decelerate towards target pObjctl->accel = OCT_DECELERATE; } else { // no accel pObjctl->accel = 0; } // heading must be inside of 5 degrees cone angle sincosval_s sincosv; GetSinCos( DEG_TO_BAMS( m_nRelaxedHeadingAngle ), &sincosv ); if ( yaw_dot < -sincosv.sinval ) { yaw = OCT_YAW_LEFT; } else if ( yaw_dot > sincosv.sinval ) { yaw = OCT_YAW_RIGHT; } if ( pitch_dot < -sincosv.sinval ) { pitch = OCT_PITCH_UP; } else if ( pitch_dot > sincosv.sinval ) { pitch = OCT_PITCH_DOWN; } // if heading outside of 30 degrees cone angle, we decelerate GetSinCos( DEG_TO_BAMS( m_nFullSpeedHeading ), &sincosv ); bool_t bYawOutsideHeading = ( ( yaw_dot < -sincosv.sinval ) || ( yaw_dot > sincosv.sinval ) ); bool_t bPitchOutsideHeading = ( ( pitch_dot < -sincosv.sinval ) || ( pitch_dot > sincosv.sinval ) ); if ( bYawOutsideHeading || bPitchOutsideHeading ) { // also maintain min. speed during turns if ( fCurSpeed > min( m_fMinSpeedTurn, fDesiredSpeed ) ) { // decelerate towards target pObjctl->accel = OCT_DECELERATE; } } } #ifdef BOT_LOGFILES BOT_MsgOut( "heading_dot: %f, yaw_dot: %f, pitch_dot: %f", heading_dot, yaw_dot, pitch_dot ); #endif // BOT_LOGFILES //FIXME: oct must also handle slide horiz./vert. pObjctl->rot_x = pitch; pObjctl->rot_y = yaw; } }
int TexinfoForBrushTexture (plane_t *plane, brush_texture_t *bt, const Vector& origin) { Vector vecs[2]; int sv, tv; vec_t ang, sinv, cosv; vec_t ns, nt; texinfo_t tx, *tc; int i, j, k; if (!bt->name[0]) return 0; memset (&tx, 0, sizeof(tx)); // HLTOOLS - add support for texture vectors stored in the map file if (g_nMapFileVersion < 220) { TextureAxisFromPlane(plane, vecs[0], vecs[1]); } if (!bt->textureWorldUnitsPerTexel[0]) bt->textureWorldUnitsPerTexel[0] = 1; if (!bt->textureWorldUnitsPerTexel[1]) bt->textureWorldUnitsPerTexel[1] = 1; if (g_nMapFileVersion < 220) { // rotate axis if (bt->rotate == 0) { sinv = 0 ; cosv = 1; } else if (bt->rotate == 90) { sinv = 1 ; cosv = 0; } else if (bt->rotate == 180) { sinv = 0 ; cosv = -1; } else if (bt->rotate == 270) { sinv = -1 ; cosv = 0; } else { ang = bt->rotate / 180 * M_PI; sinv = sin(ang); cosv = cos(ang); } if (vecs[0][0]) sv = 0; else if (vecs[0][1]) sv = 1; else sv = 2; if (vecs[1][0]) tv = 0; else if (vecs[1][1]) tv = 1; else tv = 2; for (i=0 ; i<2 ; i++) { ns = cosv * vecs[i][sv] - sinv * vecs[i][tv]; nt = sinv * vecs[i][sv] + cosv * vecs[i][tv]; vecs[i][sv] = ns; vecs[i][tv] = nt; } for (i=0 ; i<2 ; i++) { for (j=0 ; j<3 ; j++) { tx.textureVecsTexelsPerWorldUnits[i][j] = vecs[i][j] / bt->textureWorldUnitsPerTexel[i]; tx.lightmapVecsLuxelsPerWorldUnits[i][j] = tx.textureVecsTexelsPerWorldUnits[i][j] / 16.0f; } } } else { tx.textureVecsTexelsPerWorldUnits[0][0] = bt->UAxis[0] / bt->textureWorldUnitsPerTexel[0]; tx.textureVecsTexelsPerWorldUnits[0][1] = bt->UAxis[1] / bt->textureWorldUnitsPerTexel[0]; tx.textureVecsTexelsPerWorldUnits[0][2] = bt->UAxis[2] / bt->textureWorldUnitsPerTexel[0]; tx.textureVecsTexelsPerWorldUnits[1][0] = bt->VAxis[0] / bt->textureWorldUnitsPerTexel[1]; tx.textureVecsTexelsPerWorldUnits[1][1] = bt->VAxis[1] / bt->textureWorldUnitsPerTexel[1]; tx.textureVecsTexelsPerWorldUnits[1][2] = bt->VAxis[2] / bt->textureWorldUnitsPerTexel[1]; tx.lightmapVecsLuxelsPerWorldUnits[0][0] = bt->UAxis[0] / bt->lightmapWorldUnitsPerLuxel; tx.lightmapVecsLuxelsPerWorldUnits[0][1] = bt->UAxis[1] / bt->lightmapWorldUnitsPerLuxel; tx.lightmapVecsLuxelsPerWorldUnits[0][2] = bt->UAxis[2] / bt->lightmapWorldUnitsPerLuxel; tx.lightmapVecsLuxelsPerWorldUnits[1][0] = bt->VAxis[0] / bt->lightmapWorldUnitsPerLuxel; tx.lightmapVecsLuxelsPerWorldUnits[1][1] = bt->VAxis[1] / bt->lightmapWorldUnitsPerLuxel; tx.lightmapVecsLuxelsPerWorldUnits[1][2] = bt->VAxis[2] / bt->lightmapWorldUnitsPerLuxel; } tx.textureVecsTexelsPerWorldUnits[0][3] = bt->shift[0] + DOT_PRODUCT( origin, tx.textureVecsTexelsPerWorldUnits[0] ); tx.textureVecsTexelsPerWorldUnits[1][3] = bt->shift[1] + DOT_PRODUCT( origin, tx.textureVecsTexelsPerWorldUnits[1] ); tx.lightmapVecsLuxelsPerWorldUnits[0][3] = bt->shift[0] + DOT_PRODUCT( origin, tx.lightmapVecsLuxelsPerWorldUnits[0] ); tx.lightmapVecsLuxelsPerWorldUnits[1][3] = bt->shift[1] + DOT_PRODUCT( origin, tx.lightmapVecsLuxelsPerWorldUnits[1] ); tx.flags = bt->flags; // // find the texinfo // if ( numtexinfo >= MAX_MAP_TEXINFO ) { Error( "Map has too many texinfos, MAX_MAP_TEXINFO == %i\n", MAX_MAP_TEXINFO ); } tc = texinfo; tx.texdata = FindTexData( bt->name ); for (i=0 ; i<numtexinfo ; i++, tc++) { if (tc->flags != tx.flags) continue; bool skip = false; for (j=0 ; j<2 && !skip; j++) { if ( tc->texdata != tx.texdata ) { skip = true; break; } for (k=0 ; k<4 && !skip; k++) { if (tc->textureVecsTexelsPerWorldUnits[j][k] != tx.textureVecsTexelsPerWorldUnits[j][k]) { skip = true; break; } if( tc->lightmapVecsLuxelsPerWorldUnits[j][k] != tx.lightmapVecsLuxelsPerWorldUnits[j][k] ) { skip = true; break; } } } if ( skip ) { continue; } return i; } *tc = tx; if ( onlyents ) { Error( "FindOrCreateTexInfo: Tried to create new texinfo during -onlyents compile!\n" ); } numtexinfo++; return i; }
void Collision_Response(void) { // this function does all the "real" physics to determine if there has // been a collision between any ball and any other ball, if there is a collision // the function uses the mass of each ball along with the intial velocities to // compute the resulting velocities // from the book we know that in general // va2 = (e+1)*mb*vb1+va1(ma - e*mb)/(ma+mb) // vb2 = (e+1)*ma*va1+vb1(ma - e*mb)/(ma+mb) // and the objects will have direction vectors co-linear to the normal // of the point of collision, but since we are using spheres here as the objects // we know that the normal to the point of collision is just the vector from the // center's of each object, thus the resulting velocity vector of each ball will // be along this normal vector direction // step 1: test each object against each other object and test for a collision // there are better ways to do this other than a double nested loop, but since // there are a small number of objects this is fine, also we want to somewhat model // if two or more balls hit simulataneously for (int ball_a = 0; ball_a < NUM_BALLS; ball_a++) { for (int ball_b = ball_a+1; ball_b < NUM_BALLS; ball_b++) { if (ball_a == ball_b) continue; // compute the normal vector from a->b float nabx = (balls[ball_b].varsF[INDEX_X] - balls[ball_a].varsF[INDEX_X] ); float naby = (balls[ball_b].varsF[INDEX_Y] - balls[ball_a].varsF[INDEX_Y] ); float length = sqrt(nabx*nabx + naby*naby); // is there a collision? if (length <= 2.0*(BALL_RADIUS*.75)) { // the balls have made contact, compute response // compute the response coordinate system axes // normalize normal vector nabx/=length; naby/=length; // compute the tangential vector perpendicular to normal, simply rotate vector 90 float tabx = -naby; float taby = nabx; // draw collision DDraw_Lock_Primary_Surface(); // blue is normal Draw_Clip_Line16(balls[ball_a].varsF[INDEX_X]+0.5, balls[ball_a].varsF[INDEX_Y]+0.5, balls[ball_a].varsF[INDEX_X]+20*nabx+0.5, balls[ball_a].varsF[INDEX_Y]+20*naby+0.5, RGB16Bit(0,0,255), primary_buffer, primary_lpitch); // yellow is tangential Draw_Clip_Line16(balls[ball_a].varsF[INDEX_X]+0.5, balls[ball_a].varsF[INDEX_Y]+0.5, balls[ball_a].varsF[INDEX_X]+20*tabx+0.5, balls[ball_a].varsF[INDEX_Y]+20*taby+0.5, RGB16Bit(0,255,255), primary_buffer, primary_lpitch); DDraw_Unlock_Primary_Surface(); // tangential is also normalized since it's just a rotated normal vector // step 2: compute all the initial velocities // notation ball: (a,b) initial: i, final: f, n: normal direction, t: tangential direction float vait = DOT_PRODUCT(balls[ball_a].varsF[INDEX_XV], balls[ball_a].varsF[INDEX_YV], tabx, taby); float vain = DOT_PRODUCT(balls[ball_a].varsF[INDEX_XV], balls[ball_a].varsF[INDEX_YV], nabx, naby); float vbit = DOT_PRODUCT(balls[ball_b].varsF[INDEX_XV], balls[ball_b].varsF[INDEX_YV], tabx, taby); float vbin = DOT_PRODUCT(balls[ball_b].varsF[INDEX_XV], balls[ball_b].varsF[INDEX_YV], nabx, naby); // now we have all the initial velocities in terms of the n and t axes // step 3: compute final velocities after collision, from book we have // note: all this code can be optimized, but I want you to see what's happening :) float ma = balls[ball_a].varsF[INDEX_MASS]; float mb = balls[ball_b].varsF[INDEX_MASS]; float vafn = (mb*vbin*(cof_E+1) + vain*(ma - cof_E*mb)) / (ma + mb); float vbfn = (ma*vain*(cof_E+1) - vbin*(ma - cof_E*mb)) / (ma + mb); // now luckily the tangential components are the same before and after, so float vaft = vait; float vbft = vbit; // and that's that baby! // the velocity vectors are: // object a (vafn, vaft) // object b (vbfn, vbft) // the only problem is that we are in the wrong coordinate system! we need to // translate back to the original x,y coordinate system, basically we need to // compute the sum of the x components relative to the n,t axes and the sum of // the y components relative to the n,t axis, since n,t may both have x,y // components in the original x,y coordinate system float xfa = vafn*nabx + vaft*tabx; float yfa = vafn*naby + vaft*taby; float xfb = vbfn*nabx + vbft*tabx; float yfb = vbfn*naby + vbft*taby; // store results balls[ball_a].varsF[INDEX_XV] = xfa; balls[ball_a].varsF[INDEX_YV] = yfa; balls[ball_b].varsF[INDEX_XV] = xfb; balls[ball_b].varsF[INDEX_YV] = yfb; // update position balls[ball_a].varsF[INDEX_X]+=balls[ball_a].varsF[INDEX_XV]; balls[ball_a].varsF[INDEX_Y]+=balls[ball_a].varsF[INDEX_YV]; balls[ball_b].varsF[INDEX_X]+=balls[ball_b].varsF[INDEX_XV]; balls[ball_b].varsF[INDEX_Y]+=balls[ball_b].varsF[INDEX_YV]; } // end if } // end for ball2 } // end for ball1 } // end Collision_Response
// perform animation for homing missiles ------------------------------------- // PRIVATE void AnimateHomingMissile( MissileObject *missilepo ) { ASSERT( missilepo != NULL ); Vector3 tempspeed; tempspeed.X = missilepo->DirectionVec.X * CurScreenRefFrames; tempspeed.Y = missilepo->DirectionVec.Y * CurScreenRefFrames; tempspeed.Z = missilepo->DirectionVec.Z * CurScreenRefFrames; missilepo->PrevPosition.X = missilepo->ObjPosition[ 0 ][ 3 ]; missilepo->PrevPosition.Y = missilepo->ObjPosition[ 1 ][ 3 ]; missilepo->PrevPosition.Z = missilepo->ObjPosition[ 2 ][ 3 ]; missilepo->ObjPosition[ 0 ][ 3 ] += tempspeed.X; missilepo->ObjPosition[ 1 ][ 3 ] += tempspeed.Y; missilepo->ObjPosition[ 2 ][ 3 ] += tempspeed.Z; TargetMissileObject *tmissilepo = (TargetMissileObject *) missilepo; GenObject *targetpo = NULL; if ( tmissilepo->TargetObjNumber == TARGETID_NO_TARGET ) { // no target (already lost) targetpo = NULL; } else if ( tmissilepo->TargetObjNumber == ShipHostObjId( LocalPlayerId ) ) { // local player is target targetpo = MyShip; // announce incoming missile #define INCOMING_SHOWTIME 600 IncomingMissile = INCOMING_SHOWTIME; // start incoming sample looping AUD_IncomingMissile( INCOMING_SHOWTIME ); } else { // search for target in shiplist targetpo = FetchFirstShip(); while ( ( targetpo != NULL ) && ( targetpo->HostObjNumber != tmissilepo->TargetObjNumber ) ) { targetpo = targetpo->NextObj; } if ( targetpo == NULL ) { // missile loses target once object not found tmissilepo->TargetObjNumber = TARGETID_NO_TARGET; } } if ( ( targetpo != NULL ) ) { Vector3 dirvec; dirvec.X = targetpo->ObjPosition[ 0 ][ 3 ] - missilepo->ObjPosition[ 0 ][ 3 ]; dirvec.Y = targetpo->ObjPosition[ 1 ][ 3 ] - missilepo->ObjPosition[ 1 ][ 3 ]; dirvec.Z = targetpo->ObjPosition[ 2 ][ 3 ] - missilepo->ObjPosition[ 2 ][ 3 ]; Vector3 normvec; normvec.X = missilepo->ObjPosition[ 0 ][ 2 ]; normvec.Y = missilepo->ObjPosition[ 1 ][ 2 ]; normvec.Z = missilepo->ObjPosition[ 2 ][ 2 ]; if ( DOT_PRODUCT( &dirvec, &normvec ) < 0 ) { // lock lost due to position tmissilepo->TargetObjNumber = TARGETID_NO_TARGET; } else { normvec.X = missilepo->ObjPosition[ 0 ][ 1 ]; normvec.Y = missilepo->ObjPosition[ 1 ][ 1 ]; normvec.Z = missilepo->ObjPosition[ 2 ][ 1 ]; if ( DOT_PRODUCT( &dirvec, &normvec ) <= 0 ) { ObjRotX( missilepo->ObjPosition, tmissilepo->MaxRotation ); } else { ObjRotX( missilepo->ObjPosition, -tmissilepo->MaxRotation ); } normvec.X = missilepo->ObjPosition[ 0 ][ 0 ]; normvec.Y = missilepo->ObjPosition[ 1 ][ 0 ]; normvec.Z = missilepo->ObjPosition[ 2 ][ 0 ]; if ( DOT_PRODUCT( &dirvec, &normvec ) <= 0 ) { ObjRotY( missilepo->ObjPosition, -tmissilepo->MaxRotation ); } else { ObjRotY( missilepo->ObjPosition, tmissilepo->MaxRotation ); } } DirVctMUL( missilepo->ObjPosition, FIXED_TO_GEOMV( missilepo->Speed ), &missilepo->DirectionVec ); } }