Esempio n. 1
0
static void d3d_SetupSkyStuff(const SkyDef& Def, ViewParams* pParams)
{
	LTVector percents;
	
	if(g_pSceneDesc->m_DrawMode == DRAWMODE_NORMAL)
	{
        const LTVector &min = world_bsp_shared->ExtentsMin();
        const LTVector &max = world_bsp_shared->ExtentsMax();
		percents.x = (pParams->m_Pos.x - min.x) / (max.x - min.x);
		percents.y = (pParams->m_Pos.y - min.y) / (max.y - min.y);
		percents.z = (pParams->m_Pos.z - min.z) / (max.z - min.z);
	}
	else
	{
		percents.Init(0.5f, 0.5f, 0.5f);
	}

	LTVector v = Def.m_ViewMax - Def.m_ViewMin;

	v.x *= percents.x;
	v.y *= percents.y;
	v.z *= percents.z;

	pParams->m_SkyViewPos = Def.m_ViewMin + v;
}
void CSteamFX::TweakSystem()
{
    LTFLOAT fIncValue = 0.01f;
    LTBOOL bChanged = LTFALSE;

    LTVector vScale;
	vScale.Init();

    uint32 dwPlayerFlags = g_pGameClientShell->GetPlayerFlags();

	// Move faster if running...

	if (dwPlayerFlags & BC_CFLG_RUN)
	{
		fIncValue = .5f;
	}

	// Move Red up/down...

	if ((dwPlayerFlags & BC_CFLG_FORWARD) || (dwPlayerFlags & BC_CFLG_REVERSE))
	{

		//m_cs.vMinVel
		//m_cs.vMaxVel
		//m_cs.vColor1
		//m_cs.vColor2

        bChanged = LTTRUE;
	}


	// Add/Subtract number of particles per second

	if ((dwPlayerFlags & BC_CFLG_STRAFE_RIGHT) || (dwPlayerFlags & BC_CFLG_STRAFE_LEFT))
	{
		fIncValue = dwPlayerFlags & BC_CFLG_STRAFE_RIGHT ? fIncValue : -fIncValue;
        //m_cs.fParticlesPerSecond += (LTFLOAT)(fIncValue * 101.0);

		//m_cs.fParticlesPerSecond = m_cs.fParticlesPerSecond < 0.0f ? 0.0f :
		//	(m_cs.fParticlesPerSecond > MAX_PARTICLES_PER_SECOND ? MAX_PARTICLES_PER_SECOND : m_cs.fParticlesPerSecond);

        bChanged = LTTRUE;
	}


	// Lower/Raise burst wait...

	if ((dwPlayerFlags & BC_CFLG_JUMP) || (dwPlayerFlags & BC_CFLG_DUCK))
	{
		fIncValue = dwPlayerFlags & BC_CFLG_DUCK ? -fIncValue : fIncValue;

        bChanged = LTTRUE;
	}


	if (bChanged)
	{
		//g_pGameClientShell->CSPrint("Particles per second: %.2f", m_cs.fParticlesPerSecond);
	}
}
Esempio n. 3
0
bool CPolyFanFX::Init(ILTClient *pClientDE, FX_BASEDATA *pBaseData, const CBaseFXProps *pProps)
{
	// Perform base class initialisation

	if (!CBaseFX::Init(pClientDE, pBaseData, pProps)) 
		return false;

	LTVector vPos;
	if( m_hParent )
	{
		m_pLTClient->GetObjectPos(m_hParent, &vPos);
	}
	else
	{
		vPos = m_vCreatePos;
	}

	LTVector vScale;
	vScale.Init(1.0f, 1.0f, 1.0f);

	ObjectCreateStruct ocs;
	INIT_OBJECTCREATESTRUCT(ocs);

	ocs.m_ObjectType		= OT_NORMAL;
	ocs.m_Flags				= 0;
	ocs.m_Pos				= vPos;
	ocs.m_Scale				= vScale;
	strcpy(ocs.m_Filename, GetProps()->m_sPolyFanName);

	m_hObject = m_pLTClient->CreateObject(&ocs);

	// Success !!

	return true;
}
Esempio n. 4
0
bool GetIntersectionUnderPoint( LTVector &vInPt, HOBJECT *pFilterList, LTVector &vOutNormal, LTVector &vOutPt )
{
	IntersectQuery	iq;
	IntersectInfo		ii;
	
	vOutNormal.Init(0, 1, 0);

	iq.m_Flags	= IGNORE_NONSOLID | INTERSECT_OBJECTS | INTERSECT_HPOLY;
	iq.m_From	= vInPt;
	iq.m_To		= iq.m_From + LTVector( 0, -1, 0) * 256.0f;

	iq.m_FilterFn  = ObjListFilterFn;
	iq.m_pUserData = pFilterList;

	if( g_pLTClient->IntersectSegment( iq, &ii ) )
	{
		if( ii.m_hObject )
		{
			vOutNormal	= ii.m_Plane.m_Normal;
			vOutPt		= ii.m_Point;

			return true;
		}
	}
	
	return false;
}
Esempio n. 5
0
void CScreenTintMgr::Update()
{
	if (!m_bChanged)
		return;

    LTVector vTemp;
	vTemp.Init(0.0f,0.0f,0.0f);
	for (int i = 0; i < NUM_TINT_EFFECTS; i++)
	{
		vTemp.x = LTMAX(vTemp.x,m_avTints[i].x);
		vTemp.y = LTMAX(vTemp.y,m_avTints[i].y);
		vTemp.z = LTMAX(vTemp.z,m_avTints[i].z);
	}

	if (vTemp.x > 1.0f)
		vTemp.x = 1.0f;
	if (vTemp.y > 1.0f)
		vTemp.y = 1.0f;
	if (vTemp.z > 1.0f)
		vTemp.z = 1.0f;
    m_bChanged = false;

    //g_pLTClient->SetCameraLightAdd( g_pPlayerMgr->GetPlayerCamera()->GetCamera(), &vTemp);

}
void GameBase::CreateBoundingBox()
{
	if (m_hDimsBox) return;

	if (!g_vtDimsAlpha.IsInitted())
	{
        g_vtDimsAlpha.Init(g_pLTServer, "DimsAlpha", LTNULL, 1.0f);
	}

	ObjectCreateStruct theStruct;
	INIT_OBJECTCREATESTRUCT(theStruct);

    LTVector vPos;
    g_pLTServer->GetObjectPos(m_hObject, &vPos);
	theStruct.m_Pos = vPos;

	SAFE_STRCPY(theStruct.m_Filename, "Models\\1x1_square.abc");
	SAFE_STRCPY(theStruct.m_SkinName, "Models\\1x1_square.dtx");

	theStruct.m_Flags = FLAG_VISIBLE | FLAG_NOLIGHT | FLAG_GOTHRUWORLD;
	theStruct.m_ObjectType = OT_MODEL;

    HCLASS hClass = g_pLTServer->GetClass("BaseClass");
    LPBASECLASS pModel = g_pLTServer->CreateObject(hClass, &theStruct);

	if (pModel)
	{
		m_hDimsBox = pModel->m_hObject;

        LTVector vDims;
        g_pLTServer->GetObjectDims(m_hObject, &vDims);

        LTVector vScale;
		VEC_DIVSCALAR(vScale, vDims, 0.5f);
        g_pLTServer->ScaleObject(m_hDimsBox, &vScale);
	}


    LTVector vOffset;
    LTRotation rOffset;
	vOffset.Init();
    rOffset.Init();

	HATTACHMENT hAttachment;
    LTRESULT dRes = g_pLTServer->CreateAttachment(m_hObject, m_hDimsBox, LTNULL,
											     &vOffset, &rOffset, &hAttachment);
    if (dRes != LT_OK)
	{
        g_pLTServer->RemoveObject(m_hDimsBox);
        m_hDimsBox = LTNULL;
	}

    LTVector vColor = GetBoundingBoxColor();

    g_pLTServer->SetObjectColor(m_hDimsBox, vColor.x, vColor.y, vColor.z, g_vtDimsAlpha.GetFloat());
}
LTBOOL CProjectileFX::MoveServerObj()
{
    if (!m_pClientDE || !m_bLocal || !m_hServerObject || !g_pWeaponMgr) return LTFALSE;

    ILTClientPhysics* pPhysicsLT = (ILTClientPhysics *)m_pClientDE->Physics();
    if (!pPhysicsLT) return LTFALSE;

    LTFLOAT fTime = m_pClientDE->GetTime();

	// If we didn't hit anything we're done...

	if (fTime >= (m_fStartTime + m_pProjectileFX->fLifeTime))
	{
        return LTFALSE;
	}

    LTFLOAT fFrameTime = g_pGameClientShell->GetFrameTime();

	// Zero out the acceleration to start with.

    LTVector zeroVec;
	zeroVec.Init();
	pPhysicsLT->SetAcceleration(m_hServerObject, &zeroVec);

    LTBOOL bRet = LTTRUE;
	MoveInfo info;

	info.m_hObject  = m_hServerObject;
	info.m_dt		= fFrameTime;
	pPhysicsLT->UpdateMovement(&info);

	if (info.m_Offset.MagSqr() > 0.01f)
	{
        LTVector vDiff, vNewPos, vCurPos;
		m_pClientDE->GetObjectPos(m_hServerObject, &vCurPos);
		vNewPos = vCurPos + info.m_Offset;
		pPhysicsLT->MoveObject(m_hServerObject, &vNewPos, 0);

		vDiff = vCurPos - vNewPos;
		if (vDiff.MagSqr() < 5.0f)
		{
            bRet = LTFALSE;
		}
	}
	else
	{
        bRet = LTFALSE;
	}

	return bRet;
}
Esempio n. 8
0
void TestSubtitleFn(int argc, char **argv)
{
	// Track the current execution shell scope for proper SEM behavior
	CGameClientShell::CClientShellScopeTracker cScopeTracker;

	if (argc <= 0) return;

	LTVector vPos;

	vPos.Init();

	g_pSubtitles->Show(argv[0],vPos);
	
}
Esempio n. 9
0
LTBOOL gr_IntersectPlanes(
	LTPlane &plane0,
	LTPlane &plane1,
	LTPlane &plane2,
	LTVector &vOut)
{
	LTMatrix mPlanes;

	/*
		Math behind this:

		Plane equation is Ax + By + Cz - D = 0
		Standard matrix equation Ax = b.

		So stick the plane equations into the A matrix:

		A B C -D	(from plane 0)
		A B C -D	(from plane 1)
		A B C -D	(from plane 2)
		0 0 0  1

		then the b vector is:
		[0 0 0 1]

		and we're solving for the x vector so:
		~AAx = ~Ab
		x = ~Ab
	*/

	mPlanes.Init(
		plane0.m_Normal[0], plane0.m_Normal[1], plane0.m_Normal[2], -plane0.m_Dist,
		plane1.m_Normal[0], plane1.m_Normal[1], plane1.m_Normal[2], -plane1.m_Dist,
		plane2.m_Normal[0], plane2.m_Normal[1], plane2.m_Normal[2], -plane2.m_Dist,
		0.0f, 0.0f, 0.0f, 1.0f);

	// If we can't invert the matrix, then two or more planes are equal.
	if(!mPlanes.Inverse())
		return LTFALSE;

	// Since our b vector is all zeros, we don't need to do a full matrix multiply.
	// vOut = mPlaneNormal * vPlaneDist;
	vOut.Init(
		mPlanes.m[0][3],
		mPlanes.m[1][3],
		mPlanes.m[2][3]);

	vOut *= (1.0f / mPlanes.m[3][3]);
	return LTTRUE;
}
Esempio n. 10
0
//---------------------------------------------------------------------------//
static void GetSmallestPushaway
(
	LTVector &moverMin,
	LTVector &moverMax, 
	LTVector &blockerMin,
	LTVector &blockerMax,
	LTVector &pushAmount,
	int32 &pushPlane
)
{
	float		minPush;
	int32			minPushDim = 0;
	
	float		testPush;
	int32			i, curPushPlane, minPushPlane;

	
	minPush = (float)MAX_CREAL;
	curPushPlane = 0;
	minPushPlane = 0;
	
	for(i=0; i < 3; i++)
	{
		testPush = blockerMax[i] - moverMin[i];
		if(fabs(testPush) < fabs(minPush))
		{
			minPush = testPush;
			minPushDim = i;
			minPushPlane = curPushPlane;
		}
		++curPushPlane;
		
		testPush = blockerMin[i] - moverMax[i];
		if(fabs(testPush) < fabs(minPush))
		{
			minPush = testPush;
			minPushDim = i;
			minPushPlane = curPushPlane;
		}
		++curPushPlane;
	}

	pushAmount.Init(0.0f, 0.0f, 0.0f);
	pushAmount[minPushDim] = minPush;
	pushPlane = minPushPlane;
}
Esempio n. 11
0
void CCharacterHitBox::GetDefaultModelDims( LTVector &vDims )
{
	vDims.Init();

	if( !m_hModel || !m_hObject )
		return;

	HMODELANIM hAni = g_pModelLT->GetCurAnim( m_hModel, MAIN_TRACKER, hAni );
	if( hAni != INVALID_ANI )
	{
		g_pModelLT->GetModelAnimUserDims( m_hModel, hAni, &vDims );
	}
	else
	{
		g_pPhysicsLT->GetObjectDims( m_hObject, &vDims );
	}
}
Esempio n. 12
0
	//called when a sphere shape is encountered. This will provide the center of the sphere relative
	//to the transform heirarchy and the radius of that sphere
	virtual void HandleSphere(const LTVector& vCenter, float fRadius, float fMassKg, float fDensityG)							
	{
		m_fTotalMassKg += fMassKg;

		float fVolume, fSurfaceArea;
		if(ApplySphereBuoyancy(vCenter, fRadius, m_SurfacePlane, fVolume, fSurfaceArea))
		{
			m_fSurfaceArea += fSurfaceArea;
			float fWaterDensity = CalcSphereWaterDensity(m_fDensity, fRadius, fMassKg, fDensityG);
            LTVector vForce = CalcBuoyancyForceVector(m_vGravity, fWaterDensity, fVolume);
			if( LTIsNaN( vForce ) || vForce.MagSqr() > 1000000.0f * 1000000.0f )
			{
				LTERROR( "Invalid force detected." );
				vForce.Init( 0.0f, 10.0f, 0.0f );
			}
			g_pLTBase->PhysicsSim()->ApplyRigidBodyForceWorldSpace(m_hRigidBody, vCenter, vForce);
		}
	}
