示例#1
0
//========================================================================================
//	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);
}
示例#2
0
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);
}
示例#3
0
/* ------------------------------------------------------------------------------------ */
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]);
}
示例#4
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);
}
示例#5
0
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;
}