/*------------------------------------------------------------------- Procedure : Create Quaternion from Vector ( Uuuummmmm ) Input : VECTOR * Vector : QUAT * New Quaternion Output : Nothing -------------------------------------------------------------------*/ void QuatFromVector2( VECTOR * Tv, QUAT * q ) { float angle; VECTOR Av; /*------------------------------------------------------------------- Normalise TARGET Vector -------------------------------------------------------------------*/ NormaliseVector( Tv ); /*------------------------------------------------------------------- Create AXIS vector -------------------------------------------------------------------*/ Av.x = Tv->y; Av.y = -Tv->x; Av.z = 0.0F; NormaliseVector( &Av ); /*------------------------------------------------------------------- Calculate ANGLE between TARGET and LOOK vectors -------------------------------------------------------------------*/ angle = (float) ( acos( -Tv->z ) / 2 ); /*------------------------------------------------------------------- Finally build TARGET QUATERNION -------------------------------------------------------------------*/ q->x = (float) ( sin( angle ) * Av.x ); q->y = (float) ( sin( angle ) * Av.y ); q->z = 0.0F; q->w = (float) cos( angle ); QuatNormalise( q ); }
bool BOTAI_FriendlyFireCheck() { int i; VECTOR Move_Dir; VECTOR TempVector; // no need to check if not a team game if(!TeamGame) return false; // calculate my direction vector ApplyMatrix( &Ships[WhoIAm].Object.Mat, &Forward, &Move_Dir ); NormaliseVector( &Move_Dir ); // for each player for(i = 0; i < MAX_PLAYERS; i++) { // that is enabled if( i != WhoIAm && Ships[i].enable && Ships[i].Object.Mode == NORMAL_MODE ) { // and on my team if(TeamNumber[WhoIAm] != TeamNumber[i]) continue; // are we within visible params? if( RaytoSphere2(&Ships[i].Object.Pos, SHIP_RADIUS, &Ships[WhoIAm].Object.Pos, &Move_Dir , &TempVector , &TempVector ) ) return true; } } return false; }
bool BOTAI_AimAtTarget( MATRIX * InvMat , VECTOR * SPos, VECTOR * TPos ) { VECTOR WantedDir; VECTOR TempDir; float Angle; float OnTarget = true; WantedDir.x = ( TPos->x - SPos->x ); WantedDir.y = ( TPos->y - SPos->y ); WantedDir.z = ( TPos->z - SPos->z ); ApplyMatrix( InvMat, &WantedDir, &TempDir ); NormaliseVector( &TempDir ); Angle = (float) acos( TempDir.x ); Angle = 90.0F - R2D( Angle ); if( TempDir.z < 0.0F ) Angle = 180.0F - Angle; if( Angle > 180.0F ) Angle -= 360.0F; if( Angle > 0.0F ) { BOTAI_SetAction( &bot.yaw, 1.0F, "AimAtTarget() yaw right" ); if( Angle > 3.0F ) OnTarget = false; } else if( Angle < 0.0F ) { BOTAI_SetAction( &bot.yaw, -1.0F, "AimAtTarget() yaw left" ); if( Angle < -3.0F ) OnTarget = false; } Angle = (float) acos( TempDir.y ); Angle = 90.0F - R2D( Angle ); Angle *= -1.0F; if( Angle > 180.0F ) Angle -= 360.0F; if( Angle < 0.0F && ( TempDir.z > 0.0F )) { BOTAI_SetAction( &bot.pitch, -1.0F, "AimAtTarget() pitch up" ); if(Angle < -3.0F) OnTarget = false; } else if( Angle > 0.0F && ( TempDir.z > 0.0F )) { BOTAI_SetAction( &bot.pitch, 1.0F, "AimAtTarget() pitch down" ); if(Angle > 3.0F) OnTarget = false; } return OnTarget; }
bool BOTAI_WillHomingMissileHit(VECTOR * MyPos) { float Cos; float Angle; VECTOR DirVector; VECTOR TmpVec; QUATLERP qlerp; SECONDARYWEAPONBULLET MissCopy = SecBulls[ HomingMissile ]; // direction vector from missile to me DirVector.x = MyPos->x - MissCopy.Pos.x; DirVector.y = MyPos->y - MissCopy.Pos.y; DirVector.z = MyPos->z - MissCopy.Pos.z; NormaliseVector( &DirVector ); // angle difference between the missile's current vector and wanted vector Cos = DotProduct( &DirVector, &MissCopy.DirVector ); // set the parameters to perform a linear interpolation on two quaternions QuatFrom2Vectors( &qlerp.end, &Forward, &DirVector ); qlerp.start = MissCopy.DirQuat; qlerp.crnt = &MissCopy.DirQuat; qlerp.dir = QuatDotProduct( &qlerp.start, &qlerp.end ); // bound angle difference if( Cos < -1.0F ) Cos = -1.0F; else if ( Cos > 1.0F ) Cos = 1.0F; // get angle difference in radians Angle = (float) acos( Cos ); // calculate the amount of angle to turn if( Angle ) qlerp.time = ( ( D2R( MissCopy.TurnSpeed ) * framelag ) / Angle ); else qlerp.time = 1.0F; if( qlerp.time > 1.0F ) qlerp.time = 1.0F; // perform quat interpolation QuatInterpolate( &qlerp ); QuatToMatrix( &MissCopy.DirQuat, &MissCopy.Mat ); ApplyMatrix( &MissCopy.Mat, &Forward, &MissCopy.DirVector ); ApplyMatrix( &MissCopy.Mat, &SlideUp, &MissCopy.UpVector ); // will missile hit? if(RaytoSphere2(MyPos, SHIP_RADIUS, &MissCopy.Pos, &MissCopy.DirVector, &TmpVec, &TmpVec )) { DebugPrintf("homing missile will hit\n"); return true; } else { DebugPrintf("safe from homing missile\n"); return false; } }
/*------------------------------------------------------------------- Procedure : Exogenon Fire Input : ENEMY * Enemy Output : Nothing -------------------------------------------------------------------*/ void AI_EXOGENON_FIRE( register ENEMY * Enemy ) { VECTOR TempVector; VECTOR TempUpVector; VECTOR TempOffset = { 0.0F, 0.0F, 180.0F }; float Distance; Enemy->Object.AnimSpeed = 1.0F; if( Enemy->Timer ) { Enemy->Timer -= framelag; if( Enemy->Timer <= 0.0F ) { // This is where the main Weapon would fire.... Enemy->Timer = 0.0F; if( EnemyTypes[Enemy->Type].PrimaryWeaponType != NO_PRIMARY ) { ApplyMatrix( &Enemy->Object.Mat, &Forward, &TempVector ); Distance = DistanceVector2Vector( &Ships[WhoIAm].Object.Pos ,&Enemy->Object.Pos ); TempVector.x *= Distance; TempVector.y *= Distance; TempVector.z *= Distance; TempVector.y -= Enemy->Object.Pos.y - Ships[WhoIAm].Object.Pos.y; NormaliseVector(&TempVector); ApplyMatrix( &Enemy->Object.Mat, &SlideUp, &TempUpVector ); EnemyFirePrimary( OWNER_ENEMY, Enemy->Index, ++Enemy->BulletID, EnemyTypes[Enemy->Type].PrimaryWeaponType, Enemy->Object.Group, &Enemy->Object.Pos, &TempOffset, &TempVector, &TempUpVector, EnemyTypes[Enemy->Type].PowerLevel, (EnemyTypes[Enemy->Type].PowerLevel +1) * 33.0F, FALSE, NULL ); } Enemy->Object.AI_Mode = AIMODE_EXOGENON_SWEEP; ExogenonAim( Enemy ); ExogenonSweepDir = Enemy->AIMoveFlags; ExogenonSweepAngle = Enemy->AI_Angle; Enemy->Timer = 60.0F * 1.0F; } } }
bool BOTAI_InViewCone( VECTOR * Pos, MATRIX * Mat, VECTOR * TPos, float ViewConeCos ) { float Cos; VECTOR NormVector; VECTOR Dir; if( ViewConeCos == 1.0F ) return true; Dir.x = TPos->x - Pos->x; Dir.y = TPos->y - Pos->y; Dir.z = TPos->z - Pos->z; NormVector = Dir; NormaliseVector( &NormVector ); ApplyMatrix( Mat, &Forward, &Dir ); Cos = DotProduct( &NormVector, &Dir ); if( Cos > ViewConeCos ) return true; return false; }
float BOTAI_WhenWillBulletHitMe(VECTOR * MyPos) { int i; float time; float shortestTime = BIGDISTANCE; float dist; VECTOR TempVect; VECTOR temp; VECTOR TempVector; float ShipRadius; float Cos; // primary weapon bullets for(i = 0; i < MAXPRIMARYWEAPONBULLETS; i++) { // that are active and aren't my own if(PrimBulls[i].Used && PrimBulls[i].Owner != WhoIAm) { // set the collision radius switch( PrimaryWeaponAttribs[ PrimBulls[i].Weapon ].ColType ) { case COLTYPE_Transpulse: TempVector.x = Ships[ WhoIAm ].Object.Pos.x - PrimBulls[i].Pos.x; TempVector.y = Ships[ WhoIAm ].Object.Pos.y - PrimBulls[i].Pos.y; TempVector.z = Ships[ WhoIAm ].Object.Pos.z - PrimBulls[i].Pos.z; NormaliseVector( &TempVector ); Cos = (float) ( 1.0F - fabs( DotProduct( &TempVector, &PrimBulls[i].Dir ) ) ); Cos = (float) ( Cos * ( 1.0F - fabs( DotProduct( &TempVector, &PrimBulls[i].UpVector ) ) ) ); ShipRadius = SHIP_RADIUS + ( PrimBulls[i].ColRadius * Cos ); break; case COLTYPE_Sphere: case COLTYPE_Trojax: ShipRadius = SHIP_RADIUS + PrimBulls[i].ColRadius; break; case COLTYPE_Point: default: ShipRadius = SHIP_RADIUS; break; } // bullet will (currently) eventually collide with this position if(RaytoSphere2( MyPos, ShipRadius, &PrimBulls[i].Pos, &PrimBulls[i].Dir, &TempVect, &TempVect )) { dist = DistanceVector2Vector(MyPos, &PrimBulls[i].Pos); time = dist/PrimBulls[i].Speed; if(time < shortestTime) shortestTime = time; } } } // reset homing missile flag when it's gone if(HomingMissile > -1) { if(!SecBulls[HomingMissile].Used) MissileAvoidanceSet = false; } // missiles HomingMissile = -1; for(i = 0; i< MAXSECONDARYWEAPONBULLETS; i++) { // ignore inactive missiles or my own if(!SecBulls[i].Used || SecBulls[i].Owner == WhoIAm) continue; // get the distance from me and time to impact dist = DistanceVector2Vector(MyPos, &SecBulls[i].Pos); time = dist/SecBulls[i].Speed; // straight missiles (treat like normal bullets) if(SecBulls[i].MoveType == MISMOVE_STRAIGHT ) { // if it will hit me if(RaytoSphere2(MyPos, SHIP_RADIUS, &SecBulls[i].Pos, &SecBulls[i].DirVector, &TempVect, &TempVect)) { if(time < shortestTime) shortestTime = time; // find the closest } } // if a homing missile has locked on to me else if(SecBulls[i].MoveType == MISMOVE_HOMING && SecBulls[i].Target == WhoIAm) { // and it's close enough i have to deal with it if(dist < 2048.0F * GLOBAL_SCALE) { HomingMissile = i; shortestTime = time; // new } } } if(shortestTime < 10000.0F) return shortestTime; else return -1.0F; // nothing will hit }
void BOTAI_AvoidHomingMissiles() { VECTOR NormVector; VECTOR DirVector; float xAngle; float yAngle; if(HomingMissile > -1) { // -- decide what movement to perform // new missile //if(!MissileAvoidanceSet) { //DebugPrintf("set details for missile %d\n", HomingMissile); MissileAvoidanceSet = true; NormVector.x = SecBulls[HomingMissile].Pos.x - Ships[WhoIAm].Object.Pos.x; NormVector.y = SecBulls[HomingMissile].Pos.y - Ships[WhoIAm].Object.Pos.y; NormVector.z = SecBulls[HomingMissile].Pos.z - Ships[WhoIAm].Object.Pos.z; ApplyMatrix( &Ships[WhoIAm].Object.FinalInvMat, &NormVector, &DirVector ); NormaliseVector( &DirVector ); MissileOrigDirVector = DirVector; } // left/right angle xAngle = (float) acos( MissileOrigDirVector.x ); xAngle = 90.0F - R2D( xAngle ); if( MissileOrigDirVector.z < 0.0F ) xAngle = 180.0F - xAngle; if( xAngle > 180.0F ) xAngle -= 360.0F; //DebugPrintf("x = %f\n", xAngle); // up/down angle yAngle = (float) acos( MissileOrigDirVector.y ); yAngle = 90.0F - R2D( yAngle ); yAngle *= -1.0F; if( yAngle > 180.0F ) yAngle -= 360.0F; //DebugPrintf("y = %f\n", yAngle); // -- execute slide movements // target is directly in front or behind me if((xAngle > -22.5F && xAngle < 22.5F) || (xAngle < -157.5F || xAngle > 157.5F)) { // slide either left or right, doesn't matter BOTAI_SetAction( &bot.right, 1.0F, "AvoidHomingMissiles() right" ); } // target is directly to the side of me else if((xAngle > 67.5F && xAngle < 112.5F) || (xAngle < -67.5F && xAngle > -112.5F)) { // forward or backward, doesn't matter BOTAI_SetAction( &bot.forward, 1.0F, "AvoidHomingMissiles() forward" ); } // target is to my front left else if(xAngle > -67.5F && xAngle < -22.5F) { // move forward right BOTAI_SetAction( &bot.forward, 1.0F, "AvoidHomingMissiles() forward" ); BOTAI_SetAction( &bot.right, 1.0F, "AvoidHomingMissiles() right" ); } // target is to my rear left else if(xAngle > -157.5F && xAngle < -112.5F) { // move back left BOTAI_SetAction( &bot.forward, -1.0F, "AvoidHomingMissiles() reverse" ); BOTAI_SetAction( &bot.forward, -1.0F, "AvoidHomingMissiles() left" ); } // target is to my front right else if(xAngle > 22.5F && xAngle < 67.5F) { // move front left BOTAI_SetAction( &bot.forward, 1.0F, "AvoidHomingMissiles() forward" ); BOTAI_SetAction( &bot.right, -1.0F, "AvoidHomingMissiles() left" ); } // target is to my rear right else if(xAngle > 112.5F && xAngle < 157.5F) { // move back right BOTAI_SetAction( &bot.forward, -1.0F, "AvoidHomingMissiles() reverse" ); BOTAI_SetAction( &bot.right, 1.0F, "AvoidHomingMissiles() right" ); } if(yAngle > 0.0F) BOTAI_SetAction( &bot.up, -1.0F, "AvoidHomingMissiles() down" ); else BOTAI_SetAction( &bot.up, 1.0F, "AvoidHomingMissiles() up" ); } }
/* Slides to target pos without aiming at it; returns true if reached target */ bool BOTAI_SlideToTarget(VECTOR * TPos) { VECTOR NormVector; VECTOR DirVector; float xAngle; float yAngle; //DebugPrintf("sliding to target\n"); // -- Calculate angles NormVector.x = TPos->x - Ships[WhoIAm].Object.Pos.x; NormVector.y = TPos->y - Ships[WhoIAm].Object.Pos.y; NormVector.z = TPos->z - Ships[WhoIAm].Object.Pos.z; ApplyMatrix( &Ships[WhoIAm].Object.FinalInvMat, &NormVector, &DirVector ); NormaliseVector( &DirVector ); ////DebugPrintf("x = %f y = %f z = %f\n", DirVector.x, DirVector.y, DirVector.z); // left/right angle xAngle = (float) acos( DirVector.x ); xAngle = 90.0F - R2D( xAngle ); if( DirVector.z < 0.0F ) xAngle = 180.0F - xAngle; if( xAngle > 180.0F ) xAngle -= 360.0F; ////DebugPrintf("X Angle %f\n", xAngle); // up/down angle yAngle = (float) acos( DirVector.y ); yAngle = 90.0F - R2D( yAngle ); yAngle *= -1.0F; if( yAngle > 180.0F ) yAngle -= 360.0F; ////DebugPrintf("Y Angle %f\n", yAngle); ////DebugPrintf("z %f\n", DirVector.z); // -- execute slide movements // sliding right if(xAngle > 0.0F && DistWall[0] > 100.0F) BOTAI_SetAction( &bot.right, 1.0F, "SlideToTarget() right" ); // sliding left else if(xAngle < 0.0F && DistWall[1] > 100.0F) BOTAI_SetAction( &bot.right, -1.0F, "SlideToTarget() left" ); // sliding up if(DistWall[2] > 100.0F) { if(yAngle < 0.0F ) BOTAI_SetAction( &bot.up, 1.0F, "SlideToTarget() up" ); } // sliding down if(DistWall[3] > 100.0F) { if(yAngle > 0.0F) BOTAI_SetAction( &bot.up, -1.0F, "SlideToTarget() down" ); } // forward if(DirVector.z > 0.0F && DistWall[8] > 100.0F) BOTAI_SetAction( &bot.forward, 1.0F, "SlideToTarget() forward" ); // backward else if(DirVector.z < 0.0F && DistWall[9] > 100.0F ) BOTAI_SetAction( &bot.forward, -1.0F, "SlideToTarget() reverse" ); // Reached Target if(Ships[WhoIAm].Object.Pos.x < TPos->x + TOL && Ships[WhoIAm].Object.Pos.x > TPos->x - TOL && Ships[WhoIAm].Object.Pos.y < TPos->y + TOL && Ships[WhoIAm].Object.Pos.y > TPos->y - TOL && Ships[WhoIAm].Object.Pos.z < TPos->z + TOL && Ships[WhoIAm].Object.Pos.z > TPos->z - TOL) return true; else return false; }
/* (buggy) always triple chords up/right/forward to target */ bool BOTAI_MoveToTarget(VECTOR * TPos) { VECTOR NormVector; VECTOR DirVector; float xAngle; float yAngle; //DebugPrintf("moving to %f %f %f\n", TPos->x, TPos->y, TPos->z); // set slide movements and check if at target pos if(BOTAI_SlideToTarget(TPos)) return true; // adjust the aim // -- Calculate angles NormVector.x = TPos->x - Ships[WhoIAm].Object.Pos.x; NormVector.y = TPos->y - Ships[WhoIAm].Object.Pos.y; NormVector.z = TPos->z - Ships[WhoIAm].Object.Pos.z; ApplyMatrix( &Ships[WhoIAm].Object.FinalInvMat, &NormVector, &DirVector ); NormaliseVector( &DirVector ); ////DebugPrintf("x = %f y = %f z = %f\n", DirVector.x, DirVector.y, DirVector.z); // left/right angle xAngle = (float) acos( DirVector.x ); xAngle = 90.0F - R2D( xAngle ); if( DirVector.z < 0.0F ) xAngle = 180.0F - xAngle; if( xAngle > 180.0F ) xAngle -= 360.0F; ////DebugPrintf("X Angle %f\n", xAngle); // up/down angle yAngle = (float) acos( DirVector.y ); yAngle = 90.0F - R2D( yAngle ); yAngle *= -1.0F; if( yAngle > 180.0F ) yAngle -= 360.0F; ////DebugPrintf("Y Angle %f\n", yAngle); // -- angle aim // sliding right if( bot.right == 1.0F) { // aim left if(xAngle < 30.0F) BOTAI_SetAction( &bot.yaw, -1.0F, "MoveToTarget() yaw left" ); // aim right else if(xAngle > 40.0F) BOTAI_SetAction( &bot.yaw, 1.0F, "MoveToTarget() yaw right" ); } // sliding left else if( bot.right == -1.0F) { // aim left if(xAngle < -40.0F) BOTAI_SetAction( &bot.yaw, -1.0F, "MoveToTarget() yaw left" ); // aim right else if(xAngle > -30.0F) BOTAI_SetAction( &bot.yaw, 1.0F, "MoveToTarget() yaw right" ); } // sliding up if(bot.up == 1.0F) { // aim up if(yAngle < -40.0F) BOTAI_SetAction( &bot.pitch, -1.0F, "MoveToTarget() pitch up" ); // aim down else if(yAngle > -30.0F) BOTAI_SetAction( &bot.pitch, 1.0F, "MoveToTarget() pitch down" ); } // sliding down else if(bot.up == -1.0F) { // aim up if(yAngle > 30.0F) BOTAI_SetAction( &bot.pitch, -1.0F, "MoveToTarget() pitch up" ); // aim down else if(yAngle < 40.0F) BOTAI_SetAction( &bot.pitch, 1.0F, "MoveToTarget() pitch down" ); } return false; }
/* triple-chords to target pos in a straight line; returns true if reached target */ bool BOTAI_MoveToTargetNew(VECTOR * TPos) { VECTOR Slide; VECTOR TriChordVector; VECTOR WantedVector; VECTOR NormVector; VECTOR DirVector; VECTOR FwdDirVector; float xAngle; float yAngle; float Cos; ////DebugPrintf("moving to %f %f %f\n", TPos->x, TPos->y, TPos->z); // -- calculate direction vector from my position to target NormVector.x = TPos->x - Ships[WhoIAm].Object.Pos.x; NormVector.y = TPos->y - Ships[WhoIAm].Object.Pos.y; NormVector.z = TPos->z - Ships[WhoIAm].Object.Pos.z; DirVector = NormVector; // apply that vector to my matrix to make direction relative to my direction and rotation //ApplyMatrix( &Ships[WhoIAm].Object.FinalInvMat, &NormVector, &DirVector ); NormaliseVector( &DirVector ); //DebugPrintf("straight x = %f y = %f z = %f\n", DirVector.x, DirVector.y, DirVector.z); // calculate the desired vector // forward right Slide.x = 1.0F; Slide.y = 0.0F; Slide.z = 1.0F; // calculate the triple chord direction vector ApplyMatrix( &Ships[WhoIAm].Object.FinalMat, &Slide, &TriChordVector ); NormaliseVector( &TriChordVector ); //DebugPrintf("trivec x = %f y = %f z = %f\n", TriChordVector.x, TriChordVector.y, TriChordVector.z); // difference between wanted vector and slide vector WantedVector.x = DirVector.x - TriChordVector.x; WantedVector.y = DirVector.y - TriChordVector.y; WantedVector.z = DirVector.z - TriChordVector.z; ////DebugPrintf("W x = %f y = %f z = %f\n", WantedVector.x, WantedVector.y, WantedVector.z); // angle between trichord vector and wanted vector, == 1.0F when aligned perfectly Cos = DotProduct( &DirVector, &TriChordVector ); ////DebugPrintf("Cos = %f\n", Cos); return false; // left/right angle xAngle = (float) acos( WantedVector.x ); xAngle = 90.0F - R2D( xAngle ); if( WantedVector.z < 0.0F ) xAngle = 180.0F - xAngle; if( xAngle > 180.0F ) xAngle -= 360.0F; ////DebugPrintf("X Angle %f\n", xAngle); // up/down angle yAngle = (float) acos( WantedVector.y ); yAngle = 90.0F - R2D( yAngle ); yAngle *= -1.0F; if( yAngle > 180.0F ) yAngle -= 360.0F; ////DebugPrintf("Y Angle %f\n", yAngle); if( xAngle > 0.0F ) BOTAI_SetAction( &bot.yaw, 1.0F, "MoveToTargetNew() yaw right" ); else if( xAngle < 0.0F ) BOTAI_SetAction( &bot.yaw, -1.0F, "MoveToTargetNew() yaw left" ); if( yAngle < 0.0F && ( WantedVector.z > 0.0F )) BOTAI_SetAction( &bot.pitch, -1.0F, "MoveToTargetNew() pitch up" ); else if( yAngle > 0.0F && ( WantedVector.z > 0.0F )) BOTAI_SetAction( &bot.pitch, 1.0F, "MoveToTargetNew() pitch down" ); // Reached Target if(Ships[WhoIAm].Object.Pos.x < TPos->x + TOL && Ships[WhoIAm].Object.Pos.x > TPos->x - TOL && Ships[WhoIAm].Object.Pos.y < TPos->y + TOL && Ships[WhoIAm].Object.Pos.y > TPos->y - TOL && Ships[WhoIAm].Object.Pos.z < TPos->z + TOL && Ships[WhoIAm].Object.Pos.z > TPos->z - TOL) return true; else return false; }
/****************************************************************************************** Process real-time game lights *******************************************************************************************/ void ProcessRTLights( void ) { int j; RT_LIGHT *light; XLIGHT *xlight; RT_FIXED_LIGHT *fixed; RT_PULSING_LIGHT *pulse; RT_FLICKERING_LIGHT *flicker; RT_SPOT_LIGHT *spot; float chance; MATRIX rotmat; for ( j = 0; j < rt_lights; j++ ) { light = &rt_light[ j ]; if ( light->xlight == (u_int16_t) -1 ) continue; // only happens if run out of XLIGHTs xlight = &XLights[ light->xlight ]; if ( light->delay > 0.0F ) { light->delay -= framelag; if ( light->delay <= 0.0F ) { light->enabled = true; } } if ( light->enabled ) { switch ( light->type ) { case LIGHT_FIXED: fixed = &light->fixed; switch ( light->state ) { case STATE_OFF: light->now_time = 0.0F; xlight->Visible = false; light->intensity = 0.0F; break; case STATE_TURNING_ON: if ( light->delay < 0.0F ) { light->now_time += -light->delay; light->delay = 0.0F; } else light->now_time += framelag; xlight->Visible = true; if ( light->now_time < fixed->on_time ) { InterpLightOn( light, light->now_time / fixed->on_time, fixed->on_type ); } else { xlight->r = light->r; xlight->g = light->g; xlight->b = light->b; xlight->Visible = true; light->state = STATE_ON; } break; case STATE_ON: xlight->r = light->r; xlight->g = light->g; xlight->b = light->b; xlight->Visible = true; break; case STATE_TURNING_OFF: light->now_time += framelag; xlight->Visible = true; if ( light->now_time < fixed->off_time ) { InterpLightOff( light, light->now_time / fixed->off_time, fixed->off_type ); } else { light->state = STATE_OFF; light->now_time = 0.0F; xlight->Visible = false; } break; } break; case LIGHT_PULSING: pulse = &light->pulse; if ( light->delay < 0.0F ) { light->now_time += -light->delay; light->delay = 0.0F; } else light->now_time += framelag; if ( light->now_time > pulse->total_time ) { light->now_time = FMOD( light->now_time, pulse->total_time ); } if ( light->now_time < pulse->on_time ) { // light is turning on light->state = STATE_TURNING_ON; InterpLightOn( light, light->now_time / pulse->on_time, pulse->type ); xlight->Visible = true; } else if ( light->now_time < pulse->stay_on_point ) { // light is staying on light->state = STATE_ON; xlight->r = light->r; xlight->g = light->g; xlight->b = light->b; xlight->Visible = true; } else if ( light->now_time < pulse->off_point ) { // light is turning off light->state = STATE_TURNING_OFF; InterpLightOff( light, ( light->now_time - pulse->stay_on_point ) / pulse->off_time, pulse->type ); xlight->Visible = true; } else // light->now_time < pulse->total_time { // light is staying off light->state = STATE_OFF; xlight->Visible = false; } break; case LIGHT_FLICKERING: flicker = &light->flicker; chance = RANDOM(); if ( light->delay < 0.0F ) { light->now_time += -light->delay; light->delay = 0.0F; } else light->now_time += framelag; if ( light->state == STATE_ON ) { // check chance of switching off if ( light->now_time > flicker->stay_on_time && chance > flicker->stay_on_chance ) { light->state = STATE_OFF; light->now_time = 0.0F; xlight->Visible = false; } } else // light is off { // check chance of switching on if ( light->now_time > flicker->stay_off_time && chance > flicker->stay_off_chance ) { light->state = STATE_ON; light->now_time = 0.0F; xlight->Visible = true; } } break; case LIGHT_SPOT: spot = &light->spot; if ( spot->rotation_speed ) { // rotate spotlight beam if ( light->delay < 0.0F ) { light->now_time += -light->delay; light->delay = 0.0F; } else light->now_time += framelag; spot->angle = light->now_time * spot->rotation_speed; if ( spot->angle > TWO_PI ) spot->angle = FMOD( spot->angle, TWO_PI ); MatrixFromAxisAndAngle( spot->angle, &spot->up, &rotmat ); ApplyMatrix( &rotmat, &spot->dir, &xlight->Dir ); NormaliseVector( &xlight->Dir ); } light->state = STATE_ON; xlight->Visible = true; break; } } else { // light is disabled, check if turning off if ( light->state == STATE_TURNING_OFF ) { switch ( light->type ) { case LIGHT_FIXED: fixed = &light->fixed; light->now_time += framelag; if ( light->now_time < fixed->off_time ) { InterpLightOff( light, light->now_time / fixed->off_time, fixed->off_type ); xlight->Visible = true; } else { light->state = STATE_OFF; light->now_time = 0.0F; xlight->Visible = false; } break; case LIGHT_PULSING: pulse = &light->pulse; light->now_time += framelag; if ( light->now_time < pulse->off_time ) { InterpLightOff( light, light->now_time / pulse->off_time, pulse->type ); xlight->Visible = true; } else { light->state = STATE_OFF; light->now_time = 0.0F; xlight->Visible = false; } break; case LIGHT_FLICKERING: light->state = STATE_OFF; xlight->Visible = false; break; case LIGHT_SPOT: light->state = STATE_OFF; xlight->Visible = false; break; } } else if ( light->delay <= 0.0F ) { light->state = STATE_OFF; xlight->Visible = false; } } } }
/*------------------------------------------------------------------- Procedure : create a quaternion from two vectors that rotates v1 to v2 about an axis perpendicular to both Input : QUAT * Destin Quaternion : VECTOR * v1 : VECTOR * v2 Output : Nothing -------------------------------------------------------------------*/ void QuatFrom2Vectors( QUAT * destQuat, VECTOR * v1, VECTOR * v2 ) { VECTOR u1, u2; VECTOR axis; /* axis of rotation */ float theta; /* angle of rotation about axis */ float theta_complement; float crossProductMagnitude; /* ** Normalize both vectors and take cross product to get rotation axis. */ u1 = *v1; u2 = *v2; NormaliseVector( &u1 ); NormaliseVector( &u2 ); CrossProduct( &u1 , &u2, &axis ); /* ** | u1 X u2 | = |u1||u2|sin(theta) ** ** Since u1 and u2 are normalized, ** ** theta = arcsin(|axis|) */ crossProductMagnitude = (float) sqrt( DotProduct( &axis , &axis ) ); /* ** Occasionally, even though the vectors are normalized, the magnitude will ** be calculated to be slightly greater than one. If this happens, just ** set it to 1 or asin() will barf. */ if( crossProductMagnitude > 1.0F ) crossProductMagnitude = 1.0F; /* ** Take arcsin of magnitude of rotation axis to compute rotation angle. ** Since crossProductMagnitude=[0,1], we will have theta=[0,pi/2]. */ theta = (float) asin( crossProductMagnitude ); theta_complement = PI - theta; /* ** If cos(theta) < 0, use complement of theta as rotation angle. */ if( DotProduct( &u1 , &u2 ) < 0.0F ) { theta = theta_complement; theta_complement = PI - theta; } /* if angle is 0, just return identity quaternion */ if( theta < EPS ) { destQuat->x = 0.0F; destQuat->y = 0.0F; destQuat->z = 0.0F; destQuat->w = 1.0F; }else{ if( theta_complement < EPS ) { /* ** The two vectors are opposed. Find some arbitrary axis vector. ** First try cross product with x-axis if u1 not parallel to x-axis. */ if( (u1.y*u1.y + u1.z*u1.z) >= EPS ) { axis.x = 0.0F ; axis.y = u1.z ; axis.z = u1.y ; }else{ /* ** u1 is parallel to to x-axis. Use z-axis as axis of rotation. */ axis.x = axis.y = 0.0F ; axis.z = 1.0F ; } } NormaliseVector( &axis ); QuatMake( destQuat, axis.x, axis.y, axis.z, theta ) ; QuatNormalise( destQuat ); } }