Esempio n. 13
0
bool CDynaLightFX::Init(ILTClient *pClientDE, FX_BASEDATA *pBaseData, const CBaseFXProps *pProps)
{
	// Perform base class initialisation

	if (!CBaseFX::Init(pClientDE, pBaseData, pProps)) 
		return false;

	LTVector vScale;
	vScale.Init(100.0f, 100.0f, 100.0f);

	ObjectCreateStruct ocs;
	INIT_OBJECTCREATESTRUCT(ocs);

	ocs.m_ObjectType		= OT_LIGHT;
	ocs.m_Flags				= pBaseData->m_dwObjectFlags;
	ocs.m_Flags2			|= pBaseData->m_dwObjectFlags2;
	ocs.m_Pos				= m_vCreatePos;
	ocs.m_Rotation			= m_rCreateRot;
	ocs.m_Scale				= vScale;

	if(GetProps()->m_bForceLightWorld)
	{
		ocs.m_Flags2 |= FLAG2_FORCEDYNAMICLIGHTWORLD;
	}

	// Lights can't be really close

	ocs.m_Flags	&= ~FLAG_REALLYCLOSE;

	// Create the light

	m_hObject = m_pLTClient->CreateObject(&ocs);

	// We want the colour updated thankyou

	m_bUpdateColour = true;
	m_bUpdateScale  = true;

	// Success !!

	return true;
}
Esempio n. 14
0
	//called when an OBB shape is encountered. This will provide the transform of the OBB relative to
	//the transform heirarchy and the half dimensions of the OBB
	virtual void HandleOBB(const LTRigidTransform& tTransform, const LTVector& vHalfDims, float fMassKg, float fDensityG)		
	{
		m_fTotalMassKg += fMassKg;

		float fVolume, fSurfaceArea;
		LTVector vApplyAt;

		if(ApplyOBBBuoyancy(tTransform, vHalfDims, m_SurfacePlane, fVolume, vApplyAt, fSurfaceArea))
		{
			m_fSurfaceArea += fSurfaceArea;
			float fWaterDensity = CalcOBBWaterDensity(m_fDensity, vHalfDims, fMassKg, fDensityG);
			LTVector vForce = CalcBuoyancyForceVector(m_vGravity, fWaterDensity, fVolume);
			if( LTIsNaN( vForce ) || vForce.MagSqr() > 1000000.0f * 1000000.0f )
			{
				LTERROR( "Invalid force detected." );
				vForce.Init( 0.0f, 10.0f, 0.0f );
			}
			g_pLTBase->PhysicsSim()->ApplyRigidBodyForceWorldSpace(m_hRigidBody, vApplyAt, vForce);
		}
	}
Esempio n. 15
0
	//called when a capsule shape is encounered. This will provide the two end points of the capsule
	//relative to the transform heirarchy and the radius of the capsule
	virtual void HandleCapsule(const LTVector& vPt1, const LTVector& vPt2, float fRadius, float fMassKg, float fDensityG)		
	{
		m_fTotalMassKg += fMassKg;

		float fVolume, fSurfaceArea;
		LTVector vApplyAt;

		//determine the lenght of the capsule axis
		float fLength = vPt1.Dist(vPt2);

		if(ApplyCapsuleBuoyancy(vPt1, vPt2, fLength, fRadius, m_SurfacePlane, fVolume, vApplyAt, fSurfaceArea))
		{
			m_fSurfaceArea += fSurfaceArea;
			float fWaterDensity = CalcCapsuleWaterDensity(m_fDensity, fRadius, fLength, fMassKg, fDensityG);
			LTVector vForce = CalcBuoyancyForceVector(m_vGravity, fWaterDensity, fVolume);
			if( LTIsNaN( vForce ) || vForce.MagSqr() > 1000000.0f * 1000000.0f )
			{
				LTERROR( "Invalid force detected." );
				vForce.Init( 0.0f, 10.0f, 0.0f );
			}
			g_pLTBase->PhysicsSim()->ApplyRigidBodyForceWorldSpace(m_hRigidBody, vApplyAt, vForce);
		}
	}
