//======================================================================================== // geCamera_ScreenPointToWorld //======================================================================================== GENESISAPI void GENESISCC geCamera_ScreenPointToWorld ( const geCamera *Camera, int32 ScreenX, int32 ScreenY, geVec3d *Vector) // Takes a screen X and Y pair, and a camera and generates a vector pointing // in the direction from the camera position to the screen point. { geVec3d In,Left,Up; geVec3d ScaledIn,ScaledLeft,ScaledUp ; geFloat XCenter ; geFloat YCenter ; geFloat Scale ; const geXForm3d *pM; pM = &(Camera->TransposeXForm); XCenter = Camera->XCenter ; YCenter = Camera->YCenter ; Scale = Camera->Scale ; geXForm3d_GetIn( pM, &In ) ; geXForm3d_GetLeft( pM, &Left ) ; geXForm3d_GetUp( pM, &Up ) ; geVec3d_Scale(&In, Scale, &ScaledIn); geVec3d_Scale(&Left, XCenter - ((geFloat)ScreenX), &ScaledLeft ); geVec3d_Scale(&Up, YCenter - ((geFloat)ScreenY), &ScaledUp ); geVec3d_Copy(&ScaledIn, Vector); geVec3d_Add(Vector, &ScaledLeft, Vector ); geVec3d_Add(Vector, &ScaledUp, Vector ); geVec3d_Normalize(Vector); }
void GENESISCC geExtBox_Translate( geExtBox *B, geFloat DX, geFloat DY, geFloat DZ ) { geVec3d VecDelta; assert (geExtBox_IsValid (B) != GE_FALSE); geVec3d_Set (&VecDelta, DX, DY, DZ); assert( geVec3d_IsValid(&VecDelta) != GE_FALSE ); geVec3d_Add (&B->Min, &VecDelta, &B->Min); geVec3d_Add (&B->Max, &VecDelta, &B->Max); }
/* ------------------------------------------------------------------------------------ */ void DrawBoundBox(geWorld *World, const geVec3d *Pos, const geVec3d *Min, const geVec3d *Max) { geFloat dx; geFloat dy; geFloat dz; static geVec3d Verts[8]; static geVec3d * Faces[6][4] = { {&Verts[0], &Verts[1], &Verts[2], &Verts[3]}, //Top {&Verts[4], &Verts[5], &Verts[6], &Verts[7]}, //Bottom {&Verts[3], &Verts[2], &Verts[6], &Verts[7]}, //Side {&Verts[1], &Verts[0], &Verts[4], &Verts[5]}, //Side {&Verts[0], &Verts[3], &Verts[7], &Verts[4]}, //Front {&Verts[2], &Verts[1], &Verts[5], &Verts[6]}, //Back }; int i; for(i=0; i<8; i++) geVec3d_Add(Pos, Min, &Verts[i]); dx = Max->X - Min->X; dy = Max->Y - Min->Y; dz = Max->Z - Min->Z; Verts[0].Y += dy; Verts[3].Y += dy; Verts[3].X += dx; Verts[7].X += dx; Verts[1].Y += dy; Verts[1].Z += dz; Verts[5].Z += dz; Verts[6].Z += dz; Verts[6].X += dx; Verts[2].X += dx; Verts[2].Y += dy; Verts[2].Z += dz; for(i=0; i<6; i++) DrawFace(World, &Faces[i][0]); }
//===================================================================================== // LeafCenter //===================================================================================== void LeafCenter(GBSP_Node *Node, geVec3d *PortalMid) { int32 NumPortals, Side; geVec3d Mid; GBSP_Portal *Portal; NumPortals = 0; geVec3d_Clear(PortalMid); for (Portal = Node->Portals; Portal; Portal = Portal->Next[Side]) { Side = Portal->Nodes[1] == Node; PolyCenter(Portal->Poly, &Mid); geVec3d_Add(PortalMid, &Mid, PortalMid); NumPortals++; } geVec3d_Scale(PortalMid, 1.0f/(geFloat)NumPortals, PortalMid); }
void weapon_mini_rocket_proccess(float timePassed){ #define COLLISION geWorld_Collision(mini_rocketCurrentWorld,&(g->box.Min),&(g->box.Max),&(g->position),&newPos,GE_CONTENTS_SOLID_CLIP,GE_COLLIDE_ALL,0xffffffff, cb_move, 0, &lCol) int i; InfMiniRocket* g; geVec3d newPos; geVec3d to; geVec3d angles; GE_Collision lCol; for( i=0; i<NUMBER_OF_MINIROCKETS; i++){ g = & miniRockets[i]; if( g->active ){ geVec3d_AddScaled(&(g->position), &(g->velocity), timePassed, &(newPos) ); if( COLLISION ) { g->position = lCol.Impact; //geVec3d_Scale(&(g->velocity), -0.8f, &(g->velocity) ); weapon_mini_rocket_destroy(g); } else { g->position = newPos; } geVec3d_Add(&(g->position), &(g->velocity), &to); LookAt(g->position, to, &angles); angles.X += GE_PI/2; // update xform variable geXForm3d_SetIdentity(&(g->xform)); geXForm3d_RotateX(&(g->xform), angles.X); geXForm3d_RotateY(&(g->xform), angles.Y); geXForm3d_RotateZ(&(g->xform), angles.Z); g->xform.Translation = g->position; geActor_ClearPose(g->mini_rocket, &(g->xform) ); } } #undef COLLISION }
/* ------------------------------------------------------------------------------------ */ void CCameraManager::DoThirdPersonTracking() { geXForm3d theViewPoint; geVec3d Pos; GE_Collision Collision; geVec3d Front, Back; geVec3d Direction; geFloat CurrentDistance; geExtBox ActorExtBox; geFloat ActorScale; geVec3d Orient; geFloat x; // changed QD 01/2004 geFloat PlayerScale = CCD->Player()->GetScale(); // end change CCD->ActorManager()->GetScale(theActor, &ActorScale); // Get actor scale CCD->ActorManager()->GetBoundingBox(theActor, &ActorExtBox); CurrentDistance = m_defaultdistance * ActorScale; geVec3d ActorPosition, ActorRotation; CCD->ActorManager()->GetPosition(theActor, &ActorPosition); ActorPosition.Y += CameraOffsetTranslation.Y; CCD->ActorManager()->GetRotation(theActor, &ActorRotation); // Start Nov2003DCS geVec3d_Add(&ActorRotation, &CameraOffsetRotation, &ActorRotation); // End Nov2003DCS ActorRotation.X = 0.0f; // changed QD 12/15/05 //geXForm3d_SetIdentity(&theViewPoint); //geXForm3d_RotateZ(&theViewPoint, ActorRotation.Z+CameraOffsetRotation.Z); geXForm3d_SetZRotation(&theViewPoint, ActorRotation.Z+CameraOffsetRotation.Z); // end change geXForm3d_RotateX(&theViewPoint, ActorRotation.X+CameraOffsetRotation.X+GE_PIOVER180*(m_cameraX)); geXForm3d_RotateY(&theViewPoint, ActorRotation.Y+CameraOffsetRotation.Y+GE_PIOVER180*(m_cameraY)); geXForm3d_Translate(&theViewPoint, ActorPosition.X, ActorPosition.Y, ActorPosition.Z); Pos = theViewPoint.Translation; geXForm3d_GetIn(&theViewPoint, &Direction); geVec3d_AddScaled(&Pos, &Direction, CurrentDistance, &Back); // changed QD 12/15/05 // geVec3d_AddScaled(&Pos, &Direction, 0.0f, &Front); geVec3d_Copy(&Pos, &Front); // end change if(geWorld_Collision(CCD->World(), &CameraExtBox.Min, &CameraExtBox.Max, &Front, &Back, /*GE_VISIBLE_CONTENTS*/GE_CONTENTS_SOLID_CLIP, GE_COLLIDE_ALL, 0, NULL, NULL, &Collision)) { // changed QD 01/2004 // can't be negative (sqrt!) // CurrentDistance = (geFloat)fabs(geVec3d_DistanceBetween(&Collision.Impact, &Front)); // if(CurrentDistance < 0.0f) // CurrentDistance = 0.0f; CurrentDistance = geVec3d_DistanceBetween(&Collision.Impact, &Front); // end change if(CurrentDistance > (m_defaultdistance*ActorScale)) CurrentDistance = m_defaultdistance*ActorScale; geVec3d_AddScaled(&Pos, &Direction, CurrentDistance, &Back); } // changed QD 01/2004 geVec3d_AddScaled(&Pos, &Direction, playermindistance*ActorScale, &Front); if(CCD->Meshes()->CollisionCheck(&CameraExtBox.Min, &CameraExtBox.Max, Front, Back, &Collision)) { // changed QD distance can't be negative // geFloat CurrentDistance2 = (geFloat)fabs(geVec3d_DistanceBetween(&Collision.Impact, &Front));//-4.0f; geFloat CurrentDistance2 = geVec3d_DistanceBetween(&Collision.Impact, &Front); CurrentDistance2 += playermindistance*ActorScale; if(theActor == CCD->Player()->GetActor()) { if(CurrentDistance2 < (playermindistance*ActorScale)) CurrentDistance2 = playermindistance*ActorScale; if(CurrentDistance2 > (playermaxdistance*ActorScale)) CurrentDistance2 = playermaxdistance*ActorScale; } else { if(CurrentDistance2 > (m_defaultdistance*ActorScale)) CurrentDistance2 = m_defaultdistance*ActorScale; } if(CurrentDistance2 < CurrentDistance) { CurrentDistance = CurrentDistance2; geVec3d_AddScaled(&Pos, &Direction, CurrentDistance2, &Back); } } // end change m_currentdistance = CurrentDistance/ActorScale; // Ok, here's the implementation of Ralph Deane's too-cool // ..third-person Actor Fading code. As the camera approaches // ..the player avatar, the AVATAR IS FADED OUT until finally // ..it's rendering is shut down. This is one Way Cool Effect. // 03/22/2000 eaa3 Added Ralph Deane's scaling fixes. geFloat fAlpha = 255.0f; if(CurrentDistance < (40.0f*ActorScale)) { fAlpha = (10.0f*((CurrentDistance-((geFloat)fabs(ActorExtBox.Min.Z)+1.0f))/ActorScale))+30.0f; if(fAlpha < (15.0f*ActorScale)) fAlpha = 0.0f; if(fAlpha > 255.0f) fAlpha = 255.0f; } CCD->ActorManager()->SetAlpha(theActor, fAlpha); // Adjust actor alpha geVec3d_Subtract( &Pos, &Back, &Orient ); // protect from Div by Zero if(CurrentDistance > 0.0f) { x = Orient.X; // changed QD 12/15/05 // Orient.X = (geFloat)( GE_PI*0.5 ) - (geFloat)acos(Orient.Y / CurrentDistance); Orient.X = GE_PIOVER2 - (geFloat)acos(Orient.Y / CurrentDistance); Orient.Y = (geFloat)atan2(x, Orient.Z) + GE_PI; Orient.Z = 0.0f; // roll is zero - always!!? } Rotation = Orient; // Set camera orientation Translation = Back; // Set camera translation return; }
/* ------------------------------------------------------------------------------------ */ geBoolean CDSpotLight::Tick(geFloat dwTicks) { geEntity_EntitySet *pSet; geEntity *pEntity; if(CCD->World() == NULL) return GE_TRUE; pSet = geWorld_GetEntitySet(CCD->World(), "DSpotLight"); if(!pSet) return GE_TRUE; for(pEntity=geEntity_EntitySetGetNextEntity(pSet, NULL); pEntity; pEntity=geEntity_EntitySetGetNextEntity(pSet, pEntity)) { DSpotLight *Light; geFloat Radius; geFloat Percentage; int Index; geVec3d Pos; int32 Leaf; Light = (DSpotLight*)geEntity_GetUserData(pEntity); if(!EffectC_IsStringNull(Light->TriggerName)) { if(GetTriggerState(Light->TriggerName)) { if(Light->active == GE_FALSE) { Light->DynLight = geWorld_AddLight(CCD->World()); Light->active = GE_TRUE; } } else { if(Light->active == GE_TRUE) geWorld_RemoveLight(CCD->World(), Light->DynLight); Light->active = GE_FALSE; } } else { if(Light->active == GE_FALSE) { Light->DynLight = geWorld_AddLight(CCD->World()); Light->active = GE_TRUE; // CCD->ReportError("DSpotLight light added", false); } } if(Light->active == GE_TRUE) { // pass the OriginOffset to SetOrigin // so that the light will stay in the same position relative to the model. Light->origin = Light->OriginOffset; SetOriginOffset(Light->EntityName, Light->BoneName, Light->Model, &(Light->origin)); geWorld_GetLeaf(CCD->World(), &(Light->origin), &Leaf); Pos = Light->origin; if(Light->Rotate) { if(Light->Model) { geXForm3d Xf; geVec3d Tmp; geWorld_GetModelXForm(CCD->World(), Light->Model, &Xf); geXForm3d_GetEulerAngles(&Xf, &Tmp); geVec3d_Add(&(Light->RealAngle), &Tmp, &(Light->angles)); geVec3d_Scale(&(Light->angles), GE_180OVERPI, &(Light->angles)); } else if(!EffectC_IsStringNull(Light->EntityName)) { // changed QD 07/15/06 /* geXForm3d BoneXForm; geActor *theActor; theActor = GetEntityActor(Light->EntityName); if(!EffectC_IsStringNull(Light->BoneName)) { if(geActor_GetBoneTransform(theActor, Light->BoneName, &BoneXForm) != GE_TRUE) continue; // No such bone } else { if(geActor_GetBoneTransform(theActor, RootBoneName(theActor), &BoneXForm) != GE_TRUE) continue; // No such bone } geXForm3d_RotateY(&BoneXForm, Light->RealAngle.Y); geXForm3d_GetEulerAngles(&BoneXForm, &(Light->angles)); Light->angles.Z += Light->RealAngle.Z; */ SetAngle(Light->EntityName, Light->BoneName, &(Light->angles)); if(Light->RealAngle.X || Light->RealAngle.Y || Light->RealAngle.Z) { geXForm3d XForm, BoneXForm; geXForm3d_SetZRotation(&XForm, Light->RealAngle.Z); geXForm3d_RotateX(&XForm, Light->RealAngle.X); geXForm3d_RotateY(&XForm, Light->RealAngle.Y); geXForm3d_SetZRotation(&BoneXForm, Light->angles.Z); geXForm3d_RotateX(&BoneXForm, Light->angles.X); geXForm3d_RotateY(&BoneXForm, Light->angles.Y); geXForm3d_Multiply(&BoneXForm, &XForm, &XForm); geXForm3d_GetEulerAngles(&XForm, &(Light->angles)); } // end change QD 07/15/06 // convert to degrees geVec3d_Scale(&(Light->angles), GE_180OVERPI, &(Light->angles)); } } Percentage = Light->LastTime / Light->RadiusSpeed; Index = (int)(Percentage * Light->NumFunctionValues); if(Light->InterpolateValues && Index < Light->NumFunctionValues - 1) { geFloat Remainder; geFloat InterpolationPercentage; int DeltaValue; geFloat Value; Remainder = (geFloat)fmod(Light->LastTime, Light->IntervalWidth); InterpolationPercentage = Remainder / Light->IntervalWidth; DeltaValue = Light->RadiusFunction[Index + 1] - Light->RadiusFunction[Index]; Value = Light->RadiusFunction[Index] + DeltaValue * InterpolationPercentage; Percentage = ((geFloat)(Value - 'a')) / ((geFloat)('z' - 'a')); } else Percentage = ((geFloat)(Light->RadiusFunction[Index] - 'a')) / ((geFloat)('z' - 'a')); Radius = Percentage * (Light->MaxRadius - Light->MinRadius) + Light->MinRadius; // angles in degrees geWorld_SetSpotLightAttributes(CCD->World(), Light->DynLight, &Pos, &(Light->Color), Radius, Light->arc, &(Light->angles), Light->style, Light->CastShadows); Light->LastTime = (geFloat)fmod(Light->LastTime + dwTicks, Light->RadiusSpeed); if(EffectC_IsPointVisible(CCD->World(), CCD->CameraManager()->Camera(), &Pos, Leaf, EFFECTC_CLIP_LEAF ) == GE_FALSE) { geWorld_RemoveLight(CCD->World(), Light->DynLight); Light->active = GE_FALSE; } } } return GE_TRUE; }
Brush *BrushTemplate_CreateCylinder (const BrushTemplate_Cylinder *pTemplate) { double CurrentXDiameter, CurrentZDiameter; double DeltaXDiameter, DeltaZDiameter; double CurrentXOffset, CurrentZOffset; double DeltaXOffset, DeltaZOffset, sqrcheck; double EllipseZ; int NumVerticalBands, HBand, VBand; int VertexCount=0; geVec3d *Verts, *TopPoints; geVec3d Current, Final, Delta; geXForm3d YRotation; FaceList *fl; Face *f; Brush *b; NumVerticalBands = (int)(pTemplate->VerticalStripes); if (NumVerticalBands < 3) { return NULL; } Verts =(geVec3d *)geRam_Allocate(sizeof(geVec3d)*NumVerticalBands * 2); TopPoints =(geVec3d *)geRam_Allocate(sizeof(geVec3d)*NumVerticalBands); fl =FaceList_Create(NumVerticalBands + 2); if(!Verts || !TopPoints ||!fl) { return NULL; } geXForm3d_SetIdentity(&YRotation); geXForm3d_SetYRotation(&YRotation, (M_PI * 2.0f)/(geFloat)NumVerticalBands); // Start with the top of cylinder CurrentXDiameter =pTemplate->TopXSize; CurrentZDiameter =pTemplate->TopZSize; DeltaXDiameter =(pTemplate->BotXSize - pTemplate->TopXSize); DeltaZDiameter =(pTemplate->BotZSize - pTemplate->TopZSize); // Get the offset amounts CurrentXOffset =pTemplate->TopXOffset; CurrentZOffset =pTemplate->TopZOffset; DeltaXOffset =(pTemplate->BotXOffset - pTemplate->TopXOffset); DeltaZOffset =(pTemplate->BotZOffset - pTemplate->TopZOffset); // Get the band positions and deltas geVec3d_Set(&Current, (float)(pTemplate->TopXSize / 2), (float)(pTemplate->YSize / 2), 0.0); geVec3d_Set(&Delta, (float)((pTemplate->BotXSize / 2) - Current.X), (float)(-(pTemplate->YSize/2) - Current.Y), 0.0); for(HBand = 0;HBand <= 1;HBand++) { Final = Current; for(VBand = 0;VBand < NumVerticalBands;VBand++) { // Get the elliptical Z value // (x^2/a^2) + (z^2/b^2) = 1 // z = sqrt(b^2(1 - x^2/a^2)) sqrcheck=( ((CurrentZDiameter/2)*(CurrentZDiameter/2)) * (1.0 - (Final.X*Final.X) / ( (CurrentXDiameter/2)*(CurrentXDiameter/2) )) ); if(sqrcheck <0.0) sqrcheck=0.0; EllipseZ = sqrt(sqrcheck); // Check if we need to negate this thing if(VBand > (NumVerticalBands/2)) EllipseZ = -EllipseZ; geVec3d_Set ( &Verts[VertexCount], (float)(Final.X + CurrentXOffset), Final.Y, (float)(EllipseZ + CurrentZOffset) ); VertexCount++; // Rotate the point around the Y to get the next vertical band geXForm3d_Rotate(&YRotation, &Final, &Final); } CurrentXDiameter +=DeltaXDiameter; CurrentZDiameter +=DeltaZDiameter; CurrentXOffset +=DeltaXOffset; CurrentZOffset +=DeltaZOffset; geVec3d_Add(&Current, &Delta, &Current); } for(VBand=0;VBand < NumVerticalBands;VBand++) { TopPoints[VBand] =Verts[VBand]; } f =Face_Create(NumVerticalBands, TopPoints, 0); if(f) { if(pTemplate->Solid > 1) { Face_SetFixedHull(f, GE_TRUE); } FaceList_AddFace(fl, f); } for(VBand=NumVerticalBands-1, HBand=0;VBand >=0;VBand--, HBand++) { TopPoints[HBand] =Verts[VBand + NumVerticalBands]; } f =Face_Create(NumVerticalBands, TopPoints, 0); if(f) { if(pTemplate->Solid > 1) { Face_SetFixedHull(f, GE_TRUE); } FaceList_AddFace(fl, f); } // Generate the polygons for(HBand = 0;HBand < 1;HBand++) { for(VBand = 0;VBand < NumVerticalBands;VBand++) { TopPoints[3] =Verts[(HBand * NumVerticalBands) + VBand]; TopPoints[2] =Verts[(HBand * NumVerticalBands) + ((VBand + 1) % NumVerticalBands)]; TopPoints[1] =Verts[((HBand + 1) * NumVerticalBands) + ((VBand + 1) % NumVerticalBands)]; TopPoints[0] =Verts[((HBand + 1) * NumVerticalBands) + VBand]; f =Face_Create(4, TopPoints, 0); if(f) { FaceList_AddFace(fl, f); } } } geRam_Free(Verts); geRam_Free(TopPoints); if(!pTemplate->Solid) { b =Brush_Create(BRUSH_LEAF, fl, NULL); if(b) { Brush_SetSubtract(b, pTemplate->TCut); } return b; } else { BrushList *bl =BrushList_Create(); Brush *bh, *bm; b =Brush_Create(BRUSH_LEAF, fl, NULL); if(b) { Brush_SetHollow(b, GE_TRUE); Brush_SetHullSize(b, (float)pTemplate->Thickness); bh =Brush_CreateHollowFromBrush(b); if(bh) { Brush_SetHollowCut(bh, GE_TRUE); BrushList_Append(bl, b); BrushList_Append(bl, bh); bm =Brush_Create(BRUSH_MULTI, NULL, bl); if(bm) { Brush_SetHollow(bm, GE_TRUE); Brush_SetSubtract(bm, pTemplate->TCut); Brush_SetHullSize(bm, (float)pTemplate->Thickness); return bm; } } else { Brush_Destroy(&b); BrushList_Destroy(&bl); } } else { BrushList_Destroy(&bl); } } return NULL; }
/* ------------------------------------------------------------------------------------ */ void ActorParticle_SystemFrame(ActorParticle_System *ps, geFloat DeltaTime) { // the quick fix to the particle no-draw problem ps->psQuantumSeconds = DeltaTime; { ActorParticle *ptcl; ptcl = ps->psParticles; while(ptcl) { ptcl->ptclTime -= ps->psQuantumSeconds; if(ptcl->ptclTime <= 0.0f) { ActorParticle *temp; temp = ptcl->ptclNext; ActorUnlinkParticle(ps, ptcl); ActorDestroyParticle(ps, ptcl); ptcl = temp; continue; } else { // locals geVec3d DeltaPos = {0.0f, 0.0f, 0.0f}; // apply velocity if(ptcl->ptclFlags & PARTICLE_HASVELOCITY) { geVec3d_Scale(&(ptcl->ptclVelocity), ps->psQuantumSeconds, &DeltaPos); } // apply DeltaPos to particle position if(ptcl->ptclFlags & PARTICLE_HASVELOCITY) { geVec3d temppos, temppos1; GE_Collision Collision; CCD->ActorManager()->GetPosition(ptcl->Actor, &temppos); geVec3d_Add(&temppos, &DeltaPos, &temppos1); if(ptcl->Bounce) { float totalTravelled = 1.0f; // keeps track of fraction of path travelled (1.0=complete) float margin = 0.001f; // margin to be satisfied with (1.0 - margin == 1.0) int loopCounter = 0; // safety valve for endless collisions in tight corners const int maxLoops = 10; while(CCD->Collision()->CheckForWCollision(&ptcl->theBox.Min, &ptcl->theBox.Max, temppos, temppos1, &Collision, ptcl->Actor)) { float ratio; float elasticity = 1.3f; float friction = 0.9f; // loses (1 minus friction) of speed CollisionCalcRatio(Collision, temppos, temppos1, &ratio); CollisionCalcImpactPoint(Collision, temppos, temppos1, 1.0f, ratio, &temppos1); CollisionCalcVelocityImpact(Collision, ptcl->ptclVelocity, elasticity, friction, &(ptcl->ptclVelocity)); if(ratio >= 0) totalTravelled += (1.0f - totalTravelled) * ratio; if(totalTravelled >= 1.0f - margin) break; if(++loopCounter >= maxLoops) // safety check break; } } else { if(CCD->Collision()->CheckForWCollision(&ptcl->theBox.Min, &ptcl->theBox.Max, temppos, temppos1, &Collision, ptcl->Actor)) { ActorParticle *temp; temp = ptcl->ptclNext; ActorUnlinkParticle(ps, ptcl); ActorDestroyParticle(ps, ptcl); ptcl = temp; continue; } } CCD->ActorManager()->Position(ptcl->Actor, temppos1); } } geVec3d Rotation, Amount; Amount.X = ptcl->RotationSpeed.X*ps->psQuantumSeconds; Amount.Y = ptcl->RotationSpeed.Y*ps->psQuantumSeconds; Amount.Z = ptcl->RotationSpeed.Z*ps->psQuantumSeconds; CCD->ActorManager()->GetRotate(ptcl->Actor, &Rotation); Rotation.X += Amount.X; Rotation.Y += Amount.Y; Rotation.Z += Amount.Z; CCD->ActorManager()->Rotate(ptcl->Actor, Rotation); // set actor alpha ptcl->Alpha -= (ptcl->AlphaRate*ps->psQuantumSeconds); if(ptcl->Alpha < 0.0f) ptcl->Alpha = 0.0f; else if(ptcl->Alpha > 255.0f) ptcl->Alpha = 255.0f; CCD->ActorManager()->SetAlpha(ptcl->Actor, ptcl->Alpha); ptcl = ptcl->ptclNext; } DeltaTime -= QUANTUMSIZE; } ps->psLastTime += DeltaTime; }
/* ------------------------------------------------------------------------------------ */ void Particle_SystemFrame(Particle_System *ps, geFloat DeltaTime) { geVec3d AnchorDelta; // the quick fix to the particle no-draw problem ps->psQuantumSeconds = DeltaTime; { Particle *ptcl; ptcl = ps->psParticles; while(ptcl) { ptcl->ptclTime -= ps->psQuantumSeconds; if(ptcl->ptclTime <= 0.0f) { Particle *temp; temp = ptcl->ptclNext; UnlinkParticle(ps, ptcl); DestroyParticle(ps, ptcl); ptcl = temp; continue; } else { // locals geVec3d DeltaPos = {0.0f, 0.0f, 0.0f}; // apply velocity if(ptcl->ptclFlags & PARTICLE_HASVELOCITY) { geVec3d_Scale(&(ptcl->ptclVelocity), ps->psQuantumSeconds, &DeltaPos); } // apply gravity if(ptcl->ptclFlags & PARTICLE_HASGRAVITY) { // locals geVec3d Gravity; // make gravity vector geVec3d_Scale(&(ptcl->Gravity), ps->psQuantumSeconds, &Gravity); // apply gravity to built in velocity and DeltaPos geVec3d_Add(&(ptcl->ptclVelocity), &Gravity, &(ptcl->ptclVelocity)); geVec3d_Add(&DeltaPos, &Gravity, &DeltaPos); } //apply wind if(ptcl->ptclFlags & PARTICLE_HASWIND) { geVec3d Wind = CCD->Player()->GetWind(); //make wind vector geVec3d_Scale(&Wind, ps->psQuantumSeconds, &Wind); //add wind to delta pos geVec3d_Add(&DeltaPos, &Wind, &DeltaPos); } // apply DeltaPos to particle position if((ptcl->ptclFlags & PARTICLE_HASVELOCITY) || (ptcl->ptclFlags & PARTICLE_HASGRAVITY) || (ptcl->ptclFlags & PARTICLE_HASWIND)) { geVec3d temppos, temppos1; GE_Collision Collision; geVec3d_Copy((geVec3d*)&(ptcl->ptclVertex.X), &temppos); geVec3d_Add(&temppos, &DeltaPos, &temppos1); if(ptcl->Bounce) { float totalTravelled = 1.0f;// keeps track of fraction of path travelled (1.0=complete) float margin = 0.001f; // margin to be satisfied with (1.0 - margin == 1.0) int loopCounter = 0; // safety valve for endless collisions in tight corners const int maxLoops = 10; while(geWorld_Collision(CCD->World(), NULL, NULL, &temppos, &temppos1, GE_VISIBLE_CONTENTS, GE_COLLIDE_ALL, 0, NULL, NULL, &Collision)) { float ratio ; float elasticity = 1.3f ; float friction = 0.9f ; // loses (1 minus friction) of speed CollisionCalcRatio(Collision, temppos, temppos1, &ratio); CollisionCalcImpactPoint(Collision, temppos, temppos1, 1.0f, ratio, &temppos1); CollisionCalcVelocityImpact(Collision, ptcl->ptclVelocity, elasticity, friction, &(ptcl->ptclVelocity)); if(ratio >= 0) totalTravelled += (1.0f - totalTravelled) * ratio ; if(totalTravelled >= 1.0f - margin) break ; if(++loopCounter >= maxLoops) // safety check break ; } } else { if(geWorld_Collision(CCD->World(), NULL, NULL, &temppos, &temppos1, GE_VISIBLE_CONTENTS, GE_COLLIDE_ALL, 0, NULL, NULL, &Collision)) { Particle *temp; temp = ptcl->ptclNext; UnlinkParticle(ps, ptcl); DestroyParticle(ps, ptcl); ptcl = temp; continue; } } geVec3d_Copy(&temppos1, (geVec3d *)&(ptcl->ptclVertex.X)); } // make the particle follow its anchor point if it has one if(ptcl->AnchorPoint != (const geVec3d*)NULL) { geVec3d_Subtract(ptcl->AnchorPoint, &(ptcl->CurrentAnchorPoint), &AnchorDelta); geVec3d_Add((geVec3d*)&(ptcl->ptclVertex.X), &AnchorDelta, (geVec3d*)&(ptcl->ptclVertex.X)); geVec3d_Copy(ptcl->AnchorPoint, &(ptcl->CurrentAnchorPoint)); } } #ifndef POLYQ // set particle alpha ptcl->ptclVertex.a = ptcl->Alpha * (ptcl->ptclTime / ptcl->ptclTotalTime); geWorld_AddPolyOnce(ps->psWorld, &(ptcl->ptclVertex), 1, ptcl->ptclTexture, GE_TEXTURED_POINT, PARTICLE_RENDERSTYLE, ptcl->Scale); #else // set particle alpha ptcl->ptclVertex.a = ptcl->Alpha * (ptcl->ptclTime / ptcl->ptclTotalTime); if(ptcl->ptclPoly) gePoly_SetLVertex(ptcl->ptclPoly, 0, &(ptcl->ptclVertex)); #endif ptcl = ptcl->ptclNext; } DeltaTime -= QUANTUMSIZE; } ps->psLastTime += DeltaTime; }