//======================================================================================== // 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); }
//===================================================================================== // 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; }
//================================================================================ // 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; }
//==================================================================================== // 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; }
//================================================================================ // Frustum_SetFromCamera //================================================================================ void Frustum_SetFromCamera(Frustum_Info *Info, geCamera *Camera) { geFloat s, c, ZFar; geBoolean ZFarEnable; geVec3d Normal; int32 i; // changed QD Clipping geFloat ZScale; geCamera_GetViewAngleXSinCos(Camera,&s,&c); // Left clip plane Normal.X = s; Normal.Y = 0.0f; Normal.Z = -c; geVec3d_Normalize(&Normal); Info->Planes[0].Normal = Normal; // Right clip plane Normal.X = -s; geVec3d_Normalize(&Normal); Info->Planes[1].Normal = Normal; geCamera_GetViewAngleYSinCos(Camera,&s,&c); // Bottom clip plane Normal.X = 0.0f; Normal.Y = s; Normal.Z = -c; geVec3d_Normalize(&Normal); Info->Planes[2].Normal = Normal; // Top clip plane Normal.Y = -s; geVec3d_Normalize(&Normal); Info->Planes[3].Normal = Normal; // changed QD Clipping /* Info->NumPlanes = 4; // Clear all distances for (i=0; i<Info->NumPlanes; i++) { Info->Planes[i].Dist = 0.0f; Info->Planes[i].Type = PLANE_ANY; } // Check to see if we need to use a far clip plane geCamera_GetFarClipPlane(Camera, &ZFarEnable, &ZFar); if (ZFarEnable) { geFloat ZScale; ZScale = geCamera_GetZScale(Camera); // Far clip plane Normal.X = 0.0f; Normal.Y = 0.0f; Normal.Z = 1.0f; geVec3d_Normalize(&Normal); Info->Planes[4].Normal = Normal; Info->Planes[4].Dist = -(ZFar/ZScale); Info->Planes[4].Type = PLANE_ANY; Info->NumPlanes = 5; } /**/ Normal.X = 0.0f; Normal.Y = 0.0f; Normal.Z = -1.0f; Info->Planes[4].Normal = Normal; Info->NumPlanes = 5; // Clear all distances for (i=0; i<Info->NumPlanes; i++) { Info->Planes[i].Dist = 0.0f; Info->Planes[i].Type = PLANE_ANY; } ZScale = geCamera_GetZScale(Camera); Info->Planes[4].Dist = (2.0f/ZScale); // Check to see if we need to use a far clip plane geCamera_GetFarClipPlane(Camera, &ZFarEnable, &ZFar); if(ZFarEnable) { // Far clip plane Normal.X = 0.0f; Normal.Y = 0.0f; Normal.Z = 1.0f; geVec3d_Normalize(&Normal); Info->Planes[5].Normal = Normal; Info->Planes[5].Dist = -(ZFar/ZScale); Info->Planes[5].Type = PLANE_ANY; Info->NumPlanes = 6; } // end change // Get BBox info for fast BBox rejection against frustum... SetUpFrustumBBox(Info); }
/* ------------------------------------------------------------------------------------ */ 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; }
/* ------------------------------------------------------------------------------------ */ Procedural* Particles_Create(char *TextureName, geWorld *World, const char *InputParams) { Procedural *Proc; int i; char ParamWork[8192],*pstr; geBitmap *ppBitmap; Proc = GE_RAM_ALLOCATE_STRUCT(Procedural); if(!Proc) return (Procedural*)NULL; memset(Proc, 0, sizeof(Procedural)); ppBitmap = geWorld_GetBitmapByName(World, TextureName); /**** read Params *****/ // changed RF064 by QD if(!strcmp(InputParams, "Params_Oil")) { strcpy(ParamWork, Params_Oil); } else if(!strcmp(InputParams, "Params_Jet")) { strcpy(ParamWork,Params_Jet); } else if(!strcmp(InputParams, "Params_Steam")) { strcpy(ParamWork,Params_Steam); } else if(!strcmp(InputParams, "Params_Explosion") || strlen(InputParams) < 20 ) { strcpy(ParamWork,DefaultParams); } // end change RF064 by QD else { strcpy(ParamWork,InputParams); } pstr = strtok(ParamWork,strbreakers); Proc->NumParticles = getint(pstr); Proc->NumSources = getint(pstr); /**** make Bitmap *****/ if(!Particles_InitBitmap(ppBitmap)) goto fail; Proc->Bitmap = ppBitmap; Proc->SizeX = geBitmap_Width(Proc->Bitmap); Proc->SizeY = geBitmap_Height(Proc->Bitmap); geBitmap_GetInfo(Proc->Bitmap, &(Proc->BmInfo), (geBitmap_Info*)NULL); Proc->SizeZ = min(Proc->SizeX, Proc->SizeY); /**** make Particles *****/ Proc->Particles = (Particle*)geRam_AllocateClear(Proc->NumParticles * sizeof(Particle)); if(!(Proc->Particles)) goto fail; for(i=0; i<Proc->NumParticles; i++) { Proc->Particles[i].shade = -1; } Proc->NumActiveParticles = 0; /**** make Sources *****/ Proc->Sources = (ParticleSource*)geRam_AllocateClear(Proc->NumSources * sizeof(ParticleSource)); if(!(Proc->Sources)) goto fail; /**** More Params *****/ // <> for stock schemes, take a few colors as parameters if(matchstr(pstr, "oil")) { nextparam(pstr); Proc->NumColors = Proc->NumShades = 16; Proc->PixelRGBA = PixelRGBA_OilColor; } else if(matchstr(pstr, "fire")) { nextparam(pstr); Proc->NumColors = 1; Proc->NumShades = 256; Proc->PixelRGBA = PixelRGBA_FireColor; } else if(matchstr(pstr, "opaquefire")) { nextparam(pstr); Proc->NumColors = 1; Proc->NumShades = 256; Proc->PixelRGBA = PixelRGBA_OpaqueFireColor; } else if(matchstr(pstr, "steam")) { nextparam(pstr); Proc->NumColors = 1; Proc->NumShades = 256; Proc->PixelRGBA = PixelRGBA_SteamColor; } else { Proc->NumColors = getint(pstr); Proc->NumShades = getint(pstr); Proc->PixelRGBA = PixelRGBA_OilColor; // <> // way to read in general spline of colors ? } if((Proc->NumColors * Proc->NumShades) < 256) { Proc->NumColors = min(Proc->NumColors, 256); Proc->NumShades = 256 / Proc->NumColors; } Proc->NumSmoothes = getint(pstr); Proc->SmoothRadius = getint(pstr); if(matchstr(pstr, "bounce")) { Proc->Capper = Capper_Bounce; Proc->SmoothWrap = GE_FALSE; } else if(matchstr(pstr,"wrap")) { Proc->Capper = Capper_Wrap; Proc->SmoothWrap = GE_TRUE; } else if(matchstr(pstr,"hard")) { Proc->Capper = Capper_Hard; Proc->SmoothWrap = GE_FALSE; } else { goto fail; } nextparam(pstr); Proc->DoMagnetic = getbool(pstr); if(Proc->DoMagnetic) { getvec(pstr, &(Proc->MagneticField)); } Proc->DoAttractor = getbool(pstr); if(Proc->DoAttractor) { Proc->AttractorStrength = getfloat(pstr); // negative for repulsive Proc->AttractorIsAxis = getbool(pstr); if(Proc->AttractorIsAxis) { getvec(pstr, &(Proc->AttractorAxis)); geVec3d_Normalize(&(Proc->AttractorAxis)); } getvec(pstr, &(Proc->AttractorPos)); scalevec(&(Proc->AttractorPos)); } /**** LUT's *****/ if(!Particles_InitPalette(Proc)) goto fail; for(i=0; i<Proc->NumSources; i++) { ParticleSource *pSource; Particle *pParticle; pSource = Proc->Sources + i; // base pParticle = &(pSource->Base); getvec(pstr, pParticle->p); getvec(pstr, pParticle->v); scalevec(pParticle->p); scalevec(pParticle->v); pParticle->DeathTime = getfloat(pstr); pParticle->color = getint(pstr); pParticle->shade = Proc->NumShades - 1; pParticle->CurDeathTime = 0.0f; // random pParticle = &(pSource->Random); getvec(pstr,pParticle->p); getvec(pstr,pParticle->v); scalevec(pParticle->p); scalevec(pParticle->v); absvec(pParticle->p); absvec(pParticle->v); pParticle->DeathTime = getfloat(pstr); pParticle->color = getint(pstr); pParticle->shade = getint(pstr); pParticle->CurDeathTime = 0.0f; pSource->RandomVMagnitude = geVec3d_Normalize((geVec3d*)(pParticle->v)); pSource->Delay = getfloat(pstr); // seconds pSource->Base.Drag = getfloat(pstr); pSource->CurTime = pSource->Delay; } return Proc; fail: Particles_Destroy(Proc); return (Procedural*)NULL; }