//======================================================================================== // 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); }
/* ------------------------------------------------------------------------------------ */ 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; } }
//===================================================================================== // 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 CMainFrame::OnUpdateWorldPos(CCmdUI *pCmdUI) { CPoint CursorPos; char stuff[100]; CFusionView * pView ; CWnd * pWnd ; geVec3d wp ; pCmdUI->Enable() ; GetCursorPos(&CursorPos); pWnd = WindowFromPoint( CursorPos ); if( pWnd != NULL ) { if( pWnd->IsKindOf( RUNTIME_CLASS (CFusionView)) ) { pView = (CFusionView *)pWnd ; if( pView->mViewType == ID_VIEW_TOPVIEW || pView->mViewType == ID_VIEW_FRONTVIEW || pView->mViewType == ID_VIEW_SIDEVIEW ) { pView->ScreenToClient( &CursorPos ) ; Render_ViewToWorld( pView->VCam, CursorPos.x, CursorPos.y, &wp ) ; CFusionDoc *pDoc =pView->GetDocument(); if(pDoc) { if (Level_GetGridType (pDoc->pLevel) == GridMetric) { geVec3d_Scale (&wp, Units_EngineToCentimeters (1.0f), &wp); } } sprintf( stuff, "% 4d,% 4d,% 4d", (int)wp.X, (int)wp.Y, (int)wp.Z ); pCmdUI->SetText( stuff ) ; return ; } } } m_wndStatusBar.SetPaneText( ID_WORLDPOS_PANE, "" ); }
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; }
//===================================================================================== // RenderTexturedPoint //===================================================================================== static geBoolean RenderTexturedPoint(DRV_Driver *RDriver, gePoly *Poly, Frustum_Info *FInfo, geCamera *Camera) { assert(geWorld_PolyIsValid(Poly)); if (MirrorRecursion > 0) { GE_LVertex *pVerts, Save; geVec3d Up, Left, Start; geFloat Scale, XScale, YScale; const geXForm3d *MXForm; pVerts = Poly->Verts; Poly->NumVerts = 4; Start.X = pVerts[0].X; Start.Y = pVerts[0].Y; Start.Z = pVerts[0].Z; Save = pVerts[1] = pVerts[2] = pVerts[3] = pVerts[0]; MXForm = geCamera_GetWorldSpaceXForm(Camera); geXForm3d_GetLeft(MXForm, &Left); geXForm3d_GetUp(MXForm, &Up); Scale = Poly->Scale * 0.5f; XScale = (geFloat)geBitmap_Width(Poly->Bitmap) * Scale; YScale = (geFloat)geBitmap_Height(Poly->Bitmap) * Scale; geVec3d_Scale(&Left, XScale, &Left); geVec3d_Scale(&Up, YScale, &Up); pVerts->X = Start.X - Left.X + Up.X; pVerts->Y = Start.Y - Left.Y + Up.Y; pVerts->Z = Start.Z - Left.Z + Up.Z; pVerts->u = 0.0f; pVerts->v = 0.0f; pVerts++; pVerts->X = Start.X + Left.X + Up.X; pVerts->Y = Start.Y + Left.Y + Up.Y; pVerts->Z = Start.Z + Left.Z + Up.Z; pVerts->u = 1.0f; pVerts->v = 0.0f; pVerts++; pVerts->X = Start.X + Left.X - Up.X; pVerts->Y = Start.Y + Left.Y - Up.Y; pVerts->Z = Start.Z + Left.Z - Up.Z; pVerts->u = 1.0f; pVerts->v = 1.0f; pVerts++; pVerts->X = Start.X - Left.X - Up.X; pVerts->Y = Start.Y - Left.Y - Up.Y; pVerts->Z = Start.Z - Left.Z - Up.Z; pVerts->u = 1.0f; pVerts->v = 0.0f; RenderTexturedPoly(RDriver, Poly, FInfo, Camera); Poly->NumVerts = 1; // Restore the poly Poly->Verts[0] = Save; } else { //GFX_Plane *Planes; geVec3d Src, Dest; GE_LVertex *pVerts; DRV_TLVertex ScreenPnts[4]; geBitmap *Bitmap; geFloat Sx, Sy, z, UVAdd, Width, Height; geFloat Left, Right, Top, Bottom; geFloat Scale; uint32 RenderFlags; int32 i; assert(Poly != NULL); assert(Camera != NULL); pVerts = &Poly->Verts[0]; // Xform the point Src.X = pVerts->X; Src.Y = pVerts->Y; Src.Z = pVerts->Z; geCamera_Transform(Camera,&Src,&Dest); geCamera_Project(Camera, &Dest, &Src); for (i=0; i<4; i++) { ScreenPnts[i].x = Src.X; ScreenPnts[i].y = Src.Y; ScreenPnts[i].z = Src.Z; ScreenPnts[i].r = pVerts->r; ScreenPnts[i].g = pVerts->g; ScreenPnts[i].b = pVerts->b; ScreenPnts[i].a = pVerts->a; } z = -Dest.Z; if (z < 1) return GE_TRUE; { geRect Rect; geCamera_GetClippingRect(Camera,&Rect); Left = (geFloat)Rect.Left; Right = (geFloat)Rect.Right+1.0f; Top = (geFloat)Rect.Top; Bottom = (geFloat)Rect.Bottom+1.0f; } Scale = ((geCamera_GetScale(Camera) / z) * Poly->Scale); Bitmap = Poly->Bitmap; Width = (geFloat)geBitmap_Width(Bitmap) * Scale; Height = (geFloat)geBitmap_Height(Bitmap) * Scale; Sx = Width * 0.5f; Sy = Height * 0.5f; // Build the screen poly from the point ScreenPnts[0].x -= Sx; ScreenPnts[0].y -= Sy; ScreenPnts[1].x += Sx; ScreenPnts[1].y -= Sy; ScreenPnts[2].x += Sx; ScreenPnts[2].y += Sy; ScreenPnts[3].x -= Sx; ScreenPnts[3].y += Sy; ScreenPnts[0].u = 0.0f + pVerts->u; ScreenPnts[0].v = 0.0f + pVerts->v; ScreenPnts[1].u = 1.0f + pVerts->u; ScreenPnts[1].v = 0.0f + pVerts->v; ScreenPnts[2].u = 1.0f + pVerts->u; ScreenPnts[2].v = 1.0f + pVerts->v; ScreenPnts[3].u = 0.0f + pVerts->u; ScreenPnts[3].v = 1.0f + pVerts->v; // Now, clip it against the 2d camera viewport if (ScreenPnts[0].x < Left) { if (ScreenPnts[1].x <= Left) return GE_TRUE; UVAdd = (Left-ScreenPnts[0].x) / Width; Width -= Left-ScreenPnts[0].x; ScreenPnts[0].u += UVAdd; ScreenPnts[3].u += UVAdd; ScreenPnts[0].x = Left; ScreenPnts[3].x = Left; } if (ScreenPnts[0].y < Top) { if (ScreenPnts[2].y <= Top) return GE_TRUE; UVAdd = (Top-ScreenPnts[0].y) / Height; Height -= (Top-ScreenPnts[0].y); ScreenPnts[0].v += UVAdd; ScreenPnts[1].v += UVAdd; ScreenPnts[0].y = Top; ScreenPnts[1].y = Top; } if (ScreenPnts[1].x >= Right) { if (ScreenPnts[0].x >= Right) return GE_TRUE; UVAdd = (ScreenPnts[1].x-Right) / Width; Width -= (ScreenPnts[1].x-Right); ScreenPnts[1].u -= UVAdd; ScreenPnts[2].u -= UVAdd; ScreenPnts[1].x = Right-1; ScreenPnts[2].x = Right-1; } if (ScreenPnts[2].y >= Bottom) { if (ScreenPnts[0].y >= Bottom) return GE_TRUE; UVAdd = (ScreenPnts[2].y-Bottom) / Height; Height -= (ScreenPnts[2].x-Bottom); ScreenPnts[2].v -= UVAdd; ScreenPnts[3].v -= UVAdd; ScreenPnts[2].y = Bottom-1; ScreenPnts[3].y = Bottom-1; } // Lastly, render it... ScreenPnts[0].a = pVerts->a; // Fixed bug where i fogot to set RGB's... ScreenPnts[0].r = pVerts->r; ScreenPnts[0].g = pVerts->g; ScreenPnts[0].b = pVerts->b; if (Poly->RenderFlags & GE_RENDER_DO_NOT_OCCLUDE_OTHERS) RenderFlags = DRV_RENDER_NO_ZWRITE; else RenderFlags = 0; if (Poly->RenderFlags & GE_RENDER_DO_NOT_OCCLUDE_SELF) RenderFlags |= DRV_RENDER_NO_ZMASK; if (pVerts->a != 255.0f) RenderFlags |= DRV_RENDER_ALPHA; /* 01/30/2003 Wendell Buckner Driver render flush is probably causing a slow down! */ if (Poly->RenderFlags & GE_RENDER_DEPTH_SORT_BF) RenderFlags |= DRV_RENDER_FLUSH; if (Poly->RenderFlags & GE_RENDER_CLAMP_UV) RenderFlags |= DRV_RENDER_CLAMP_UV; if (Poly->RenderFlags & GE_RENDER_NO_FOG) // skybox fog RenderFlags |= DRV_RENDER_POLY_NO_FOG; assert(geWorld_HasBitmap(gWorld, Bitmap)); assert(geBitmap_GetTHandle(Bitmap)); /* 08/08/2004 Wendell Buckner BUG FIX: Allways call geBitmap_SetRenderFlags() before calling a textured rendering function(for embm, dot3, & etc...). */ geBitmap_SetRenderFlags(Bitmap, &RenderFlags); RDriver->RenderMiscTexturePoly((DRV_TLVertex*)ScreenPnts, 4, geBitmap_GetTHandle(Bitmap), RenderFlags); } return GE_TRUE; }
/* ------------------------------------------------------------------------------------ */ 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; }
/* ------------------------------------------------------------------------------------ */ 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; }
/* ------------------------------------------------------------------------------------ */ 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; }