geBoolean TestEdge_r(geFloat Start, geFloat End, int32 p1, int32 p2, int32 StartVert) { int32 j, k; geFloat Dist; geVec3d Delta; geVec3d Exact; geVec3d Off; geFloat Error; geVec3d p; if (p1 == p2) { //GHook.Printf("TestEdge_r: Degenerate Edge.\n"); return GE_TRUE; // degenerate edge } for (k=StartVert ; k<NumEdgeVerts ; k++) { j = EdgeVerts[k]; if (j==p1 || j == p2) continue; p = WeldedVerts[j]; geVec3d_Subtract(&p, &EdgeStart, &Delta); Dist = geVec3d_DotProduct(&Delta, &EdgeDir); if (Dist <= Start || Dist >= End) continue; geVec3d_AddScaled(&EdgeStart, &EdgeDir, Dist, &Exact); geVec3d_Subtract(&p, &Exact, &Off); Error = geVec3d_Length(&Off); if (fabs(Error) > OFF_EPSILON) continue; // break the edge NumTJunctions++; TestEdge_r (Start, Dist, p1, j, k+1); TestEdge_r (Dist, End, j, p2, k+1); return GE_TRUE; } if (NumTempIndexVerts >= MAX_TEMP_INDEX_VERTS) { GHook.Error("Max Temp Index Verts.\n"); return GE_FALSE; } TempIndexVerts[NumTempIndexVerts] = p1; NumTempIndexVerts++; return GE_TRUE; }
//================================================================================ // CalcPortalInfo //================================================================================ geBoolean CalcPortalInfo(VIS_Portal *Portal) { geFloat BestDist, Dist; GBSP_Poly *Poly; geVec3d Vect; int32 i; Poly = Portal->Poly; PolyCenter(Poly, &Portal->Center); BestDist = 0.0f; for (i=0; i< Poly->NumVerts; i++) { geVec3d_Subtract(&Poly->Verts[i], &Portal->Center, &Vect); Dist = geVec3d_Length(&Vect); if (Dist > BestDist) BestDist = Dist; } Portal->Radius = BestDist; return GE_TRUE; }
void GENESISCC geExtBox_GetScaling( const geExtBox *B, geVec3d *pScale ) { assert (geExtBox_IsValid (B) != GE_FALSE ); assert (pScale != NULL); geVec3d_Subtract( &(B->Max), &(B->Min), pScale ); }
//===================================================================================== // FixFaceTJunctions //===================================================================================== geBoolean FixFaceTJunctions(GBSP_Node *Node, GBSP_Face *Face) { int32 i, P1, P2; int32 Start[MAX_TEMP_INDEX_VERTS]; int32 Count[MAX_TEMP_INDEX_VERTS]; geVec3d Edge2; geFloat Len; int32 Base; NumTempIndexVerts = 0; for (i=0; i< Face->NumIndexVerts; i++) { P1 = Face->IndexVerts[i]; P2 = Face->IndexVerts[(i+1)%Face->NumIndexVerts]; EdgeStart = WeldedVerts[P1]; Edge2 = WeldedVerts[P2]; FindEdgeVerts(&EdgeStart, &Edge2); geVec3d_Subtract(&Edge2, &EdgeStart, &EdgeDir); Len = geVec3d_Normalize(&EdgeDir); Start[i] = NumTempIndexVerts; TestEdge_r(0.0f, Len, P1, P2, 0); Count[i] = NumTempIndexVerts - Start[i]; } if (NumTempIndexVerts < 3) { Face->NumIndexVerts = 0; //GHook.Printf("FixFaceTJunctions: Face collapsed.\n"); return GE_TRUE; } for (i=0 ; i<Face->NumIndexVerts; i++) { if (Count[i] == 1 && Count[(i+Face->NumIndexVerts-1)%Face->NumIndexVerts] == 1) break; } if (i == Face->NumIndexVerts) { Base = 0; } else { // rotate the vertex order Base = Start[i]; } if (!FinalizeFace(Face, Base)) return GE_FALSE; return GE_TRUE; }
/* ------------------------------------------------------------------------------------ */ int CPathFollower::GetDirectionVector(const geVec3d &LookFrom, const geVec3d &LookAt, geVec3d *theDirectionVector) { geVec3d_Subtract(&LookAt, &LookFrom, theDirectionVector); geVec3d_Normalize(theDirectionVector); return RGF_SUCCESS; }
/* ------------------------------------------------------------------------------------ */ CDSpotLight::CDSpotLight() { geEntity_EntitySet *pSet; geEntity *pEntity; pSet = geWorld_GetEntitySet(CCD->World(), "DSpotLight"); if(!pSet) return; // None there. // Ok, we have dynamic lights somewhere. Dig through 'em all. for(pEntity=geEntity_EntitySetGetNextEntity(pSet, NULL); pEntity; pEntity=geEntity_EntitySetGetNextEntity(pSet, pEntity)) { DSpotLight *pLight = (DSpotLight*)geEntity_GetUserData(pEntity); pLight->RadiusSpeed *= 1000.0f; // From SECONDS to MILLISECONDS if(EffectC_IsStringNull(pLight->szEntityName)) { char szName[128]; geEntity_GetName(pEntity, szName, 128); pLight->szEntityName = szName; } // Ok, put this entity into the Global Entity Registry CCD->EntityRegistry()->AddEntity(pLight->szEntityName, "DSpotLight"); // "negative light" shadow if(pLight->Shadow) { pLight->Color.r = -pLight->Color.r; pLight->Color.g = -pLight->Color.g; pLight->Color.b = -pLight->Color.b; } pLight->OriginOffset = pLight->origin; geVec3d_Scale(&(pLight->angles), GE_PIOVER180, &(pLight->RealAngle)); if(pLight->Model) { geVec3d ModelOrigin; geWorld_GetModelRotationalCenter(CCD->World(), pLight->Model, &ModelOrigin); geVec3d_Subtract(&(pLight->origin), &ModelOrigin, &(pLight->OriginOffset)); } pLight->active = GE_FALSE; pLight->NumFunctionValues = strlen(pLight->RadiusFunction); if(pLight->NumFunctionValues == 0) { CCD->ReportError("[WARNING] DSpotLight has no RadiusFunction string\n", false); continue; } pLight->IntervalWidth = pLight->RadiusSpeed / (geFloat)pLight->NumFunctionValues; } }
//==================================================================================== // gePlane_SetFromVerts //==================================================================================== void gePlane_SetFromVerts(GFX_Plane *Plane, const geVec3d *V1, const geVec3d *V2, const geVec3d *V3) { geVec3d Vect1, Vect2; // Get the 2 vectors to derive the normal geVec3d_Subtract(V1, V2, &Vect1); geVec3d_Subtract(V3, V2, &Vect2); // The normal is the cross between these 2 vectors geVec3d_CrossProduct(&Vect1, &Vect2, &Plane->Normal); geVec3d_Normalize(&Plane->Normal); // Get the planes distance from the origin, by projecting a vert on the plane // along the plane normal, to the origin... Plane->Dist = geVec3d_DotProduct(V1, &Plane->Normal); // Finally, get the plane type Plane->Type = PLANE_ANY; }
/* ------------------------------------------------------------------------------------ */ void CAudioStream::Tick(geFloat dwTicks) { geEntity_EntitySet *pSet; geEntity *pEntity; geVec3d PlayerPos; if(m_nStreamerCount == 0) return; // No streamers in world, bail early // Now scan for StreamingAudioProxy entities pSet = geWorld_GetEntitySet(CCD->World(), "StreamingAudioProxy"); if(!pSet) return; // Don't waste CPU time. // Clean up any non-playing streams Sweep(); // Ok, go through and see if we need to trigger playback. PlayerPos = CCD->Player()->Position(); // Get player position for(pEntity=geEntity_EntitySetGetNextEntity(pSet, NULL); pEntity; pEntity=geEntity_EntitySetGetNextEntity(pSet, pEntity)) { StreamingAudioProxy *pProxy = (StreamingAudioProxy*)geEntity_GetUserData(pEntity); if(pProxy->bActive == false) continue; // Not active, ignore it // changed QD 12/15/05 //if(geVec3d_DistanceBetween(&pProxy->origin, &PlayerPos) > pProxy->Range) // continue; // Too far away geVec3d temp; geVec3d_Subtract(&pProxy->origin, &PlayerPos, &temp); if(geVec3d_DotProduct(&temp, &temp) > pProxy->Range*pProxy->Range) continue; // Too far away // end change // Check to see if we've waited long enough before triggering this // ..from the last time. if(CCD->FreeRunningCounter() < (DWORD)(pProxy->LastTimeTriggered + (pProxy->SleepTime*1000))) continue; // No more often than every <n> seconds. // Ok, we're close enough and it's time. Trigger it! Play(pProxy->szStreamFile, pProxy->bLoops, true); // If this is a one-shot, kill any hope of reactivation. if(pProxy->bOneShot == GE_TRUE) pProxy->bActive = false; // Turn it off! } return; }
/* ------------------------------------------------------------------------------------ */ CDynalite::CDynalite() { geEntity_EntitySet *pSet; geEntity *pEntity; pSet = geWorld_GetEntitySet(CCD->World(), "DynamicLight"); if(!pSet) return; // None there. // Ok, we have dynamic lights somewhere. Dig through 'em all. for(pEntity=geEntity_EntitySetGetNextEntity(pSet, NULL); pEntity; pEntity=geEntity_EntitySetGetNextEntity(pSet, pEntity)) { DynamicLight *pLight = (DynamicLight*)geEntity_GetUserData(pEntity); pLight->RadiusSpeed *= 1000.0f; // From SECONDS to MILLISECONDS if(EffectC_IsStringNull(pLight->szEntityName)) { char szName[128]; geEntity_GetName(pEntity, szName, 128); pLight->szEntityName = szName; } // Ok, put this entity into the Global Entity Registry CCD->EntityRegistry()->AddEntity(pLight->szEntityName, "DynamicLight"); //MOD010124 - Added next if block to calculate the Origin offset. We pass it to // SetOrigin later in the tick function so that the light will stay in // the same position relative to the model. The offset is just the // difference of the Dynamic Light's origin vector and the Model's // origin vector. pLight->OriginOffset = pLight->origin; if(pLight->Model) { geVec3d ModelOrigin; geWorld_GetModelRotationalCenter(CCD->World(), pLight->Model, &ModelOrigin); geVec3d_Subtract(&(pLight->origin), &ModelOrigin, &(pLight->OriginOffset)); } pLight->active = GE_FALSE; pLight->NumFunctionValues = strlen(pLight->RadiusFunction); if(pLight->NumFunctionValues == 0) { CCD->ReportError("[WARNING] DynamicLight has no RadiusFunction string\n", false); continue; } pLight->IntervalWidth = pLight->RadiusSpeed / (geFloat)pLight->NumFunctionValues; } return; }
/* ------------------------------------------------------------------------------------ */ CRain::CRain() { geEntity_EntitySet *pSet; geEntity *pEntity; pSet = geWorld_GetEntitySet(CCD->World(), "Rain"); if(!pSet) return; for(pEntity=geEntity_EntitySetGetNextEntity(pSet, NULL); pEntity; pEntity=geEntity_EntitySetGetNextEntity(pSet, pEntity)) { Rain *R = (Rain*)geEntity_GetUserData(pEntity); if(EffectC_IsStringNull(R->szEntityName)) { char szName[128]; geEntity_GetName(pEntity, szName, 128); R->szEntityName = szName; } // Ok, put this entity into the Global Entity Registry CCD->EntityRegistry()->AddEntity(R->szEntityName, "Rain"); R->OriginOffset = R->origin; if(R->Model) { geVec3d ModelOrigin; geWorld_GetModelRotationalCenter(CCD->World(), R->Model, &ModelOrigin); geVec3d_Subtract(&(R->origin), &ModelOrigin, &(R->OriginOffset)); } // calculate number of Sprays needed R->EffectCount = (int)R->Radius / RAINM_RADIUSTOEFFECTRATIO; // create dynamic array to hold effect indexes R->EffectList = (int*)malloc(sizeof(int)*R->EffectCount); // make sure data is valid if(R->Severity < 0.0f) R->Severity = 0.0f; else if(R->Severity > 1.0f) R->Severity = 1.0f; if(R->DropLife <= 0.0f) R->DropLife = 0.1f; R->active = GE_FALSE; TPool_Bitmap("rain.bmp", "a_rain.bmp", R->BmpName, R->AlphaName); } }
void GENESISCC geExtBox_SetTranslation( geExtBox *B, const geVec3d *pCenter ) { geVec3d Center,Translation; assert (geExtBox_IsValid (B) != GE_FALSE); assert (pCenter != NULL); assert( geVec3d_IsValid(pCenter) != GE_FALSE ); geExtBox_GetTranslation( B, &Center ); geVec3d_Subtract( pCenter, &Center, &Translation); geExtBox_Translate( B, Translation.X, Translation.Y, Translation.Z ); }
/* ------------------------------------------------------------------------------------ */ int CPathFollower::Tick(geFloat dwTicks) { geEntity_EntitySet *pSet; geEntity *pEntity; geVec3d PlayerPos; // Ok, check to see if there are path followers in this world pSet = geWorld_GetEntitySet(CCD->World(), "PathFollower"); if(!pSet) return RGF_FAILURE; // No path followers PlayerPos = CCD->Player()->Position(); // Ok, dig through 'em all. for(pEntity=geEntity_EntitySetGetNextEntity(pSet, NULL); pEntity; pEntity=geEntity_EntitySetGetNextEntity(pSet, pEntity)) { PathFollower *pFollower = (PathFollower*)geEntity_GetUserData(pEntity); if(pFollower->bReady == GE_FALSE) continue; // Disabled entity if(pFollower->bMoving == GE_TRUE) continue; // Already moving, don't re-trigger if(pFollower->RangeTrigger == 0.0f) continue; // Not range trigger, keep moving // changed QD 12/15/05 //if(geVec3d_DistanceBetween(&(pFollower->origin), &PlayerPos) > pFollower->RangeTrigger) // continue; // Too far away geVec3d temp; geVec3d_Subtract(&(pFollower->origin), &PlayerPos, &temp); if(geVec3d_DotProduct(&temp, &temp) > pFollower->RangeTrigger*pFollower->RangeTrigger) continue; // end change // In range, trigger it! pFollower->bTriggered = GE_TRUE; // Triggered... pFollower->bMoving = GE_TRUE; // We're moving! pFollower->TimeInMotion = 0.0f; // Clear time in motion pFollower->LastMotionTick = CCD->FreeRunningCounter_F(); // Prime the time } return RGF_SUCCESS; }
//================================================================================ // Frustum_SetFromPoly // Create a frustum looking through a poly (from the origin) //================================================================================ geBoolean Frustum_SetFromPoly(Frustum_Info *Info, geVec3d *Verts, int32 NumVerts, geBoolean Flip) { int32 NextVert; geVec3d *pVert1, *pVert2, Vect; GFX_Plane *Planes; int32 i; if (NumVerts >= MAX_FCP) return GE_FALSE; // Too many planes!!! Planes = Info->Planes; Info->NumPlanes = 0; for (i=0; i< NumVerts; i++) { NextVert = ((i+1) < NumVerts) ? (i+1) : 0; pVert1 = &Verts[i]; pVert2 = &Verts[NextVert]; if (geVec3d_Compare(pVert1, pVert2, 0.1f)) // Coplanar edge... continue; // Coplanar edges will cause a plane to be duplicated, skip it or it will screw up // the clipping stage of the frustum created from this poly... geVec3d_Subtract(pVert1, pVert2, &Vect); if (Flip) geVec3d_CrossProduct(pVert2, &Vect, &Planes->Normal); else geVec3d_CrossProduct(&Vect, pVert2, &Planes->Normal); geVec3d_Normalize(&Planes->Normal); Planes->Dist = 0.0f; Planes->Type = PLANE_ANY; Planes++; Info->NumPlanes++; } // Get BBox info for fast BBox rejection against frustum... SetUpFrustumBBox(Info); return GE_TRUE; }
/* ------------------------------------------------------------------------------------ */ int CPathFollower::GetRotationToFacePoint(const geVec3d &LookFrom, const geVec3d &LookAt, geVec3d *LookRotation) { geFloat x, l; geVec3d_Subtract(&LookAt, &LookFrom, LookRotation); l = geVec3d_Length(LookRotation); // protect from Div by Zero if(l > 0.0f) { x = LookRotation->X; // changed QD 12/15/05 // LookRotation->X = (geFloat)(GE_PI*0.5f) - (geFloat)acos(LookRotation->Y / l); LookRotation->X = GE_PIOVER2 - (geFloat)acos(LookRotation->Y / l); LookRotation->Y = (geFloat)atan2(x, LookRotation->Z) + GE_PI; LookRotation->Z = 0.0f; // roll is zero - always!!? } return RGF_SUCCESS; }
/* ------------------------------------------------------------------------------------ */ 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; }
/* ------------------------------------------------------------------------------------ */ 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; }
geBoolean GENESISCC geExtBox_RayCollision( const geExtBox *B, const geVec3d *Start, const geVec3d *End, geFloat *T, geVec3d *Normal ) { // only detects rays going 'in' to the box geFloat t; geVec3d Delta; geVec3d LocalNormal; geFloat LocalT; assert( B != NULL ); assert( Start != NULL ); assert( End != NULL ); assert (geVec3d_IsValid( Start )!= GE_FALSE); assert (geVec3d_IsValid( End )!= GE_FALSE); assert (geExtBox_IsValid( B )!= GE_FALSE ); geVec3d_Subtract(End,Start,&Delta); if (Normal == NULL) Normal = &LocalNormal; if (T == NULL) T = &LocalT; // test x end of box, facing away from ray direction. if (Delta.X > 0.0f) { if ( (Start->X <= B->Min.X) && (B->Min.X <= End->X) && (geExtBox_XFaceDist( Start ,&Delta, B, &t, B->Min.X ) != GE_FALSE) ) { geVec3d_Set( Normal, -1.0f, 0.0f, 0.0f ); *T = t; return GE_TRUE; } } else if (Delta.X < 0.0f) { if ( (End->X <= B->Max.X) && (B->Max.X <= Start->X) && (geExtBox_XFaceDist( Start ,&Delta, B, &t, B->Max.X ) != GE_FALSE) ) { geVec3d_Set( Normal, 1.0f, 0.0f, 0.0f ); *T = t; return GE_TRUE; } } // test y end of box, facing away from ray direction. if (Delta.Y > 0.0f) { if ( (Start->Y <= B->Min.Y) && (B->Min.Y <= End->Y) && (geExtBox_YFaceDist( Start ,&Delta, B, &t, B->Min.Y ) != GE_FALSE) ) { geVec3d_Set( Normal, 0.0f, -1.0f, 0.0f ); *T = t; return GE_TRUE; } } else if (Delta.Y < 0.0f) { if ( (End->Y <= B->Max.Y) && (B->Max.Y <= Start->Y) && (geExtBox_YFaceDist( Start ,&Delta, B, &t, B->Max.Y ) != GE_FALSE) ) { geVec3d_Set( Normal, 0.0f, 1.0f, 0.0f ); *T = t; return GE_TRUE; } } // test z end of box, facing away from ray direction. if (Delta.Z > 0.0f) { if ( (Start->Z <= B->Min.Z) && (B->Min.Z <= End->Z) && (geExtBox_ZFaceDist( Start ,&Delta, B, &t, B->Min.Z ) != GE_FALSE) ) { geVec3d_Set( Normal, 0.0f, 0.0f, -1.0f ); *T = t; return GE_TRUE; } } else if (Delta.Z < 0.0f) { if ( (End->Z <= B->Max.Z) && (B->Max.Z <= Start->Z) && (geExtBox_ZFaceDist( Start ,&Delta, B, &t, B->Max.Z ) != GE_FALSE) ) { geVec3d_Set( Normal, 0.0f, 0.0f, 1.0f ); *T = t; return GE_TRUE; } } return GE_FALSE; }
/* ------------------------------------------------------------------------------------ */ void CCameraManager::DoIsoTracking() { geXForm3d theViewPoint; geVec3d Pos; GE_Collision Collision; geVec3d Front, Back; geVec3d Direction; geFloat CurrentDistance; geExtBox ActorExtBox; geFloat ActorScale; geVec3d Orient; geFloat x; 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); ActorRotation.X = 0.0f; // changed QD 12/15/05 //geXForm3d_SetIdentity(&theViewPoint); //geXForm3d_RotateZ(&theViewPoint, CameraOffsetRotation.Z); geXForm3d_SetZRotation(&theViewPoint, CameraOffsetRotation.Z); // end change geXForm3d_RotateX(&theViewPoint, CameraOffsetRotation.X+GE_PIOVER180*(m_cameraX)); geXForm3d_RotateY(&theViewPoint, 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(IsoCollFlag) { 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 if(CCD->Meshes()->CollisionCheck(&CameraExtBox.Min, &CameraExtBox.Max, Front, Back, &Collision)) { geFloat CurrentDistance2 = geVec3d_DistanceBetween(&Collision.Impact, &Front); 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; if(IsoCollFlag) { 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 = GE_PI*0.5f - (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; }
/* ------------------------------------------------------------------------------------ */ int CCameraManager::RenderView() { geXForm3d theViewPoint; // changed QD 12/15/05 //geXForm3d_SetIdentity(&theViewPoint); // Clear the matrix //geXForm3d_RotateZ(&theViewPoint, Rotation.Z); // Rotate then translate geXForm3d_SetZRotation(&theViewPoint, Rotation.Z); // end change geXForm3d_RotateX(&theViewPoint, Rotation.X); geXForm3d_RotateY(&theViewPoint, Rotation.Y); geXForm3d_Translate(&theViewPoint, Translation.X+shakex, Translation.Y+shakey, Translation.Z); // changed RF063 GE_Contents ZoneContents; geExtBox ExtBox; geVec3d Direction, Pos; GE_LVertex Vertex; ExtBox.Min.X = ExtBox.Min.Z = -1.0f; ExtBox.Min.Y = 0.0f; ExtBox.Max.Y = 1.0f; ExtBox.Max.X = ExtBox.Max.Z = 1.0f; if(CCD->Collision()->GetContentsOf(Translation, &ExtBox, &ZoneContents) == RGF_SUCCESS) //if(geWorld_GetContents(CCD->World(), &Translation, &ExtBox.Min, //&ExtBox.Max, GE_COLLIDE_MODELS, 0, NULL, NULL, &ZoneContents) == GE_TRUE) { Liquid * LQ = CCD->Liquids()->IsLiquid(ZoneContents.Model); if(LQ) { geXForm3d_GetIn(&theViewPoint, &Direction); geVec3d_AddScaled(&Translation, &Direction, OverlayDist, &Pos); Vertex.r = LQ->TintColor.r; Vertex.g = LQ->TintColor.g; Vertex.b = LQ->TintColor.b; Vertex.a = LQ->Transparency; Vertex.u = 0.0f; Vertex.v = 0.0f; Vertex.X = Pos.X; Vertex.Y = Pos.Y; Vertex.Z = Pos.Z; geWorld_AddPolyOnce(CCD->World(), &Vertex, 1, LQ->Texture, GE_TEXTURED_POINT , GE_RENDER_DO_NOT_OCCLUDE_SELF, 2.0f ); } // changed RF064 else { Overlay * OL = CCD->Overlays()->IsOverlay(ZoneContents.Model); if(OL) { geXForm3d_GetIn(&theViewPoint, &Direction); geVec3d_AddScaled(&Translation, &Direction, OverlayDist, &Pos); Vertex.r = OL->TintColor.r; Vertex.g = OL->TintColor.g; Vertex.b = OL->TintColor.b; Vertex.a = OL->Transparency; Vertex.u = 0.0f; Vertex.v = 0.0f; Vertex.X = Pos.X; Vertex.Y = Pos.Y; Vertex.Z = Pos.Z; geWorld_AddPolyOnce(CCD->World(), &Vertex, 1, OL->Texture, GE_TEXTURED_POINT , GE_RENDER_DO_NOT_OCCLUDE_SELF, 2.0f); } } // end change RF064 } if(jerk) { geVec3d Direction; geXForm3d_GetIn(&theViewPoint, &Direction); geVec3d_AddScaled(&theViewPoint.Translation, &Direction, -jerkamt, &theViewPoint.Translation); } // end change RF063 // Set up camera attributes just prior to rendering the world. geRect Rect; geCamera_SetWorldSpaceXForm(EngineCamera, &theViewPoint); geCamera_GetClippingRect(EngineCamera, &Rect); geCamera_SetAttributes(EngineCamera, FOV, &Rect); // changed RF064 geVec3d_Subtract(&m_OldXForm.Translation, &theViewPoint.Translation, &m_vMoveDif ); m_bPositionMoved = !geVec3d_IsZero(&m_vMoveDif); if( m_bPositionMoved || m_OldXForm.AX != theViewPoint.AX || m_OldXForm.AY != theViewPoint.AY || m_OldXForm.AZ != theViewPoint.AZ || m_OldXForm.BX != theViewPoint.BX || m_OldXForm.BY != theViewPoint.BY || m_OldXForm.BZ != theViewPoint.BZ || m_OldXForm.CX != theViewPoint.CX || m_OldXForm.CY != theViewPoint.CY || m_OldXForm.CZ != theViewPoint.CZ) { m_bViewChanged = true; m_OldXForm = theViewPoint; } // end change RF064 return RGF_SUCCESS; }
/* ------------------------------------------------------------------------------------ */ int CPathFollower::GetNextPosition(const char *szEntityName, geVec3d *NextPosition, bool YLocked) { geEntity_EntitySet *pSet; geEntity *pEntity; int nResult; geVec3d thePos, temp, DirectionVector; // Ok, check to see if there are path followers in this world pSet = geWorld_GetEntitySet(CCD->World(), "PathFollower"); if(!pSet) return RGF_FAILURE; // No path followers // Ok, dig through 'em all. for(pEntity=geEntity_EntitySetGetNextEntity(pSet, NULL); pEntity; pEntity=geEntity_EntitySetGetNextEntity(pSet, pEntity)) { PathFollower *pFollower = (PathFollower*)geEntity_GetUserData(pEntity); if(strcmp(pFollower->EntityName, szEntityName) != 0) continue; // Keep looking // Ok, it's this entity. Let's set the return position to the // ..current position in case we aren't moving *NextPosition = pFollower->CurrentPosition; // Compute the # of milliseconds since we last moved, then use that // ..to compute the distance we've travelled in that period geFloat nMotionTime = (CCD->FreeRunningCounter_F() - pFollower->LastMotionTick); if(nMotionTime > 100.0f) nMotionTime = 100.0f; // In case of stalls elsewhere geFloat fDistance = nMotionTime * (pFollower->Speed * 0.001f); // / 1000.0f); pFollower->TimeInMotion += nMotionTime; pFollower->LastMotionTick = CCD->FreeRunningCounter_F(); if(pFollower->bMoving == GE_FALSE) return RGF_SUCCESS; // Current position is good if(pFollower->bReady == GE_FALSE) return RGF_SUCCESS; // Disabled, use current position switch(pFollower->CurrentNodeType) { // For both start and waypoints, we're going to compute the new // position the same way (since they're both target-based motion). case RGF_POINT_TYPE_START: case RGF_POINT_TYPE_WAY: // Ok, we're moving. What we need to do is perform a new position // ..computation based on the entities speed on the path and the // ..vector towards the current target, if not a ranged point. First, // ..compute the direction vector towards the current target geVec3d_Subtract(&pFollower->CurrentTarget, &pFollower->CurrentPosition, &DirectionVector); geVec3d_Normalize(&DirectionVector); geVec3d_Scale(&DirectionVector, fDistance, &DirectionVector); // Fine, DirectionVector now contains a displacement from the current // ..position of the bound entity towards the target node. if(YLocked) DirectionVector.Y = 0.0f; // Stomp on Y vector value temp.X = pFollower->CurrentPosition.X + DirectionVector.X; temp.Y = pFollower->CurrentPosition.Y + DirectionVector.Y; temp.Z = pFollower->CurrentPosition.Z + DirectionVector.Z; break; case RGF_POINT_TYPE_RANGED: // Ranged points are somewhat different. We're basically constraining // ..random motion to a sphere (if not YLocked) of space in which the // ..bound entity randomly moves about. What we'll do is randomly // ..pick a target point in the range sphere every <n> seconds and // ..have the entity move towards that point. if(pFollower->TimeInMotion > pFollower->RandomRollTime) { // Compute a new random target in the range sphere. srand(CCD->FreeRunningCounter()); geVec3d RandomPosition; RandomPosition.X = (geFloat)(rand() % (int)pFollower->PointRange); if(rand()%2 == 1) RandomPosition.X = -(RandomPosition.X); RandomPosition.Y = (geFloat)(rand() % (int)pFollower->PointRange); if(rand()%2 == 1) RandomPosition.Y = -(RandomPosition.Y); RandomPosition.Z = (geFloat)(rand() % (int)pFollower->PointRange); if(rand()%2 == 1) RandomPosition.Z = -(RandomPosition.Z); RandomPosition.X += pFollower->PathOrigin.X; RandomPosition.Y += pFollower->PathOrigin.Y; RandomPosition.Z += pFollower->PathOrigin.Z; pFollower->CurrentTarget = RandomPosition; pFollower->TimeInMotion = 0.0f; // Clear re-seek time } // From here on in, the code is identical to the target-seeking // ..computations performed for way an start points. geVec3d_Subtract(&pFollower->CurrentTarget, &pFollower->CurrentPosition, &DirectionVector); geVec3d_Normalize(&DirectionVector); geVec3d_Scale(&DirectionVector, fDistance, &DirectionVector); // Fine, DirectionVector now contains a displacement from the current // ..position of the bound entity towards the target node. if(YLocked) DirectionVector.Y = 0.0f; // Stomp on Y vector value temp.X = pFollower->CurrentPosition.X + DirectionVector.X; temp.Y = pFollower->CurrentPosition.Y + DirectionVector.Y; temp.Z = pFollower->CurrentPosition.Z + DirectionVector.Z; break; } // Ok, we have a new point to move to! Let's do a basic ray // ..collision test so we can first-level cull any motion if(pFollower->CollisionTest == GE_TRUE) { nResult = CCD->Collision()->CheckForCollision(NULL, NULL, pFollower->CurrentPosition, temp); if(nResult) return RGF_SUCCESS; // Don't move, we collided. } // Fine, no collisions. Let's check to see if (a) we're not on a // ..ranged point and (b) if we're within 1 world unit of the target // ..point. If we pass those tests, we will reset the target to the // ..next target point. *NextPosition = temp; // Copy out for use pFollower->CurrentPosition = *NextPosition; if(pFollower->CurrentNodeType == RGF_POINT_TYPE_RANGED) return RGF_SUCCESS; // Done all we need to do, bail this. if(geVec3d_DistanceBetween(&pFollower->CurrentPosition, &pFollower->CurrentTarget) <= pFollower->Speed) { // Move to the NEXT path point, based on our direction if(pFollower->bForward == GE_TRUE) { // Get next pathpoint nResult = CCD->PathDatabase()->NextPoint(pFollower->PathHandle, &thePos); if(nResult == RGF_NO_NEXT) { // No next point is END OF PATH. Fine, if looping motion, let's // ..switch directions - otherwise shut down the motion. if(pFollower->MotionLoops) { if(pFollower->Reverse) pFollower->bForward = GE_FALSE; // Switch direction else { CCD->PathDatabase()->Rewind(pFollower->PathHandle, &thePos); pFollower->CurrentTarget = thePos; } } else { pFollower->bReady = GE_FALSE; // End of motion pFollower->bMoving = GE_FALSE; // Don't move any more! } } else { // All be cool, set our target tot he new point pFollower->CurrentTarget = thePos; } } else { // Get previous pathpoint nResult = CCD->PathDatabase()->PreviousPoint(pFollower->PathHandle, &thePos); if(nResult == RGF_NO_PREVIOUS) { // No previous point is START OF PATH. Fine, if looping motion, let's // ..switch directions - otherwise shut down the motion. if(pFollower->MotionLoops) pFollower->bForward = GE_TRUE; // Switch direction else { pFollower->bReady = GE_FALSE; // End of motion pFollower->bMoving = GE_FALSE; // Don't move any more! } } else { // All be cool, set our target tot he new point pFollower->CurrentTarget = thePos; } } } // All done, new point back to caller return RGF_SUCCESS; } // Entity not bound, return failure. return RGF_FAILURE; }
GENESISAPI gePhysicsJoint * GENESISCC gePhysicsJoint_Create(gePhysicsJoint_Kind Kind, const geVec3d *Location, geFloat assemblyRate, gePhysicsObject *PS1, gePhysicsObject *PS2, geFloat physicsScale) { gePhysicsJoint* pPhysjnt; geVec3d POLocation; geVec3d physicsSpaceLocation; pPhysjnt = NULL; pPhysjnt = GE_RAM_ALLOCATE_STRUCT(gePhysicsJoint); if (pPhysjnt == NULL) { return NULL; } //////////////////////////////////////////////////////////////////////////////////////////////////// // make sure the joint makes sense pPhysjnt->Type = Kind; pPhysjnt->assemblyRate = assemblyRate * JOINT_ASSEMBLY_RATE_MULTIPLIER; pPhysjnt->Object1 = PS1; pPhysjnt->Object2 = PS2; geVec3d_Scale(Location, physicsScale, &physicsSpaceLocation); switch (Kind) { case JT_WORLD: if (PS1 == NULL) { /* GenVSI_Error(VSI, GE_FALSE, "Joint_Spawn: World joint needs non-NULL gePhysicsObject1 field.\n"); */ return NULL; } #if 0 if (pJoint->Next == pJoint) { /* GenVSI_Error(VSI, GE_FALSE, "Joint_Spawn: Next field points to parent.\n"); */ return NULL; } #endif gePhysicsObject_GetLocation(PS1, &POLocation, 0); geVec3d_Subtract(&physicsSpaceLocation, &POLocation, &pPhysjnt->locationA); geVec3d_Copy(&physicsSpaceLocation, &pPhysjnt->locationB); break; case JT_SPHERICAL: if (PS1 == NULL || PS2 == NULL) { /* GenVSI_Error(VSI, GE_FALSE, "Joint_Spawn: Spherical joint needs 2 non-NULL gePhysicsObjects.\n"); */ return NULL; } #if 0 if (pJoint->Next == pJoint) { /* GenVSI_Error(VSI, GE_FALSE, "Joint_Spawn: Next field points to parent.\n"); */ } #endif if (PS1 == PS2) { /* GenVSI_Error(VSI, GE_FALSE, "Joint_Spawn: Spherical joint: need 2 distinct gePhysicsObjects.\n"); */ return NULL; } gePhysicsObject_GetLocation(PS1, &POLocation, 0); geVec3d_Subtract(&physicsSpaceLocation, &POLocation, &pPhysjnt->locationA); gePhysicsObject_GetLocation(PS2, &POLocation, 0); geVec3d_Subtract(&physicsSpaceLocation, &POLocation, &pPhysjnt->locationB); break; default: /* GenVSI_Error(VSI, GE_FALSE, "Joint_Spawn: unsupported joint type %d.\n", ij->jointType); */ return NULL; } return pPhysjnt; }
/* ------------------------------------------------------------------------------------ */ static void Particles_MoveParticles(Procedural *Proc, geFloat time) { int cnt; Particle *pP; pP = Proc->Particles; for(cnt=0; cnt<Proc->NumActiveParticles; cnt++, pP++) { geFloat mul, vsqr; pP->CurDeathTime += time; if(pP->CurDeathTime > pP->DeathTime) { pP->shade -= (Proc->NumShades + 15)>>4; pP->CurDeathTime -= pP->DeathTime; } if(pP->shade < 0) { Particles_DeleteParticle(Proc,pP); if(cnt >= Proc->NumActiveParticles) break; } pP->p[0] += pP->v[0] * time; Proc->Capper(pP->p + 0, pP->v + 0, Proc->SizeX); pP->p[1] += pP->v[1] * time; Proc->Capper(pP->p + 1, pP->v + 1, Proc->SizeY); pP->p[2] += pP->v[2] * time; Proc->Capper(pP->p + 2, pP->v + 2, Proc->SizeZ); vsqr = geVec3d_LengthSquared((geVec3d*)pP->v); if(vsqr > 100.0f) vsqr = 100.0f; mul = vsqr * pP->Drag; if(mul > 0.05f) mul = 0.05f; pP->v[0] -= pP->v[0] * mul; pP->v[1] -= pP->v[1] * mul; pP->v[2] -= pP->v[2] * mul; // change velocity based on some forces if(Proc->DoMagnetic) { geVec3d A; geVec3d_CrossProduct((geVec3d*)(pP->v) , &(Proc->MagneticField), &A); pP->v[0] += time * A.X; pP->v[1] += time * A.Y; pP->v[2] += time * A.Z; } if(Proc->DoAttractor) { geFloat ax, ay, az, q; if(Proc->AttractorIsAxis) { geVec3d Diff; geVec3d_Subtract((geVec3d*)pP->p , &(Proc->AttractorPos), &Diff); q = geVec3d_DotProduct(&(Proc->AttractorAxis), &Diff); ax = q * Proc->AttractorAxis.X - Diff.X; ay = q * Proc->AttractorAxis.Y - Diff.Y; az = q * Proc->AttractorAxis.Z - Diff.Z; } else { ax = Proc->AttractorPos.X - pP->p[0]; ay = Proc->AttractorPos.Y - pP->p[1]; az = Proc->AttractorPos.Z - pP->p[2]; } q = Proc->AttractorStrength * time; ax *= q; ay *= q; az *= q; pP->v[0] += ax; pP->v[1] += ay; pP->v[2] += az; } }