Esempio n. 16
0
// Gives each object a touch notification and creates container links for them.
void DoNonsolidCollision(MoveAbstract *pAbstract, LTObject *pObj1, LTObject *pObj2)
{
	CollisionInfo *pInfo;
	LTVector zeroVec;


	pInfo = pAbstract->GetCollisionInfo();

	// Setup the collision info...
	pInfo->m_Plane.m_Normal.Init();
	pInfo->m_Plane.m_Dist = 0.0f;
	pInfo->m_hPoly = INVALID_HPOLY;
	
	zeroVec.Init();

	if(pObj1->m_Flags & FLAG_TOUCH_NOTIFY)
	{
		pAbstract->DoTouchNotify(pObj1, pObj2, zeroVec, 0.0f);
	}

	if(pObj2->m_Flags & FLAG_TOUCH_NOTIFY)
	{
		pAbstract->DoTouchNotify(pObj2, pObj1, zeroVec, 0.0f);
	}

	// Update area object touching.
	if(pObj1->m_Flags & FLAG_CONTAINER)
	{
		pAbstract->PutObjectInContainer(pObj2, pObj1);
	}
	
	if(pObj2->m_Flags & FLAG_CONTAINER)
	{
		pAbstract->PutObjectInContainer(pObj1, pObj2);
	}
}
Esempio n. 17
0
void CFlashLightPlayer::GetLightPositions(LTVector& vStartPos, LTVector& vEndPos, LTVector& vUOffset, LTVector& vROffset)
{
	vStartPos.Init();
	vEndPos.Init();
	vUOffset.Init();
	vROffset.Init();

	CMoveMgr* pMoveMgr = g_pPlayerMgr->GetMoveMgr();
	if (!pMoveMgr) return;

	LTRotation rRot;

	if (pMoveMgr->GetVehicleMgr()->IsVehiclePhysics())
	{
		if (g_pPlayerMgr->IsFirstPerson())
		{
			pMoveMgr->GetVehicleMgr()->GetVehicleLightPosRot(vStartPos, rRot);
		}
		else // 3rd person vehicle
		{
			// Get light pos on 3rd-person vehicle...

			HLOCALOBJ hPlayerObj = g_pLTClient->GetClientObject();
			if (hPlayerObj)
			{
				g_pLTClient->GetObjectRotation(hPlayerObj, &rRot);
				g_pLTClient->GetObjectPos(hPlayerObj, &vStartPos);
			}
		}
	}
	else if (g_pPlayerMgr->IsFirstPerson())
	{
		HOBJECT hCamera = g_pPlayerMgr->GetCamera();
		if (!hCamera) return;

		g_pLTClient->GetObjectRotation(hCamera, &rRot);
		g_pLTClient->GetObjectPos(hCamera, &vStartPos);
	}
	else // 3rd person
	{
		// Get light pos from 3rd-person model...

		HLOCALOBJ hPlayerObj = g_pLTClient->GetClientObject();
		if (hPlayerObj)
		{
			// g_pLTClient->GetObjectRotation(hPlayerObj, &rRot);
			// g_pLTClient->GetObjectPos(hPlayerObj, &vStartPos);

			HMODELSOCKET hSocket;
			if ( LT_OK == g_pModelLT->GetSocket(hPlayerObj, "LeftHand", hSocket) )
			{
				LTransform tf;

				if ( LT_OK == g_pModelLT->GetSocketTransform(hPlayerObj, hSocket, tf, LTTRUE) )
				{
					vStartPos = tf.m_Pos;
					rRot = tf.m_Rot;
				}
			}
		}
	}

	vEndPos = vStartPos + (rRot.Forward() * g_cvarFLLightOffsetForward.GetFloat());

  	if (g_pPlayerMgr->IsFirstPerson())
  	{
  		vROffset = (rRot.Right() * g_cvarFLLightOffsetRight.GetFloat());
  		vUOffset = (rRot.Up() * g_cvarFLLightOffsetUp.GetFloat());

		// Update the Start/End position to addjust for any offset...

		vEndPos += vROffset;
		vEndPos += vUOffset;

		vStartPos += vROffset;
		vStartPos += vUOffset;
  	}
}
Esempio n. 18
0
//function that handles the custom rendering
void CBaseSpriteFX::RenderSprite(ILTCustomRenderCallback* pInterface, const LTRigidTransform& tCamera)
{
	//setup our vertex declaration
	if(pInterface->SetVertexDeclaration(g_ClientFXVertexDecl.GetTexTangentSpaceDecl()) != LT_OK)
		return;

	//bind a quad index stream
	if(pInterface->BindQuadIndexStream() != LT_OK)
		return;

	//determine how many indices we are going to need
	uint32 nNumIndices  = (GetProps()->m_bTwoSided) ? 12 : 6;
	uint32 nNumVertices = (GetProps()->m_bTwoSided) ? 8 : 4;

	//sanity check to ensure that we can at least render a sprite
	LTASSERT(QUAD_RENDER_INDEX_STREAM_SIZE >= nNumIndices, "Error: Quad index list is too small to render a sprite");
	LTASSERT(DYNAMIC_RENDER_VERTEX_STREAM_SIZE / sizeof(STexTangentSpaceVert) >= nNumVertices, "Error: Dynamic vertex buffer size is too small to render a sprite");

	//determine the up and right vectors for the sprite
	LTVector vTangent, vBinormal;

	//get the position of this sprite
	LTRigidTransform tObjTransform;
	g_pLTClient->GetObjectTransform(m_hObject, &tObjTransform);

	//determine the center of this sprite
	LTVector vCenter = tObjTransform.m_vPos;

	//determine the orientation of the sprite based upon its facing
	if(GetProps()->m_bAlignToCamera)
	{
		//apply the to camera offset
		LTVector vToCamera = tCamera.m_vPos - vCenter;
		float fScale = GetProps()->m_fToCameraOffset / vToCamera.Mag();
		vCenter += vToCamera * fScale;

		//perform the rotation
		float fCosAng = LTCos(m_fCurrRotationRad);
		float fSinAng = LTSin(m_fCurrRotationRad);

		LTVector vRight = tCamera.m_rRot.Right();
		LTVector vUp = -tCamera.m_rRot.Up();

		vTangent	= fCosAng * vRight + fSinAng * vUp;
		vBinormal	= fCosAng * vUp - fSinAng * vRight;
	}
	else if(GetProps()->m_bAlignAroundZ)
	{
		//we want to orient around the Z axis and align to the camera

		//we need to determine our U vector, which is always our forward
		LTVector vU = tObjTransform.m_rRot.Forward();

		//and now we want to offset our center so that we are anchored on the right hand
		//side of the sprite to the point
		vCenter += vU * (m_fWidth * 0.5f);

		//determine the axis from our camera to our object
		LTVector vToCamera = tCamera.m_vPos - vCenter;

		//and now derive our V vector from the forward and the direction to the camera
		LTVector vV = vToCamera.Cross(vU);

		//detect degenerate cases
		if(vV == LTVector::GetIdentity())
		{
			//degenerate case, any orientation will work fine since the sprite won't
			//be visible anyway
			vV.Init(0.0f, 1.0f, 0.0f);
		}

		//and normalize our vector
		vV.Normalize();

		//now we can determine our tangent and binormal vectors
		vTangent	= -vU;
		vBinormal	= vV;
	}
	else
	{
		vTangent	= -tObjTransform.m_rRot.Right();
		vBinormal	= -tObjTransform.m_rRot.Up();
	}
	
	LTVector vNormal = vBinormal.Cross(vTangent);

	//scale the right and down values to be the appropriate size
	LTVector vRight	= vTangent * m_fWidth * -0.5f;
	LTVector vDown	= vBinormal * m_fWidth * GetProps()->m_fAspectRatio * 0.5f;


	//lock down our buffer for rendering
	SDynamicVertexBufferLockRequest LockRequest;
	if(pInterface->LockDynamicVertexBuffer(nNumVertices, LockRequest) != LT_OK)
		return;

	//fill in our sprite vertices
	STexTangentSpaceVert* pCurrOut = (STexTangentSpaceVert*)LockRequest.m_pData;

	uint32 nColor = SETRGBA(	(uint8)(m_vColor.x * 255.0f), 
								(uint8)(m_vColor.y * 255.0f), 
								(uint8)(m_vColor.z * 255.0f), 
								(uint8)(m_vColor.w * 255.0f));

	//fill in the particle vertices
	pCurrOut[0].m_vPos = vCenter + vRight - vDown;
	pCurrOut[0].m_vUV.Init(0.0f, 0.0f);
	
	pCurrOut[1].m_vPos = vCenter - vRight - vDown;
	pCurrOut[1].m_vUV.Init(1.0f, 0.0f);
	
	pCurrOut[2].m_vPos = vCenter - vRight + vDown;
	pCurrOut[2].m_vUV.Init(1.0f, 1.0f);

	pCurrOut[3].m_vPos = vCenter + vRight + vDown;
	pCurrOut[3].m_vUV.Init(0.0f, 1.0f);

	//setup the remaining vertex components
	for(uint32 nCurrVert = 0; nCurrVert < 4; nCurrVert++)
	{
		pCurrOut[nCurrVert].m_nPackedColor = nColor;
		pCurrOut[nCurrVert].m_vNormal = vNormal;
		pCurrOut[nCurrVert].m_vTangent = vTangent;
		pCurrOut[nCurrVert].m_vBinormal = vBinormal;
	}

	//and fill in the back side if appropriate
	if(GetProps()->m_bTwoSided)
	{
		pCurrOut[4].m_vPos = vCenter - vRight - vDown;
		pCurrOut[4].m_vUV.Init(1.0f, 0.0f);
		
		pCurrOut[5].m_vPos = vCenter + vRight - vDown;
		pCurrOut[5].m_vUV.Init(0.0f, 0.0f);
		
		pCurrOut[6].m_vPos = vCenter + vRight + vDown;
		pCurrOut[6].m_vUV.Init(0.0f, 1.0f);

		pCurrOut[7].m_vPos = vCenter - vRight + vDown;
		pCurrOut[7].m_vUV.Init(1.0f, 1.0f);

		//setup the remaining vertex components
		for(uint32 nCurrVert = 4; nCurrVert < 8; nCurrVert++)
		{
			pCurrOut[nCurrVert].m_nPackedColor = nColor;
			pCurrOut[nCurrVert].m_vNormal = -vNormal;
			pCurrOut[nCurrVert].m_vTangent = -vTangent;
			pCurrOut[nCurrVert].m_vBinormal = vBinormal;
		}
	}

	//unlock and render the batch
	pInterface->UnlockAndBindDynamicVertexBuffer(LockRequest);
	pInterface->RenderIndexed(	eCustomRenderPrimType_TriangleList, 
								0, nNumIndices, LockRequest.m_nStartIndex, 
								0, nNumVertices);
}
Esempio n. 19
0
bool CTrackedNodeMgr::SetNodeConstraints(	HTRACKEDNODE ID,
							const LTVector& vMovConeAxis, 
							const LTVector& vMovConeUp,
							float fXDiscomfortAngle,
							float fYDiscomfortAngle,
							float fXMaxAngle,
							float fYMaxAngle,
							float fMaxAngVel
						)
{
	//sanity checks
	if(!CheckValidity(ID))
		return false;

	//ok, we have a valid ID, so let us setup the parameters
	CTrackedNode* pNode = (CTrackedNode*)ID;

	//see if the up and forward vectors are valid
	LTVector vForward	= vMovConeAxis;
	LTVector vUp		= vMovConeUp;

	//ensure proper scale
	vForward.Normalize();
	vUp.Normalize();

	//ensure they form a valid space (and not a plane)
	if(vUp.Dot(vForward) > 0.99f)
	{
		//not valid, we need to try a different up, our preference is the world up
		vUp.Init(0.0f, 1.0f, 0.0f);

		if(vUp.Dot(vForward) > 0.99f)
		{
			//ok, forward is already taking the up....so, tilt us back
			vUp.Init(0.0f, 0.0f, -1.0f);
		}
	}

	//now generate the right, and ensure orthogonality
	LTVector vRight = vForward.Cross(vUp);
	vUp = vRight.Cross(vForward);

	vRight.Normalize();
	vUp.Normalize();

	//setup this as the basis space
	pNode->m_mInvTargetTransform.SetBasisVectors(&vRight, &vUp, &vForward);
	pNode->m_mInvTargetTransform.Transpose();

	//we need to make sure that their angular constraints are valid (meaning that they are positive and
	//less than 90 deg)
	fXMaxAngle			= LTCLAMP(fXMaxAngle,			0.0f, DEG2RAD(89.0f));
	fYMaxAngle			= LTCLAMP(fYMaxAngle,			0.0f, DEG2RAD(89.0f));
	fXDiscomfortAngle	= LTCLAMP(fXDiscomfortAngle,	0.0f, fXMaxAngle);
	fYDiscomfortAngle	= LTCLAMP(fYDiscomfortAngle,	0.0f, fYMaxAngle);

	//now precompute the tangent of those values (used for finding the height of the cone created which
	//is used in the threshold determination code)
	pNode->m_fTanXDiscomfort = (float)tan(fXDiscomfortAngle);
	pNode->m_fTanYDiscomfort = (float)tan(fYDiscomfortAngle);
	pNode->m_fTanXThreshold  = (float)tan(fXMaxAngle);
	pNode->m_fTanYThreshold  = (float)tan(fYMaxAngle);

	//handle setting up the maximum angular velocity
	pNode->m_fMaxAngVel		= (float)fabs(fMaxAngVel);

	//and we are ready for primetime
	return true;
}
Esempio n. 20
0
void Prop::HandleAttachmentTouch( HOBJECT hToucher )
{
	if( !hToucher || !m_bAttachmentShotOff )
		return;

	// Don't touch the owner...

	if( hToucher == m_hAttachmentOwner )
		return;

	// Or any non-solid objects...
	
	uint32 dwToucherFlags;
	g_pCommonLT->GetObjectFlags( hToucher, OFT_Flags, dwToucherFlags );
	if( !(dwToucherFlags & FLAG_SOLID) )
		return;

	CollisionInfo info;
    g_pLTServer->GetLastCollision( &info );

	LTVector vVel;
	g_pPhysicsLT->GetVelocity( m_hObject, &vVel );

	// Calculate where we really hit the world...
    
	if( IsMainWorld( hToucher ))
	{
        LTVector vPos, vCurVel, vP0, vP1;
        g_pLTServer->GetObjectPos( m_hObject, &vPos );

		vP1 = vPos;
        vCurVel = vVel * g_pLTServer->GetFrameTime();
		vP0 = vP1 - vCurVel;
		vP1 += vCurVel;

        LTFLOAT fDot1 = VEC_DOT( info.m_Plane.m_Normal, vP0 ) - info.m_Plane.m_Dist;
        LTFLOAT fDot2 = VEC_DOT( info.m_Plane.m_Normal, vP1 ) - info.m_Plane.m_Dist;

		if( fDot1 < 0.0f && fDot2 < 0.0f || fDot1 > 0.0f && fDot2 > 0.0f )
		{
			vPos = vP1;
		}
		else
		{
            LTFLOAT fPercent = -fDot1 / (fDot2 - fDot1);
			VEC_LERP( vPos, vP0, vP1, fPercent);
		}

		// Set our new "real" pos...

        g_pLTServer->SetObjectPos( m_hObject, &vPos );
	}

	// If we're on the ground (or an object), stop movement...

	CollisionInfo standingInfo;
    g_pLTServer->GetStandingOn( m_hObject, &standingInfo );

	CollisionInfo* pInfo = standingInfo.m_hObject ? &standingInfo : &info;

	if( pInfo->m_hObject )
	{
		// Don't stop on walls...

		if( pInfo->m_Plane.m_Normal.y > 0.75f )
		{
			vVel.Init();

			// Turn off gravity, solid, and touch notify....

			uint32 dwFlags = FLAG_POINTCOLLIDE | FLAG_NOSLIDING | FLAG_TOUCH_NOTIFY | FLAG_GRAVITY;
			g_pCommonLT->SetObjectFlags( m_hObject, OFT_Flags, 0, dwFlags );

			// Rotate to rest...

			if( m_bRotating )
			{
				LTRotation rRot( 0.0f, m_fYaw, 0.0f );
				g_pLTServer->SetObjectRotation( m_hObject, &rRot );

				m_bRotating = false;
				StartFade( s_vtAttachmentFadeDuration.GetFloat(), s_vtAttachmentFadeDelay.GetFloat() );
			}
		}
	}
	
	// Remove the stoping velocity...

	vVel = -info.m_vStopVel;
	g_pPhysicsLT->SetVelocity( m_hObject, &vVel );
}
Esempio n. 21
0
bool CFallingStuffFX::Update(float tmFrameTime)
{
    // Base class update first

    m_vLastPos = m_vPos;

    if (!CBaseFX::Update(tmFrameTime))
        return false;

    //increment our emission time by the elapsed frame time
    m_tmElapsedEmission += tmFrameTime;

    if (!IsShuttingDown() && !IsSuspended() && (m_tmElapsedEmission > GetProps()->m_tmFallingStuffFXEmission))
    {
        ObjectCreateStruct ocs;
        INIT_OBJECTCREATESTRUCT(ocs);

        LTVector vScale;
        vScale.Init(m_scale, m_scale, m_scale);

        LTVector vInterp;
        LTVector vInterpCur  = m_vPos;

        // Calculate interpolant for particle system

        if (GetProps()->m_nFallingStuffFXEmission)
        {
            vInterp = m_vPos - m_vLastPos;
            vInterp /= (float)GetProps()->m_nFallingStuffFXEmission;
        }

        for (uint32 i = 0; i < GetProps()->m_nFallingStuffFXEmission; i ++)
        {
            ocs.m_ObjectType		= OT_SPRITE;
            ocs.m_Flags				= FLAG_VISIBLE | FLAG_NOLIGHT | FLAG_ROTATABLESPRITE;

            // Compute the initial position

            float xRand = GetProps()->m_fRadius * ((-10000.0f + (rand() % 20000)) / 10000.0f);
            float zRand = GetProps()->m_fRadius * ((-10000.0f + (rand() % 20000)) / 10000.0f);

            ocs.m_Pos = m_vPos + (m_vRight * xRand) + (m_vUp * zRand);

            ocs.m_Scale				= vScale;
            strcpy(ocs.m_Filename, GetProps()->m_sSpriteName);

            // Move the start point

            vInterpCur += vInterp;

            HLOCALOBJ hNewSprite = m_pLTClient->CreateObject(&ocs);

            if (hNewSprite)
            {
                // Create a new sprite

                FALLING_THING *pNewSprite = debug_new( FALLING_THING );

                if (GetProps()->m_nImpactCreate)
                {
                    if (g_dwSplash > (uint32)GetProps()->m_nImpactCreate)
                    {
                        pNewSprite->m_bSplash = true;
                        g_dwSplash = 0;
                    }
                    else
                    {
                        pNewSprite->m_bSplash = false;
                    }
                }
                else
                {
                    pNewSprite->m_bSplash = false;
                }

                g_dwSplash ++;

                if (pNewSprite)
                {
                    LTVector v;

                    // Compute the initial velocity

                    v = m_vPlaneDir * GetProps()->m_fVel;

                    pNewSprite->m_hObject	= hNewSprite;
                    pNewSprite->m_vVel		= v;
                    pNewSprite->m_tmElapsed	= 0.0f;
                    pNewSprite->m_vPos		= ocs.m_Pos;
                    pNewSprite->m_vLastPos	= ocs.m_Pos;

                    m_collSprites.AddTail(pNewSprite);
                }
            }
        }

        m_tmElapsedEmission = 0.0f;

        // And store the last position

        m_vLastPos = m_vPos;
    }

    LTMatrix mSpin;

    if (GetProps()->m_bUseSpin)
    {
        // Setup rotation

        LTMatrix vRight;
        LTMatrix vUp;
        LTMatrix vForward;
        LTMatrix vTmp;

        Mat_SetupRot(&vRight, &m_vRight, m_xRot);
        Mat_SetupRot(&vUp, &m_vUp, m_yRot);
        Mat_SetupRot(&vForward, &m_vPlaneDir, m_zRot);

        MatMul(&vTmp, &vRight, &vUp);
        MatMul(&mSpin, &vTmp, &vForward);

        m_xRot += GetProps()->m_vRotAdd.x * tmFrameTime;
        m_yRot += GetProps()->m_vRotAdd.y * tmFrameTime;
        m_zRot += GetProps()->m_vRotAdd.z * tmFrameTime;
    }

    // Get the camera rotation

    LTRotation orient;
    m_pLTClient->GetObjectRotation(m_hCamera, &orient);

    LTRotation dRot(orient);

    LTVector vF = orient.Forward();

    float rot = (float)atan2(vF.x, vF.z);

    // Update the sprites....

    CLinkListNode<FALLING_THING *> *pNode = m_collSprites.GetHead();
    CLinkListNode<FALLING_THING *> *pDelNode;

    while (pNode)
    {
        pDelNode = NULL;

        FALLING_THING *pSprite = pNode->m_Data;

        //adjust our elapsed time
        pSprite->m_tmElapsed += tmFrameTime;

        // Check for expiration

        if (pSprite->m_tmElapsed > GetProps()->m_tmSpriteLifespan)
        {
            // Destroy this object

            m_pLTClient->RemoveObject(pSprite->m_hObject);

            pDelNode = pNode;
        }
        else
        {
            // Update !!

            pSprite->m_vLastPos = pSprite->m_vPos;

            pSprite->m_vPos += (pSprite->m_vVel * tmFrameTime);

            // Rotate if neccessary

            TVector3<float> vPos = pSprite->m_vPos;

            if (GetProps()->m_bUseSpin)
            {
                MatVMul_InPlace(&mSpin, &vPos);
            }

            // Add in wind

            vPos += (GetProps()->m_vWind * GetProps()->m_fWindAmount) * tmFrameTime;

            // Setup the new sprite position

            LTVector vPos2 = vPos;
            m_pLTClient->SetObjectPos(pSprite->m_hObject, &vPos2);


            // Setup the colour

            float r, g, b, a;

            m_pLTClient->GetObjectColor(pSprite->m_hObject, &r, &g, &b, &a);
            CalcColour(pSprite->m_tmElapsed, GetProps()->m_tmSpriteLifespan, &r, &g, &b, &a);
            m_pLTClient->SetObjectColor(pSprite->m_hObject, r, g, b, a);

            // Setup the scale

            float scale = 0.1f;

            CalcScale(pSprite->m_tmElapsed, GetProps()->m_tmSpriteLifespan, &scale);

            LTVector vScale;
            vScale.Init(scale, scale * GetProps()->m_fStretchMul, scale);
            m_pLTClient->SetObjectScale(pSprite->m_hObject, &vScale);

            // Setup the rotation

            dRot = LTRotation(0, 0, 0, 1);
            LTRotation orient(dRot);

            orient.Rotate( orient.Up(), rot );

            m_pLTClient->SetObjectRotation(pSprite->m_hObject, &orient);

            // Check to see if we need to start a splash sprite

            if (pSprite->m_bSplash)
            {
                ClientIntersectQuery ciq;
                ClientIntersectInfo  cii;

                ciq.m_From		= pSprite->m_vLastPos;
                ciq.m_To		= pSprite->m_vPos;

                if ((GetProps()->m_sImpactSpriteName[0]) && (m_pLTClient->IntersectSegment(&ciq, &cii)))
                {
                    // Create a splash sprite

                    SPLASH *pSplash = debug_new( SPLASH );

                    ObjectCreateStruct ocs;
                    INIT_OBJECTCREATESTRUCT(ocs);

                    LTVector vScale;
                    vScale.Init(0.0f, 0.0f, 0.0f);

                    ocs.m_ObjectType = OT_SPRITE;
                    ocs.m_Flags		 = FLAG_VISIBLE | FLAG_ROTATABLESPRITE | FLAG_NOLIGHT;
                    ocs.m_Pos		 = cii.m_Point + (cii.m_Plane.m_Normal * 2.0f);
                    ocs.m_Scale		 = vScale;

                    LTRotation dOrient( cii.m_Plane.m_Normal, LTVector(0.0f, 1.0f, 0.0f) );

                    strcpy(ocs.m_Filename, GetProps()->m_sImpactSpriteName);

                    pSplash->m_hObject = m_pLTClient->CreateObject(&ocs);
                    pSplash->m_scale = 0.0f;

                    LTRotation orient(dRot);
                    m_pLTClient->SetObjectRotation(pSplash->m_hObject, &orient);

                    pSplash->m_tmElapsed = 0.0f;

                    m_collSplashes.AddTail(pSplash);

                    // Destroy this object

                    m_pLTClient->RemoveObject(pSprite->m_hObject);

                    // Delete the sprite

                    pDelNode = pNode;
                }
            }
        }

        pNode = pNode->m_pNext;

        if (pDelNode) m_collSprites.Remove(pDelNode);
    }

    // Update our splashes

    CLinkListNode<SPLASH *> *pSplashNode = m_collSplashes.GetHead();

    while (pSplashNode)
    {
        CLinkListNode<SPLASH *> *pDelNode = NULL;

        SPLASH *pSplash = pSplashNode->m_Data;

        //update the elapsed time on the splash
        pSplash->m_tmElapsed += tmFrameTime;

        // Calculate the new scale

        float scale = GetProps()->m_fImpactScale1 + ((GetProps()->m_fImpactScale2 - GetProps()->m_fImpactScale1) * (pSplash->m_tmElapsed / GetProps()->m_tmImpactLifespan));

        LTVector vScale(scale, scale, scale);
        m_pLTClient->SetObjectScale(pSplash->m_hObject, &vScale);

        float r, g, b, a;

        m_pLTClient->GetObjectColor(pSplash->m_hObject, &r, &g, &b, &a);

        a = (float)(int)(pSplash->m_tmElapsed / GetProps()->m_tmImpactLifespan);
        if (a < 0.0f) a = 0.0f;
        if (a > 1.0f) a = 1.0f;

        m_pLTClient->SetObjectColor(pSplash->m_hObject, r, g, b, a);

        if (pSplash->m_tmElapsed > GetProps()->m_tmImpactLifespan)
        {
            m_pLTClient->RemoveObject(pSplash->m_hObject);
            pDelNode = pSplashNode;
        }

        pSplashNode = pSplashNode->m_pNext;

        if (pDelNode) m_collSplashes.Remove(pDelNode);
    }

    // Success !!

    return true;
}
Esempio n. 22
0
void CLineSystemFX::TweakSystem()
{
    LTFLOAT fIncValue = 0.01f;
    LTBOOL bChanged = LTFALSE;

    LTVector vScale;
	vScale.Init();

    uint32 dwPlayerFlags = g_pPlayerMgr->GetPlayerFlags();

	// Move faster if running...

	if (dwPlayerFlags & BC_CFLG_RUN)
	{
		fIncValue = .5f;
	}

	// Move Red up/down...

	if ((dwPlayerFlags & BC_CFLG_FORWARD) || (dwPlayerFlags & BC_CFLG_REVERSE))
	{
		fIncValue = dwPlayerFlags & BC_CFLG_FORWARD ? fIncValue : -fIncValue;

        m_cs.vMinVel.y += (LTFLOAT)(fIncValue * 101.0);
        m_cs.vMaxVel.y += (LTFLOAT)(fIncValue * 101.0);
		//m_cs.vColor1
		//m_cs.vColor2

        bChanged = LTTRUE;
	}


	// Add/Subtract number of lines per second

	if ((dwPlayerFlags & BC_CFLG_STRAFE_RIGHT) || (dwPlayerFlags & BC_CFLG_STRAFE_LEFT))
	{
		fIncValue = dwPlayerFlags & BC_CFLG_STRAFE_RIGHT ? fIncValue : -fIncValue;
        m_cs.fLinesPerSecond += (LTFLOAT)(fIncValue * 101.0);

		m_cs.fLinesPerSecond = m_cs.fLinesPerSecond < 0.0f ? 0.0f :
			(m_cs.fLinesPerSecond > MAX_LINES_PER_SECOND ? MAX_LINES_PER_SECOND : m_cs.fLinesPerSecond);

        bChanged = LTTRUE;
	}


	// Change line length...

	if ((dwPlayerFlags & BC_CFLG_JUMP) || (dwPlayerFlags & BC_CFLG_DUCK))
	{
		fIncValue = dwPlayerFlags & BC_CFLG_DUCK ? -fIncValue : fIncValue;

		// Adjust length and slope of lines...

		m_cs.fLineLength += (fIncValue*2.0f);

		m_vStartOffset.y = m_cs.fLineLength / 2.0f;
		m_vEndOffset.y	 = -m_cs.fLineLength / 2.0f;

		float fVal = (float)fabs(m_cs.vMaxVel.y);

		if (fVal > 0.0)
		{
			m_vEndOffset.x = (m_cs.fLineLength * (g_vWorldWindVel.x / fVal));
		}

		if (fVal > 0.0)
		{
			m_vEndOffset.z = (m_cs.fLineLength * (g_vWorldWindVel.z / fVal));
		}

        bChanged = LTTRUE;
	}


	if (bChanged)
	{
		g_pGameClientShell->CSPrint("Lines per second: %.2f", m_cs.fLinesPerSecond);
		g_pGameClientShell->CSPrint("Line length: %.2f", m_vStartOffset.y - m_vEndOffset.y);
		g_pGameClientShell->CSPrint("Velocity: %.2f", m_cs.vMinVel.y);
	}
}
Esempio n. 23
0
//*
// ----------------------------------------------------------------------- //
// Returns the vector that the physics would have the object move by.
// ----------------------------------------------------------------------- //
void CalcMotion
(
    MotionInfo* pInfo,
    LTObject*   pObj,           //the object
    LTVector&   dr,             //displacement
    LTVector&   v,              //velocity
    LTVector&   a,              //acceleration
    const bool  bApplyGravity,
    const float dt              //time step
)
{
	LTVector velocityDelta, accelDelta;
	LTVector q, slopeVel, slopeAccel, vel;
	const LTVector *n;
	LTVector objectNormal, vTemp, vTemp2;

	float fExp;
	float timeIntegral;
	float velocityMagSqr, accelMagSqr;
	LTBOOL bFriction;

	bFriction = LTFALSE;
	timeIntegral = dt * dt * 0.5f;	
	velocityMagSqr = v.MagSqr();
	accelMagSqr = a.MagSqr();

	// [KLS - 3/12/02] - Added support for per-object force override...

	LTVector vForce = pObj->GetGlobalForceOverride();
	
	// If the global force override is zero, use the MotionInfo force...

	if (LTVector(0.0, 0.0, 0.0) == vForce)
	{
		vForce = pInfo->m_Force;
	}

	/* 
	// Debug variables
	LTVector vOldAccel, vOldVel, vOldPos;
	vOldAccel = a;
	vOldVel = v;
	vOldPos = pObj->GetPos();
	//*/

	// Stop objects that are moving very slowly...
	if(velocityMagSqr < 0.1f )
	{
		v.Init();
		velocityMagSqr = 0;
	}

	if( accelMagSqr < 0.1f )
	{
		a.Init();
		accelMagSqr = 0;
	}

	// Zero out the displacement to start with.
	dr.Init();

	// Update objects affected by gravity...
	if(bApplyGravity)
	{
		// Add friction to objects standing on something...
		if(pObj->m_pStandingOn)
		{
			// Try to disable their physics.
			if( velocityMagSqr < 0.1f && accelMagSqr < 0.1f )
			{
				pObj->m_Velocity.Init();
				pObj->m_Acceleration.Init();
				pObj->m_InternalFlags &= ~IFLAG_APPLYPHYSICS;
				return;
			}
			else
			{
				// Check if object on world geometry...
				if( pObj->m_pNodeStandingOn )
				{
					// Calculate vector parallel to plane...
					n = &pObj->m_pNodeStandingOn->GetPlane()->m_Normal;
				}
				else
				{
					// Object standing on another object, so assume opposite to gravity...
					n = &objectNormal;
					objectNormal = -pInfo->m_UnitForce;
				}

				// Calculate the acceleration including the force
				LTVector vAccelWithForce = a + vForce;

				// If we're on a slope that's at enough of an angle, allow it to slide
				LTVector vForceDir = vForce;
				vForceDir.Norm();
				if (vForceDir.Dot(*n) > pInfo->m_SlideRatio)
				{
					float fAccelMag = vAccelWithForce.Mag();
					a = vAccelWithForce - *n * n->Dot(vAccelWithForce);

					// Don't allow it to accelerate up the slope..
					float fAccelDotForce = a.Dot(vForceDir);
					if (fAccelDotForce < 0.0f)
					{
						a -= vForceDir * fAccelDotForce;
					}
					
					a.Norm(fAccelMag);

					// dsi_ConsolePrint("Steep");
				}				
				else
				{
					// Figure out what our new velocity would be if only the force was used (i.e. are they jumping?)
					LTVector vNewVel = v + vForce * dt;
					// If we're going to be moving away from the plane, use the full force
					if (vNewVel.Dot(*n) > 0.01f)
					{
						a = vAccelWithForce;
						// dsi_ConsolePrint("Jump");
					}
					// If the acceleration without the force isn't moving into the surface, project it there
					else if (a.Dot(*n) > 0.01f)
					{
						float fAccelMag = a.Mag();
						a -= *n * (n->Dot(a) + 1.0f);
						a.Norm(fAccelMag);

						bFriction = LTTRUE;

						// dsi_ConsolePrint("Downhill");
					}
					else
					{
						bFriction = LTTRUE;

						// dsi_ConsolePrint("Walk");
					}
				}
			}
		}
		// Otherwise just apply gravity
		else
		{
			a += vForce;
			// dsi_ConsolePrint("Fall");
		}
	}
	// If there's no gravity and they aren't moving, then disable their physics
	else if( velocityMagSqr < 0.1f && accelMagSqr < 0.1f )
	{
		pObj->m_Velocity.Init();
		pObj->m_Acceleration.Init();
		pObj->m_InternalFlags &= ~IFLAG_APPLYPHYSICS;
		return;
	}

	// If friction
	// new velocity is given by:		v = ( a / k ) + ( v_0 - a / k ) * exp( -k * t )
	// new position is given by:		x = x_0 + ( a / k ) * t + ( k * v_0 - a ) * ( 1 - exp( -k * t )) / k^2
	if( bFriction && pObj->m_FrictionCoefficient > 0.0f )
	{
		// Velocity...
		fExp = ( float )exp( -pObj->m_FrictionCoefficient * dt );
		vTemp = a / pObj->m_FrictionCoefficient;
		vTemp2 = v - vTemp;
		vTemp2 *= fExp;
		vel = vTemp2 + vTemp;

		// Position delta...
		dr = vTemp * dt;
		vTemp = v * pObj->m_FrictionCoefficient;
		vTemp -= a;
		vTemp *= (( 1.0f - fExp ) / pObj->m_FrictionCoefficient / pObj->m_FrictionCoefficient);
		dr += vTemp;
		pObj->m_Velocity = vel;
		v = pObj->m_Velocity;
	}
	// If no friction
	// new velocity is given by:	v = v_0 + a * t
	// new position is given by:	x = x_0 + v_0 * t + .5 * a * t^2
	else
	{
		// Find the change in velocity...
		velocityDelta = a * dt;

		// Position delta...
		dr = v * dt;

		vTemp = a * (timeIntegral * 0.5f);
		dr += vTemp;

		// Add the final velocity to the new velocity.
		pObj->m_Velocity += velocityDelta;
		v = pObj->m_Velocity;
	}

	/*
	// Show debug information, filtering out the server-side player object
	if(bApplyGravity)
	{
		dsi_ConsolePrint("Old - A:<%7.1f,%7.1f,%7.1f> V:<%7.1f,%7.1f,%7.1f> P:<%7.1f,%7.1f,%7.1f>",
			VEC_EXPAND(vOldAccel), VEC_EXPAND(vOldVel), VEC_EXPAND(vOldPos));

		LTVector vNewAccel, vNewVel, vNewPos;
		vNewAccel = a;
		vNewVel = v;
		vNewPos = vOldPos + dr;

		dsi_ConsolePrint("New   - A:<%7.1f,%7.1f,%7.1f> V:<%7.1f,%7.1f,%7.1f> P:<%7.1f,%7.1f,%7.1f>",
			VEC_EXPAND(vNewAccel), VEC_EXPAND(vNewVel), VEC_EXPAND(vNewPos));
	}
	//*/

	return;
}
Esempio n. 24
0
//given an animation and a keyframe, this will find the dims that encompass the
//model
bool CDimensionsDlg::FindAnimDims(Model* pModel, uint32 nAnim, uint32 nKeyFrame, LTVector& vDims)
{
    //clear out the dims to start out with in case we fail
    vDims.Init();

    AnimTracker tracker, *pTracker;
    tracker.m_TimeRef.Init(pModel, nAnim, nKeyFrame, nAnim, nKeyFrame, 0.0f);

    AnimInfo *pAnim = &pModel->m_Anims[nAnim];

    pTracker = &tracker;//pAnim->m_pAnim;

    static CMoArray<TVert> tVerts;

    // Use the model code to setup the vertices.

    int nTrackers = 1;
    nTrackers = DMIN(nTrackers, MAX_GVP_ANIMS);

    GVPStruct gvp;

    gvp.m_nAnims = 0;
    for(int i = 0; i < nTrackers; i++)
    {
        gvp.m_Anims[i] = pTracker[i].m_TimeRef;
        gvp.m_nAnims++;
    }

    LTMatrix m;
    m.Identity();

    int nWantedVerts = pModel->GetTotalNumVerts() * 2;
    if(tVerts.GetSize() < nWantedVerts)
    {
        if(!tVerts.SetSize(nWantedVerts))
            return false;
    }

    gvp.m_VertexStride = sizeof(TVert);
    gvp.m_Vertices = tVerts.GetArray();
    gvp.m_BaseTransform = m;
    gvp.m_CurrentLODDist = 0;

    if (AlternateGetVertexPositions(pModel, &gvp, true, false, false, false))
    {
        LTVector vMax(0, 0, 0);

        for (i = 0; i < pModel->GetTotalNumVerts(); i ++)
        {
            TVert v = tVerts[i];

            if (fabs(v.m_vPos.x) > vMax.x) vMax.x = (float)fabs(v.m_vPos.x);
            if (fabs(v.m_vPos.y) > vMax.y) vMax.y = (float)fabs(v.m_vPos.y);
            if (fabs(v.m_vPos.z) > vMax.z) vMax.z = (float)fabs(v.m_vPos.z);
        }

        // Setup the new dims....

        //round max up to the .1 decimal place
        vMax.x = (float)(ceil(vMax.x * 10.0) / 10.0);
        vMax.y = (float)(ceil(vMax.y * 10.0) / 10.0);
        vMax.z = (float)(ceil(vMax.z * 10.0) / 10.0);

        vDims = vMax;

        return true;
    }

    //failure
    return false;
}
Esempio n. 25
0
// Wrap the textures, starting at a poly index
void CRVTrackerTextureWrap::WrapTexture(CTWPolyInfo *pPoly, const CVector &vWrapDir, CTextExtents &cExtents) const
{
	// Mark this poly as wrapped
	pPoly->m_bTouched = TRUE;

	CTexturedPlane& Texture = pPoly->m_pPoly->GetTexture(GetCurrTexture());

	// Get the texture space
	LTVector vWrapO = Texture.GetO();
	LTVector vWrapP = Texture.GetP();
	LTVector vWrapQ = Texture.GetQ();

	// Get the texture offset projections
	float fWrapOdotP = vWrapO.Dot(vWrapP);
	float fWrapOdotQ = vWrapO.Dot(vWrapQ);

	// Update the texturing extents
	for (uint32 nExtentLoop = 0; nExtentLoop < pPoly->m_aEdges.GetSize(); ++nExtentLoop)
	{
		LTVector vEdgePt = pPoly->m_aEdges[nExtentLoop]->m_aPt[0];

		float fCurU = vWrapP.Dot(vEdgePt) - fWrapOdotP;
		float fCurV = vWrapQ.Dot(vEdgePt) - fWrapOdotQ;

		cExtents.m_fMinU = LTMIN(fCurU, cExtents.m_fMinU);
		cExtents.m_fMaxU = LTMAX(fCurU, cExtents.m_fMaxU);
		cExtents.m_fMinV = LTMIN(fCurV, cExtents.m_fMinV);
		cExtents.m_fMaxV = LTMAX(fCurV, cExtents.m_fMaxV);
	}

	CMoArray<uint32> aNeighbors;
	CMoArray<float> aDots;

	// Insert the neighbors into a list in dot-product order
	for (uint32 nNeighborLoop = 0; nNeighborLoop < pPoly->m_aNeighbors.GetSize(); ++nNeighborLoop)
	{
		CTWPolyInfo *pNeighbor = pPoly->m_aNeighbors[nNeighborLoop];

		// Skip edges that don't have a neighbor
		if (!pNeighbor)
			continue;

		// Skip neighbors that are already wrapped
		if (pNeighbor->m_bTouched)
			continue;

		// Get our dot product
		float fCurDot = vWrapDir.Dot(pPoly->m_aEdges[nNeighborLoop]->m_Plane.m_Normal);

		if ((m_bRestrictWalkDir) && (fCurDot < 0.707f))
			continue;

		// Mark this neighbor as touched (to avoid later polygons pushing it onto the stack)
		pNeighbor->m_bTouched = TRUE;

		// Insert it into the list
		for (uint32 nInsertLoop = 0; nInsertLoop < aNeighbors.GetSize(); ++nInsertLoop)
		{
			if (fCurDot > aDots[nInsertLoop])
				break;
		}
		aDots.Insert(nInsertLoop, fCurDot);
		aNeighbors.Insert(nInsertLoop, nNeighborLoop);
	}

	// Recurse through its neighbors
	for (uint32 nWrapLoop = 0; nWrapLoop < aNeighbors.GetSize(); ++nWrapLoop)
	{
		CTWPolyInfo *pNeighbor = pPoly->m_aNeighbors[aNeighbors[nWrapLoop]];
		CTWEdgeInfo *pEdge = pPoly->m_aEdges[aNeighbors[nWrapLoop]];

		//////////////////////////////////////////////////////////////////////////////
		// Wrap this neighbor

		// Create a matrix representing the basis of the polygon in relation to this edge
		LTMatrix mPolyBasis;
		mPolyBasis.SetTranslation(0.0f, 0.0f, 0.0f);
		mPolyBasis.SetBasisVectors(&pEdge->m_vDir, &pPoly->m_pPoly->m_Plane.m_Normal, &pEdge->m_Plane.m_Normal);

		// Create a new basis for the neighbor polygon
		LTMatrix mNeighborBasis;
		LTVector vNeighborForward;
		vNeighborForward = pNeighbor->m_pPoly->m_Plane.m_Normal.Cross(pEdge->m_vDir);
		// Just to be sure..
		vNeighborForward.Norm();
		mNeighborBasis.SetTranslation(0.0f, 0.0f, 0.0f);
		mNeighborBasis.SetBasisVectors(&pEdge->m_vDir, &pNeighbor->m_pPoly->m_Plane.m_Normal, &vNeighborForward);

		// Create a rotation matrix from here to there
		LTMatrix mRotation;
		mRotation = mNeighborBasis * ~mPolyBasis;

		// Rotate the various vectors
		LTVector vNewP;
		LTVector vNewQ;
		LTVector vNewDir;

		mRotation.Apply3x3(vWrapP, vNewP);
		mRotation.Apply3x3(vWrapQ, vNewQ);
		mRotation.Apply3x3(vWrapDir, vNewDir);

		// Rotate the texture basis if we're following a path
		if (m_nWrapStyle == k_WrapPath)
		{
			LTVector vNeighborEdgeDir;
			if (GetSimilarEdgeDir(pNeighbor, vNewDir, vNeighborEdgeDir, 0.707f))
			{
				LTMatrix mRotatedNeighbor;
				LTVector vNeighborRight;
				vNeighborRight = vNeighborEdgeDir.Cross(pNeighbor->m_pPoly->m_Plane.m_Normal);
				vNeighborRight.Norm();
				// Make sure we're pointing the right way...
				if (vNeighborRight.Dot(pEdge->m_vDir) < 0.0f)
					vNeighborRight = -vNeighborRight;
				mRotatedNeighbor.SetTranslation(0.0f, 0.0f, 0.0f);
				mRotatedNeighbor.SetBasisVectors(&vNeighborRight, &pNeighbor->m_pPoly->m_Plane.m_Normal, &vNeighborEdgeDir);
				// Build a basis based on an edge from the current polygon 
				LTVector vBestPolyEdge;
				GetSimilarEdgeDir(pPoly, vWrapDir, vBestPolyEdge);
				LTVector vPolyRight = vBestPolyEdge.Cross(pNeighbor->m_pPoly->m_Plane.m_Normal);
				vPolyRight.Norm();
				// Make sure we're pointing the right way...
				if (vPolyRight.Dot(pEdge->m_vDir) < 0.0f)
					vPolyRight = -vPolyRight;
				// Build the poly edge matrix
				LTMatrix mPolyEdgeBasis;
				mPolyEdgeBasis.SetTranslation(0.0f, 0.0f, 0.0f);
				mPolyEdgeBasis.SetBasisVectors(&vPolyRight, &pNeighbor->m_pPoly->m_Plane.m_Normal, &vBestPolyEdge);

				// Get a matrix from here to there
				LTMatrix mRotator;
				mRotator = mRotatedNeighbor * ~mPolyEdgeBasis;
				// Rotate the texture basis
				mRotator.Apply3x3(vNewP);
				mRotator.Apply3x3(vNewQ);
				// And use the new edge as the new direction
				vNewDir = vNeighborEdgeDir;
			}

			// Remove skew from vNewP/vNewQ
			if ((float)fabs(vNewP.Dot(vNewQ)) > 0.001f)
			{
				float fMagP = vNewP.Mag();
				float fMagQ = vNewQ.Mag();
				vNewQ *= 1.0f / fMagQ;
				vNewP -= vNewQ * vNewQ.Dot(vNewP);
				vNewP.Norm(fMagP);
				vNewQ *= fMagQ;
			}
		}

		// Get the first edge point..
		CVector vEdgePt = pEdge->m_aPt[0];

		// Calculate the texture coordinate at this point
		float fWrapU = vWrapP.Dot(vEdgePt) - fWrapOdotP;
		float fWrapV = vWrapQ.Dot(vEdgePt) - fWrapOdotQ;

		// Build the new offset
		float fNewOdotP = vNewP.Dot(vEdgePt) - fWrapU;
		float fNewOdotQ = vNewQ.Dot(vEdgePt) - fWrapV;
		LTVector vNewO;
		vNewO.Init();
		float fNewPMag = vNewP.MagSqr();
		if (fNewPMag > 0.0f)
			vNewO += vNewP * (fNewOdotP / fNewPMag);
		float fNewQMag = vNewQ.MagSqr();
		if (fNewQMag > 0.0f)
			vNewO += vNewQ * (fNewOdotQ / fNewQMag);

		pNeighbor->m_pPoly->SetTextureSpace(GetCurrTexture(), vNewO, vNewP, vNewQ);

		// Recurse into this neighbor
		WrapTexture(pNeighbor, vNewDir, cExtents);
	}
}
Esempio n. 26
0
void CLaserBeam::Update(LTVector &vBeamStartPos, const LTRotation* pRDirRot,
                        LTBOOL b3rdPerson, LTBOOL bDetect)
{
	if (!m_bOn) return;

	// Calculate beam position...

	HOBJECT hCamera = g_pPlayerMgr->GetCamera();
	if (!hCamera) return;

    HLOCALOBJ hPlayerObj = g_pLTClient->GetClientObject();
	if (!hPlayerObj) return;

    HOBJECT hFilterList[] = {hPlayerObj, g_pPlayerMgr->GetMoveMgr()->GetObject(), LTNULL};

	IntersectQuery qInfo;
	IntersectInfo iInfo;

    LTVector vPos(0, 0, 0);
    LTRotation rRot;

    LTVector vU, vR, vF;

	if (pRDirRot && b3rdPerson)
	{
		vPos = vBeamStartPos;

		vU = pRDirRot->Up();
		vR = pRDirRot->Right();
		vF = pRDirRot->Forward();
	}
	else
	{
		g_pLTClient->GetObjectRotation(hCamera, &rRot);
		g_pLTClient->GetObjectPos(hCamera, &vPos);

		vU = rRot.Up();
		vR = rRot.Right();
		vF = rRot.Forward();

		if (g_cvarLaserBeamDebug.GetFloat() == 0.0f)
		{
			vBeamStartPos += vPos;
		}
		else if (g_cvarLaserBeamDebug.GetFloat() == 1.0f)
		{
			vBeamStartPos = vPos;
		}
		else if (pRDirRot)
		{
			vU = pRDirRot->Up();
			vR = pRDirRot->Right();
			vF = pRDirRot->Forward();
			vBeamStartPos = vBeamStartPos;
		}

	}


    LTVector vEndPos = vPos + (vF * 10000.0f);

	qInfo.m_From = vPos;
	qInfo.m_To   = vEndPos;

	qInfo.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID;
	qInfo.m_FilterFn = ObjListFilterFn;
	qInfo.m_pUserData = hFilterList;

    if (g_pLTClient->IntersectSegment(&qInfo, &iInfo))
	{
		vEndPos = iInfo.m_Point;
	}


	// Show the light beam...

    LTVector vColor = LTVector(GetRandom(235.0f, 255.0f), GetRandom(35.0f, 55.0f), GetRandom(35.0f, 55.0f));;

    LTFLOAT fAlpha = g_cvarLaserBeamAlpha.GetFloat();

	if (iInfo.m_hObject && bDetect)
	{
        uint32 dwUsrFlgs = 0;
        g_pCommonLT->GetObjectFlags(iInfo.m_hObject, OFT_User, dwUsrFlgs);

		if (dwUsrFlgs & USRFLG_CHARACTER)
		{
			fAlpha	= 0.95f;
			vColor.Init(GetRandom(35.0f, 55.0f), GetRandom(235.0f, 255.0f), GetRandom(35.0f, 55.0f));;
		}
	}

    LTFLOAT fWidth = g_cvarLaserBeamThickness.GetFloat();
	fWidth = b3rdPerson ? fWidth*2.0f : fWidth;

	vBeamStartPos += (vF * g_cvarLaserBeamFOffset.GetFloat());
	vBeamStartPos += (vR * g_cvarLaserBeamROffset.GetFloat());
	vBeamStartPos += (vU * g_cvarLaserBeamUOffset.GetFloat());

	PLFXCREATESTRUCT pls;

	if (g_cvarLaserBeamDebug.GetFloat() >= 0.0f)
	{
        // g_pLTClient->CPrint("StartPos = %.2f, %.2f, %.2f", VEC_EXPAND(vBeamStartPos));
        // g_pLTClient->CPrint("EndPos = %.2f, %.2f, %.2f", VEC_EXPAND(vEndPos));
	}

	pls.vStartPos			= vBeamStartPos;
	pls.vEndPos				= vEndPos;
	pls.vInnerColorStart	= vColor;
	pls.vInnerColorEnd		= pls.vInnerColorStart;
    pls.vOuterColorStart    = LTVector(0, 0, 0);
    pls.vOuterColorEnd      = LTVector(0, 0, 0);
	pls.fAlphaStart			= fAlpha;
	pls.fAlphaEnd			= fAlpha;
	pls.fMinWidth			= 0;
	pls.fMaxWidth			= fWidth;
	pls.fMinDistMult		= 1.0f;
	pls.fMaxDistMult		= 1.0f;
	pls.fLifeTime			= 1.0f;
	pls.fAlphaLifeTime		= 1.0f;
	pls.fPerturb			= 0.0f;
    pls.bAdditive           = LTTRUE;
    pls.bAlignFlat          = b3rdPerson ? LTFALSE : LTTRUE;
	pls.nWidthStyle			= PLWS_CONSTANT;
	pls.nNumSegments		= (int)g_cvarLaserBeamNumSegments.GetFloat();

	if (m_LightBeam.HasBeenDrawn())
	{
		// Keep the light beam in the vis list...

		m_LightBeam.SetPos(vBeamStartPos);

		// Hide the beam in portals if 1st person...Also set flag really
		// close to true...

        uint32 dwFlags2, dwFlags;

		dwFlags = m_LightBeam.GetFlags();
		dwFlags2 = m_LightBeam.GetFlags2();

		if (b3rdPerson)
		{
			dwFlags &= ~FLAG_REALLYCLOSE;
		}
		else
		{
			if (g_cvarLaserBeamDebug.GetFloat() > 1.0f)
			{
				dwFlags |= FLAG_REALLYCLOSE;
                pls.bUseObjectRotation = LTTRUE;
			}
		}

		m_LightBeam.SetFlags(dwFlags);
		m_LightBeam.SetFlags2(dwFlags2);

		m_LightBeam.ReInit(&pls);
	}
	else
	{
		m_LightBeam.Init(&pls);
        m_LightBeam.CreateObject(g_pLTClient);
	}


	m_LightBeam.Update();
}
Esempio n. 27
0
void CGrenade::HandleImpact(HOBJECT hObj)
{
	if (!g_vtGrenadeDampenPercent.IsInitted())
	{
        g_vtGrenadeDampenPercent.Init(g_pLTServer, "GrenadeDampenPercent", LTNULL, DEFAULT_GRENADE_DAMPEN_PERCENT);
	}

	if (!g_vtGrenadeMinVelMag.IsInitted())
	{
        g_vtGrenadeMinVelMag.Init(g_pLTServer, "GrenadeMinVelMag", LTNULL, DEFAULT_GRENADE_MIN_VELOCITY);
	}


    LTVector vVel;
    g_pLTServer->GetVelocity(m_hObject, &vVel);


	// See if we are impacting on liquid...

    LTBOOL bEnteringLiquid = LTFALSE;
    uint16 code;
    if (g_pLTServer->GetContainerCode(hObj, &code))
	{
		if (IsLiquid((ContainerCode)code))
		{
            bEnteringLiquid = LTTRUE;
		}
	}


	CollisionInfo info;
    g_pLTServer->GetLastCollision(&info);


	// Do the bounce, if the object we hit isn't liquid...

	if (!bEnteringLiquid)
	{
		vVel += (info.m_vStopVel * 2.0f);
	}


	// Dampen the grenade's new velocity based on the surface type...

    LTFLOAT fDampenPercent = g_vtGrenadeDampenPercent.GetFloat();

	m_eLastHitSurface = GetSurfaceType(info);
	SURFACE* pSurf = g_pSurfaceMgr->GetSurface(m_eLastHitSurface);
	if (pSurf)
	{
		// Play a bounce sound (based on the surface type) if one isn't
		// already playing...

		if ( ShouldPlayBounceSound(pSurf) )
		{
			// Only play one sound at a time...

			if (m_hBounceSnd)
			{
                g_pLTServer->KillSound(m_hBounceSnd);
                m_hBounceSnd = LTNULL;
			}

            uint32 dwFlags = PLAYSOUND_GETHANDLE | PLAYSOUND_TIME;

			int nVolume	= IsLiquid(m_eContainerCode) ? 50 : 100;

            LTVector vPos;
            g_pLTServer->GetObjectPos(m_hObject, &vPos);

			m_hBounceSnd = g_pServerSoundMgr->PlaySoundFromPos(vPos, (char*)GetBounceSound(pSurf),
				pSurf->fGrenadeSndRadius, SOUNDPRIORITY_MISC_MEDIUM, dwFlags, nVolume);
		}

		fDampenPercent = (1.0f - pSurf->fHardness);
	}

	fDampenPercent = fDampenPercent > 1.0f ? 1.0f : (fDampenPercent < 0.0f ? 0.0f : fDampenPercent);

	vVel *= (1.0f - fDampenPercent);


	// See if we should come to a rest...

    LTVector vTest = vVel;
	vTest.y = 0.0f;

	if (vTest.Mag() < g_vtGrenadeMinVelMag.GetFloat())
	{
		// If we're on the ground (or an object), stop movement...

		CollisionInfo standingInfo;
        g_pLTServer->GetStandingOn(m_hObject, &standingInfo);

		CollisionInfo* pInfo = standingInfo.m_hObject ? &standingInfo : &info;

		if (pInfo->m_hObject)
		{
			// Don't stop on walls...

			if (pInfo->m_Plane.m_Normal.y > 0.75f)
			{
				vVel.Init();

				// Turn off gravity, solid, and touch notify....

                uint32 dwFlags = g_pLTServer->GetObjectFlags(m_hObject);
				dwFlags &= ~(FLAG_GRAVITY | FLAG_TOUCH_NOTIFY | FLAG_SOLID);

                g_pLTServer->SetObjectFlags(m_hObject, dwFlags);

				// Rotate to rest...

				RotateToRest();
			}
		}
	}


	// Reset rotation velocities due to the bounce...

	ResetRotationVel(&vVel, pSurf);


	// We need to subtact this out because the engine will add it back in,
	// kind of a kludge but necessary...

	vVel -= info.m_vStopVel;


    g_pLTServer->SetVelocity(m_hObject, &vVel);

	m_cBounces++;
}