Exemplo n.º 1
0
//given a capsule specified with a transform, two points, and a radius, this will approximate how much is submerged
//and distribute that force to the appropriate points on the capsule
static bool ApplyCapsuleBuoyancy(const LTVector& vPt1, const LTVector& vPt2, float fLength, float fRadius, 
								 const LTPlane& WSPlane, float& fVolume, LTVector& vApplyAt,
								 float& fSurfaceArea)
{
	//convert the capsule to an OBB and apply it
	
	//determine information about the main axis
	LTVector vMainAxis = vPt2 - vPt1;
	LTASSERT( fLength > 0.0f, "Invalid capsule length." );
	LTVector vUnitAxis = vMainAxis / fLength;

	//we can now build up a rotation given the plane normal and the axis to build our transform
	LTVector vUp = WSPlane.Normal();
	if(fabsf(vUp.Dot(vUnitAxis)) > 0.99f)
	{
		//too close to use, built an arbitrary orthonormal
		vUp = vUnitAxis.BuildOrthonormal();
	}

	LTMatrix3x4 mTemp;
	LTVector vRight = vUnitAxis.Cross(vUp);
	vRight.Normalize( );
	LTVector vTrueUp = vRight.Cross( vUnitAxis );
	mTemp.SetBasisVectors(vRight, vTrueUp, vUnitAxis);

	LTRotation rRot;
	rRot.ConvertFromMatrix(mTemp);

	//now we can form our transform
	LTRigidTransform tTransform((vPt1 + vPt2) * 0.5f, rRot);
	LTVector vHalfDims(fRadius, fRadius, fLength * 0.5f + fRadius);

	return ApplyOBBBuoyancy(tTransform, vHalfDims, WSPlane, fVolume, vApplyAt, fSurfaceArea);
}
Exemplo n.º 2
0
void CRagDollInPlaneConstraint::Apply(uint32 nPosIndex)
{
	//find the plane pivot point (the connection between both points forming the first plane)
	LTVector& vPivot = m_pPlaneCenter->m_vPosition[nPosIndex];

	//find the vector that goes from the pivot point to the hinge point
	LTVector vToHinge = m_pHinge->m_vPosition[nPosIndex] - vPivot;
	LTVector vToOther = m_pPlaneOther->m_vPosition[nPosIndex] - vPivot;

	//find the plane normal
	LTVector vPlaneNormal = vToOther.Cross(vToHinge);
	vPlaneNormal.Normalize();

	vPlaneNormal = vToHinge.Cross(vPlaneNormal) * m_fNormalScale;
	vPlaneNormal.Normalize();

	//move the point into the plane
	LTVector& vConstrain = m_pConstrain->m_vPosition[nPosIndex];

	float fDot = vPlaneNormal.Dot(vConstrain - vPivot);

	if(fDot < -m_fTolerance)
	{
		fDot += m_fTolerance;
		vConstrain -= vPlaneNormal * fDot;
	}
	else if(fDot > m_fTolerance)
	{
		fDot -= m_fTolerance;
		vConstrain -= vPlaneNormal * fDot;
	}

	//success
}
Exemplo n.º 3
0
void DebugLineSystem::AddArrow( const LTVector & vStart, const LTVector & vEnd,
								const DebugLine::Color & color /* = Color::White */,
								uint8 nAlpha /* = 255 */ )
{
	const float fHeadSize = 4.0f;
	LTVector vStartToEnd = vEnd - vStart;
	float fLen = vStartToEnd.Mag();
	if( vStartToEnd != LTVector::GetIdentity() )
	{
		vStartToEnd.Normalize();
	}

	AddLine( vStart, vEnd, color, nAlpha);

	LTVector vArrow = vStart + ( ( fLen * 0.9f ) * vStartToEnd );

	LTVector vUp( 0.f, 1.f, 0.f );
	LTVector vNorm;
	if( vStartToEnd != vUp )
	{
		vNorm = vStartToEnd.Cross( vUp );
	}
	else {
		vNorm = LTVector( 1.f, 0.f, 0.f );
	}

	vNorm *= ( fHeadSize/2.0f );
	AddLine( vArrow - vNorm, vArrow + vNorm, color, nAlpha);

	AddLine( vArrow + vNorm, vEnd, color, nAlpha);
	AddLine( vArrow - vNorm, vEnd, color, nAlpha);
}
Exemplo n.º 4
0
bool FindNearestPointOnLine( const LTVector& l0, const LTVector& l1, const LTVector& vPos, LTVector* pvPosNearest )
{
	// Sanity check.

	if( !pvPosNearest )
	{
		return false;
	}

	// Find the line's normal.

	LTVector vUp( 0.f, 1.f, 0.f );
	LTVector vDir = l1 - l0;
	vDir.Normalize();

	LTVector vNormal = vDir.Cross( vUp );
	vNormal.Normalize();

	// Find the nearest intersection point between the point and the line.

	LTVector vRay0 = vPos + ( vNormal * 100000.f );
	LTVector vRay1 = vPos - ( vNormal * 100000.f );

	return ( kRayIntersect_Failure != RayIntersectLineSegment( l0, l1, vRay0, vRay1, true, pvPosNearest ) );
}
void COccluder_Frustum::InitFrustum(const ViewParams& Params)
{
	// Clear!
	Init();

	// Get the points of the near plane in order
	const uint32 k_nNumScreenPts = 4;
	LTVector aScreenPts[k_nNumScreenPts];
	aScreenPts[0] = Params.m_ViewPoints[2];
	aScreenPts[1] = Params.m_ViewPoints[3];
	aScreenPts[2] = Params.m_ViewPoints[1];
	aScreenPts[3] = Params.m_ViewPoints[0];

	// Gimmie some room
	m_aEdgePlanes.reserve(k_nNumScreenPts);
	m_aWorldEdgePlanes.reserve(k_nNumScreenPts);

	// Remember the near plane
	m_cPolyPlane = Params.m_ClipPlanes[CPLANE_NEAR_INDEX];
	m_ePolyPlaneCorner = GetAABBPlaneCorner(m_cPolyPlane.m_Normal);

	// Build the occluder
	LTVector vPrevWorld = aScreenPts[3];
	LTVector vPrevScr;
	MatVMul_H(&vPrevScr, &Params.m_FullTransform, &vPrevWorld);
	for (const LTVector *pCurVert = aScreenPts; pCurVert != &aScreenPts[k_nNumScreenPts]; ++pCurVert)
	{
		const LTVector &vNextWorld = *pCurVert;
		LTVector vNextScr;
		MatVMul_H(&vNextScr, &Params.m_FullTransform, &vNextWorld);
		float fXDiff = (vNextScr.x - vPrevScr.x);
		float fYDiff = (vNextScr.y - vPrevScr.y);
		if ((fXDiff * fXDiff + fYDiff * fYDiff) > 0.001f)
		{
			LTPlane cScreenPlane;
			LTVector vEdgeScr = vNextScr - vPrevScr;
			cScreenPlane.m_Normal.Init(vEdgeScr.y, -vEdgeScr.x, 0.0f);
			cScreenPlane.m_Normal.Normalize();
			cScreenPlane.m_Dist = cScreenPlane.m_Normal.x * vNextScr.x + cScreenPlane.m_Normal.y * vNextScr.y;

			LTPlane cWorldPlane;
			LTVector vEdgeWorld = vNextWorld - vPrevWorld;
			cWorldPlane.m_Normal = vEdgeWorld.Cross(vNextWorld - Params.m_Pos);
			cWorldPlane.m_Normal.Normalize();
			cWorldPlane.m_Dist = cWorldPlane.m_Normal.Dot(vNextWorld);

			AddPlane(cScreenPlane, cWorldPlane);
		}

		vPrevWorld = vNextWorld;
		vPrevScr = vNextScr;
	}
}
Exemplo n.º 6
0
void CRagDollAbovePlaneOnEdgeConstraint::Apply(uint32 nPosIndex)
{
	const LTVector& vPtInPlane = m_pPt1->m_vPosition[nPosIndex];

	LTVector vEdge = m_pPt2->m_vPosition[nPosIndex] - vPtInPlane;

	//we first off need to caclulate the normal of the plane
	LTVector vNormal = vEdge.Cross(m_pPt3->m_vPosition[nPosIndex] - vPtInPlane);
	vNormal.Normalize();

	//now we need to take that plane, and find the perpindicular plane that passes through the first edge
	LTVector vEdgeNormal = vNormal.Cross(vEdge) * m_fNormalScale;
	vEdgeNormal.Normalize();

	//ok, now we see if the point is above the plane
	LTVector& vConstrain = m_pConstrain->m_vPosition[nPosIndex];
	float fDot = vEdgeNormal.Dot(vConstrain - vPtInPlane);

	if(fDot < 0.0f)
	{
		vConstrain -= fDot * vEdgeNormal;
	}
}
Exemplo n.º 7
0
// The plane primitive command was called
void CRegionView::OnCreatePrimitivePlane() 
{
	// The sphere primitive dialog
	CPlanePrimitiveDlg dlg;

	//load all the defaults from the registry
	dlg.m_fWidth				= (float)::GetApp()->GetOptions().GetDWordValue("DefaultPlaneWidth", 64);
	dlg.m_fHeight				= (float)::GetApp()->GetOptions().GetDWordValue("DefaultPlaneHeight", 64);
	dlg.m_nOrientation			= ::GetApp()->GetOptions().GetDWordValue("DefaultPlaneOr", 0);
	dlg.m_nType					= ::GetApp()->GetOptions().GetDWordValue("DefaultPlaneType", 0);


	// Create the sphere primitive dialog	
	if (dlg.DoModal() == IDOK)
	{
		//determine our up and right vectors for each orientation
		LTVector vOrUp[6], vOrNormal[6];

		vOrNormal[0].Init(1.0f, 0.0f, 0.0f);	vOrUp[0].Init(0.0f, 1.0f, 0.0f);
		vOrNormal[1].Init(-1.0f, 0.0f, 0.0f);	vOrUp[1].Init(0.0f, 1.0f, 0.0f);
		vOrNormal[2].Init(0.0f, 1.0f, 0.0f);	vOrUp[2].Init(0.0f, 0.0f, 1.0f);
		vOrNormal[3].Init(0.0f, -1.0f, 0.0f);	vOrUp[3].Init(0.0f, 0.0f, 1.0f);
		vOrNormal[4].Init(0.0f, 0.0f, 1.0f);	vOrUp[4].Init(0.0f, 1.0f, 0.0f);
		vOrNormal[5].Init(0.0f, 0.0f, -1.0f);	vOrUp[5].Init(0.0f, 1.0f, 0.0f);

		//form the right vector
		LTVector vUp	= vOrUp[dlg.m_nOrientation];
		LTVector vRight = vUp.Cross(vOrNormal[dlg.m_nOrientation]);

		//now form the basis point
		LTVector vBasis = GetRegion()->m_vMarker - vRight * dlg.m_fWidth / 2.0f - vUp * dlg.m_fHeight / 2.0f;

		//determine the base point
		DoCreatePrimitivePlane(vBasis, vRight, vUp, dlg.m_fWidth, dlg.m_fHeight, (dlg.m_nType == 1));

		//save the options back out
		::GetApp()->GetOptions().SetDWordValue("DefaultPlaneWidth", (uint32)dlg.m_fWidth);
		::GetApp()->GetOptions().SetDWordValue("DefaultPlaneHeight", (uint32)dlg.m_fHeight);
		::GetApp()->GetOptions().SetDWordValue("DefaultPlaneOr", dlg.m_nOrientation);
		::GetApp()->GetOptions().SetDWordValue("DefaultPlaneType", dlg.m_nType);
	}
}
Exemplo n.º 8
0
//determines if this polygon is concave or not
bool CEditPoly::IsConcave()
{
	uint32 nNumPts = NumVerts();

	if(nNumPts <= 3)
	{
		return false;
	}

	//get the normal for this polygon
	LTVector vNormal = Normal();

	//now go through every edge
	uint32 nPrevPt = nNumPts - 1;
	for(uint32 nCurrPt = 0; nCurrPt < nNumPts; nPrevPt = nCurrPt, nCurrPt++)
	{
		//build the edge normal
		LTVector vEdge = m_pBrush->m_Points[Index(nCurrPt)] - m_pBrush->m_Points[Index(nPrevPt)];

		//find the normal
		LTVector vEdgeNorm = vNormal.Cross(vEdge);
		vEdgeNorm.Norm();

		//now run through all the other points
		for(uint32 nTestPt = 0; nTestPt < nNumPts; nTestPt++)
		{
			//ignore the points on the edge
			if((nTestPt == nCurrPt) || (nTestPt == nPrevPt))
				continue;

			//see if it is on the correct side
			if(vEdgeNorm.Dot(m_pBrush->m_Points[Index(nTestPt)] - m_pBrush->m_Points[Index(nCurrPt)]) > 0.001f)
			{
				return true;
			}
		}
	}

	return false;

}
Exemplo n.º 9
0
bool CLTBModelFX::Init(ILTClient *pClientDE, FX_BASEDATA *pBaseData, const CBaseFXProps *pProps)
{
	// Perform base class initialisation

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

	// Use the "target" Normal instead, if one was specified...

	LTVector vNorm = GetProps()->m_vNorm;

	if( pBaseData->m_vTargetNorm.LengthSquared() > MATH_EPSILON )
	{
		vNorm = pBaseData->m_vTargetNorm;
		vNorm.Normalize();
	}

	// Develop the Right and Up vectors based off the Forward...

	LTVector vR, vU;
	if( (1.0f == vNorm.y) || (-1.0f == vNorm.y) )
	{
		vR = LTVector( 1.0f, 0.0f, 0.0f ).Cross( vNorm );
	}
	else
	{
		vR = LTVector( 0.0f, 1.0f, 0.0f ).Cross( vNorm );
	}

	vU = vNorm.Cross( vR );
	m_rNormalRot = LTRotation( vNorm, vU );


	ObjectCreateStruct ocs;

	// Combine the direction we would like to face with our parents rotation...

	if( m_hParent )
	{
		m_pLTClient->GetObjectRotation( m_hParent, &ocs.m_Rotation );
	}
	else
	{
		ocs.m_Rotation = m_rCreateRot;
	}

	ocs.m_Rotation = ocs.m_Rotation * m_rNormalRot;	

	ocs.m_ObjectType		= OT_MODEL;
	ocs.m_Flags				|= pBaseData->m_dwObjectFlags |	(GetProps()->m_bShadow ? FLAG_SHADOW : 0 );
	ocs.m_Flags2			|= pBaseData->m_dwObjectFlags2;
	
	// Calculate the position with the offset in 'local' coordinate space...

	LTMatrix mMat;
	ocs.m_Rotation.ConvertToMatrix( mMat );

	m_vPos = ocs.m_Pos = m_vCreatePos + (mMat * GetProps()->m_vOffset);

	
	SAFE_STRCPY( ocs.m_Filename, GetProps()->m_szModelName );
	
	SAFE_STRCPY( ocs.m_SkinNames[0], GetProps()->m_szSkinName[0] );
	SAFE_STRCPY( ocs.m_SkinNames[1], GetProps()->m_szSkinName[1] );
	SAFE_STRCPY( ocs.m_SkinNames[2], GetProps()->m_szSkinName[2] );
	SAFE_STRCPY( ocs.m_SkinNames[3], GetProps()->m_szSkinName[3] );
	SAFE_STRCPY( ocs.m_SkinNames[4], GetProps()->m_szSkinName[4] );
	
	SAFE_STRCPY( ocs.m_RenderStyleNames[0], GetProps()->m_szRenderStyle[0] );
	SAFE_STRCPY( ocs.m_RenderStyleNames[1], GetProps()->m_szRenderStyle[1] );
	SAFE_STRCPY( ocs.m_RenderStyleNames[2], GetProps()->m_szRenderStyle[2] );
	SAFE_STRCPY( ocs.m_RenderStyleNames[3], GetProps()->m_szRenderStyle[3] );

	m_hObject = m_pLTClient->CreateObject(&ocs);
	if( !m_hObject ) 
		return LTFALSE;

	ILTModel		*pLTModel = m_pLTClient->GetModelLT();
	ANIMTRACKERID	nTracker;
	
	pLTModel->GetMainTracker( m_hObject, nTracker );

	//setup the animation if the user specified one
	if( strlen(GetProps()->m_szAnimName) > 0)
	{
		//ok, we need to set this
		HMODELANIM hAnim = m_pLTClient->GetAnimIndex(m_hObject, GetProps()->m_szAnimName);

		if(hAnim != INVALID_MODEL_ANIM)
		{
			//ok, lets set this animation
			pLTModel->SetCurAnim(m_hObject, nTracker, hAnim);
			pLTModel->ResetAnim(m_hObject, nTracker);
		}
	}
	//disable looping on this animation (so we can actually stop!)
	pLTModel->SetLooping(m_hObject, nTracker, false);

	// Setup the initial data needed to override the models animation length...
	if( GetProps()->m_bOverrideAniLength )
	{
		uint32 nAnimLength;

		pLTModel->GetCurAnimLength( m_hObject, nTracker, nAnimLength );
		pLTModel->SetCurAnimTime( m_hObject, nTracker, 0 );

		float fAniLength = (GetProps()->m_fAniLength < MATH_EPSILON) ? GetProps()->m_tmLifespan : GetProps()->m_fAniLength;
		
		if( fAniLength >= MATH_EPSILON || fAniLength <= -MATH_EPSILON )
			m_fAniRate = (nAnimLength * 0.001f) / fAniLength;

		pLTModel->SetAnimRate( m_hObject, nTracker, m_fAniRate );
	}

	// Success !!

	return LTTRUE;
}
Exemplo n.º 10
0
bool CLTBBouncyChunkFX::Init(ILTClient *pClientDE, FX_BASEDATA *pBaseData, const CBaseFXProps *pProps)
{
	// Perform base class initialisation

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

	LTVector vChunkDir = GetProps()->m_vChunkDir;
	if (pBaseData->m_bUseTargetData)
	{
		vChunkDir = pBaseData->m_vTargetNorm;
	}

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

	float scale;
	CalcScale(m_tmElapsed, GetProps()->m_tmLifespan, &scale);

	LTVector vScale(scale, scale, scale);

	ObjectCreateStruct ocs;
	INIT_OBJECTCREATESTRUCT(ocs);

	ocs.m_ObjectType		= OT_MODEL;
	ocs.m_Flags				= FLAG_NOLIGHT | FLAG_VISIBLE;
	ocs.m_Pos				= vPos + GetProps()->m_vOffset;
	ocs.m_Rotation			= rRot;
	ocs.m_Scale				= vScale;
	strcpy(ocs.m_Filename, GetProps()->m_sModelName);
	strcpy(ocs.m_SkinName, GetProps()->m_sSkinName);

	m_hBouncyChunk = m_pLTClient->CreateObject(&ocs);

	// Setup an initial vector for the velocity

	LTVector vOther;
	vOther.x = 1.0f;
	vOther.y = 0.0f;
	vOther.z = 1.0f;
	vOther.Norm();

	LTVector vRight = vChunkDir.Cross(vOther);
	LTVector vUp    = vRight.Cross(vOther);

	m_vVel = vRight * (-GetProps()->m_fChunkSpread + (float)(rand() % (int)(GetProps()->m_fChunkSpread * 2.0f)));
	m_vVel += vUp * (-GetProps()->m_fChunkSpread + (float)(rand() % (int)(GetProps()->m_fChunkSpread * 2.0f)));
	m_vVel += vChunkDir * GetProps()->m_fChunkSpeed;
	m_vVel.Norm(GetProps()->m_fChunkSpeed);

	// Create the base object

	CreateDummyObject();
		
	// Success !!

	return true;
}
Exemplo n.º 11
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;
}
Exemplo n.º 12
0
//function that handles the custom rendering
void CTracerFX::RenderTracer(ILTCustomRenderCallback* pInterface, const LTRigidTransform& tCamera)
{
	//track our performance
	CTimedSystemBlock TimingBlock(g_tsClientFXTracer);

	//first determine the length, position, and U range for this tracer (this allows for some
	//early outs)
	float fTracerLen	= GetTracerLength();
	float fTracerStart	= m_fRayPosition;
	float fTracerEnd	= fTracerStart - fTracerLen;

	if((fTracerStart <= 0.0f) || (fTracerEnd >= m_fRayLength))
	{
		//the tracer has fully gone through the ray, don't render
		return;
	}

	//now we need to clip the extents to the range [0..ray length], and handle cropping of the texture
	float fUMin = 0.0f;
	float fUMax = 1.0f;

	if(fTracerEnd < 0.0f)
	{
		//adjust the U max if we are cropping
		if(GetProps()->m_bCropTexture)
		{
			fUMax += fTracerEnd / fTracerLen;
		}
		fTracerEnd = 0.0f;
	}
	if(fTracerStart >= m_fRayLength)
	{
		//adjust the U min if we are cropping
		if(GetProps()->m_bCropTexture)
		{
			fUMin += (fTracerStart - m_fRayLength) / fTracerLen;
		}
		fTracerStart = m_fRayLength;
	}

	//setup our vertex declaration
	if(pInterface->SetVertexDeclaration(g_ClientFXVertexDecl.GetTexTangentSpaceDecl()) != LT_OK)
		return;

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

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

	//we need to determine the facing of this tracer. This is formed by creating a plane from the points
	//Camera, Start, and another point on the ray. The plane normal is then the up, the right is the ray
	//direction, and the normal is ray cross plane normal. 
	LTVector vStartToCamera = m_vStartPos - tCamera.m_vPos;
	float fMag = vStartToCamera.Mag( );
	if( fMag < 0.00001f )
	{
		vStartToCamera = tCamera.m_rRot.Forward();
	}
	else
	{
		vStartToCamera /= fMag;
	}

	//determine the up vector
	LTVector vUp = vStartToCamera.Cross(m_vDirection);
	vUp.Normalize();

	//now determine the actual normal (doesn't need to be normalized since the vectors are
	//unit length and orthogonal)
	LTVector vNormal = vUp.Cross(m_vDirection);

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

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

	//determine the color of this tracer
	float fUnitLifetime = GetUnitLifetime();
	uint32 nColor = CFxProp_Color4f::ToColor(GetProps()->m_cfcColor.GetValue(fUnitLifetime));

	//calculate the front of the tracer in world space
	LTVector vFront = m_vStartPos + m_vDirection * fTracerStart;
	LTVector vBack	= m_vStartPos + m_vDirection * fTracerEnd;

	//and the thickness vector
	float fThickness = GetProps()->m_ffcThickness.GetValue(fUnitLifetime);
	LTVector vThickness = vUp * (fThickness * 0.5f);

	//fill in the particle vertices
	pCurrOut[0].m_vPos = vFront + vThickness;
	pCurrOut[0].m_vUV.Init(fUMin, 0.0f);
	
	pCurrOut[1].m_vPos = vBack + vThickness;
	pCurrOut[1].m_vUV.Init(fUMax, 0.0f);
	
	pCurrOut[2].m_vPos = vBack - vThickness;
	pCurrOut[2].m_vUV.Init(fUMax, 1.0f);

	pCurrOut[3].m_vPos = vFront - vThickness;
	pCurrOut[3].m_vUV.Init(fUMin, 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		= vUp;
		pCurrOut[nCurrVert].m_vBinormal		= m_vDirection;
	}

	//unlock and render the batch
	pInterface->UnlockAndBindDynamicVertexBuffer(LockRequest);
	pInterface->RenderIndexed(	eCustomRenderPrimType_TriangleList, 
								0, 6, LockRequest.m_nStartIndex, 
								0, 4);
}
Exemplo n.º 13
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);
	}
}
Exemplo n.º 14
0
//function that handles the custom rendering
void CParticleSystemGroup::RenderParticleSystem(ILTCustomRenderCallback* pInterface, const LTRigidTransform& tCamera)
{
	//track our performance
	CTimedSystemBlock TimingBlock(g_tsClientFXParticles);

	//setup our vertex declaration
	if(pInterface->SetVertexDeclaration(g_ClientFXVertexDecl.GetTexTangentSpaceDecl()) != LT_OK)
		return;

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

	//set the fact that we were visible
	*m_pVisibleFlag = true;

	//now determine the largest number of particles that we can render at any time
	uint32 nMaxParticlesPerBatch = QUAD_RENDER_INDEX_STREAM_SIZE / 6;
	nMaxParticlesPerBatch = LTMIN(nMaxParticlesPerBatch, DYNAMIC_RENDER_VERTEX_STREAM_SIZE / (sizeof(STexTangentSpaceVert) * 4));

	//determine the screen orientation
	LTRotation rCamera = tCamera.m_rRot;

	if (m_pProps->m_bObjectSpace)
	{
		LTRotation rObjectRotation;
		g_pLTClient->GetObjectRotation(m_hCustomRender, &rObjectRotation);
		rCamera = rObjectRotation.Conjugate() * rCamera;
	}

	LTVector vUp = rCamera.Up();
	LTVector vRight = rCamera.Right();

	//create some vectors to offset to each corner (avoids adding for displacement in the inner loop)
	//Each one can just be scaled by the size of the particle to get the final offset
	static const float kfHalfRoot2 = 0.5f * MATH_SQRT2;

	//premultiplied versions of up and right scaled by half the square root of two
	LTVector vUpHalfRoot2 = vUp * kfHalfRoot2;
	LTVector vRightHalfRoot2 = vRight * kfHalfRoot2;

	//precalculate the diagonals for non-rotating particles since these are constant
	LTVector vDiagonals[4];
	vDiagonals[0] =  vUpHalfRoot2 - vRightHalfRoot2; 
	vDiagonals[1] =  vUpHalfRoot2 + vRightHalfRoot2; 
	vDiagonals[2] = -vUpHalfRoot2 + vRightHalfRoot2; 
	vDiagonals[3] = -vUpHalfRoot2 - vRightHalfRoot2; 

	uint32 nNumParticlesLeft = m_Particles.GetNumParticles();

	//precalculate some data for the basis space of the particles
	LTVector	vNormal		= -rCamera.Forward();
	LTVector	vTangent	= vRight;
	LTVector	vBinormal	= -vUp;

	//the U scale for particle images
	float		fUImageWidth = 1.0f / (float)m_pProps->m_nNumImages;

	//variables used within the inner loop
	float		fSize;
	uint32		nColor;

	//now run through all the particles and render
	CParticleIterator itParticles = m_Particles.GetIterator();
	while(nNumParticlesLeft > 0)
	{
		//determine our batch size
		uint32 nBatchSize = LTMIN(nNumParticlesLeft, nMaxParticlesPerBatch);

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

		//fill in a batch of particles
		STexTangentSpaceVert* pCurrOut = (STexTangentSpaceVert*)LockRequest.m_pData;

		if(m_pProps->m_bRotate)
		{
			//we need to render the particles rotated
			for(uint32 nBatchParticle = 0; nBatchParticle < nBatchSize; nBatchParticle++)
			{
				//sanity check
				LTASSERT(!itParticles.IsDone(), "Error: Particle count and iterator mismatch");

				//get the particle from the iterator
				SParticle* pParticle = (SParticle*)itParticles.GetParticle();

				GetParticleSizeAndColor(pParticle, nColor, fSize);

				//determine the sin and cosine of this particle angle
				float fAngle = pParticle->m_fAngle;
				float fSinAngle = LTSin(fAngle);
				float fCosAngle = LTCos(fAngle);

				LTVector vRotRight = (vRightHalfRoot2 * fCosAngle + vUpHalfRoot2 * fSinAngle) * fSize;
				LTVector vRotUp    = vNormal.Cross(vRotRight);

				LTVector vRotTangent  = vTangent * fCosAngle + vBinormal * fSinAngle;
				LTVector vRotBinormal = vTangent * fSinAngle + vBinormal * fCosAngle;

				SetupParticle(	pCurrOut, 
					pParticle->m_Pos + vRotUp - vRotRight,
					pParticle->m_Pos + vRotUp + vRotRight,
					pParticle->m_Pos - vRotUp + vRotRight,
					pParticle->m_Pos - vRotUp - vRotRight,
					nColor, vNormal, vRotTangent, vRotBinormal, 
					pParticle->m_nUserData & PARTICLE_IMAGE_MASK, fUImageWidth);

				//move onto the next set of particles
				pCurrOut += 4;

				//move onto the next particle for processing
				itParticles.Next();
			}
		}
		else if (m_pProps->m_bStreak)
		{
			//the particles are non-rotated but streaked along their velocity
			for(uint32 nBatchParticle = 0; nBatchParticle < nBatchSize; nBatchParticle++)
			{
				//sanity check
				LTASSERT(!itParticles.IsDone(), "Error: Particle count and iterator mismatch");

				//get the particle from the iterator
				SParticle* pParticle = (SParticle*)itParticles.GetParticle();

				GetParticleSizeAndColor(pParticle, nColor, fSize);

				//in order to render the streak, we determine a line that passes through
				//the particle and runs in the direction of the velocity of the particle

				//we need to project the velocity onto the screen
				LTVector2 vScreen;
				vScreen.x = -(pParticle->m_Velocity.Dot(vRight));
				vScreen.y = -(pParticle->m_Velocity.Dot(vUp));

				//we know that the up and right vectors are normalized, so we can save some work by
				//just doing a 2d normalization
				float fMag = vScreen.Mag();
				if(fMag == 0.0f)
					vScreen.Init(fSize, 0.0f);
				else
					vScreen *= fSize / fMag;

				//determine our actual screen space velocity
				LTVector vScreenRight = vUp * vScreen.y + vRight * vScreen.x;
				LTVector vScreenUp = vUp * -vScreen.x + vRight * vScreen.y;

				//and now compute the endpoint of the streak
				LTVector vEndPos = pParticle->m_Pos - pParticle->m_Velocity * m_pProps->m_fStreakScale;

				SetupParticle(	pCurrOut, 
					pParticle->m_Pos	- vScreenRight - vScreenUp,
					vEndPos				+ vScreenRight - vScreenUp,
					vEndPos				+ vScreenRight + vScreenUp,
					pParticle->m_Pos	- vScreenRight + vScreenUp,
					nColor, vNormal, vScreenRight, vScreenUp, 
					pParticle->m_nUserData & PARTICLE_IMAGE_MASK, fUImageWidth);

				//move onto the next set of particles
				pCurrOut += 4;

				//move onto the next particle for processing
				itParticles.Next();
			}
		}
		else
		{
			//the particles are non-rotated
			for(uint32 nBatchParticle = 0; nBatchParticle < nBatchSize; nBatchParticle++)
			{
				//sanity check
				LTASSERT(!itParticles.IsDone(), "Error: Particle count and iterator mismatch");

				//get the particle from the iterator
				SParticle* pParticle = (SParticle*)itParticles.GetParticle();

				GetParticleSizeAndColor(pParticle, nColor, fSize);

				SetupParticle(	pCurrOut, 
					pParticle->m_Pos + vDiagonals[0] * fSize,
					pParticle->m_Pos + vDiagonals[1] * fSize,
					pParticle->m_Pos + vDiagonals[2] * fSize,
					pParticle->m_Pos + vDiagonals[3] * fSize,
					nColor, vNormal, vTangent, vBinormal, 
					pParticle->m_nUserData & PARTICLE_IMAGE_MASK, fUImageWidth);

				//move onto the next set of particles
				pCurrOut += 4;

				//move onto the next particle for processing
				itParticles.Next();
			}
		}

		//unlock and render the batch
		pInterface->UnlockAndBindDynamicVertexBuffer(LockRequest);
		pInterface->RenderIndexed(	eCustomRenderPrimType_TriangleList, 
			0, nBatchSize * 6, LockRequest.m_nStartIndex, 
			0, nBatchSize * 4);

		nNumParticlesLeft -= nBatchSize;
	}
}
Exemplo n.º 15
0
bool CAIWeaponAbstract::GetShootPosition( CAI* pAI, AimContext& Context,LTVector& outvShootPos )
{
	ASSERT(pAI);

	// Cineractive firing.

	if( m_eFiringState == kAIFiringState_CineFiring )
	{
		LTVector vDir = pAI->GetWeaponForward( m_pWeapon );
		vDir.Normalize();
		outvShootPos = pAI->GetPosition() + ( vDir * 5000.f );
		return true;
	}

	// If perfect accuracy is enabled, we are done.

	if( pAI->GetAIBlackBoard()->GetBBPerfectAccuracy() )
	{
		HOBJECT hTarget = pAI->GetAIBlackBoard()->GetBBTargetObject();
		g_pLTServer->GetObjectPos( hTarget, &outvShootPos );
		return true;
	}

	// Initially aim for the target's visible position.
	// If the target is not visible at all, use his actual position.
	// This is a failsafe for AI shooting at the origin if they have
	// not yet seen the target ever.

	LTVector vVisiblePosition = pAI->GetTarget()->GetVisiblePosition();
	if( !pAI->GetAIBlackBoard()->GetBBTargetVisibleFromWeapon() )
	{
		vVisiblePosition = pAI->GetAIBlackBoard()->GetBBTargetPosition();
	}
	outvShootPos = vVisiblePosition;

	// If Target is within the FullAccuracy radius, we are done.

	if( pAI->GetTarget()->GetTargetDistSqr() < pAI->GetFullAccuracyRadiusSqr() )
	{
		return true;
	}

	// The following code forces the AI to intenionally miss every x
	// number of shots, depending on their accuracy. This gives players
	// the excitement of getting shot at without killing them too fast.

	// For example, if accuracy = 0.5 there will be a guaranteed sequence
	// of HIT, MISS, HIT, MISS, ...
	// If accuracy = 0.25, then HIT, MISS, MISS, MISS, HIT, MISS, MISS, MISS, etc.
	// If accuracy = 0.75, then HIT, HIT, HIT, MISS, HIT, HIT, HIT, MISS, etc.

	// Calculate the ratio of hits to misses based on the current 
	// accuracy.  This needs to be recalculated for every shot, 
	// because accuracy may change at any time.

	float fAccuracy = m_flWeaponContextInaccuracyScalar * pAI->GetAccuracy();
	if( fAccuracy <= 0.f )
	{
		Context.m_cMisses = 1;
		Context.m_cHits = 0;
	}
	else if( fAccuracy >= 1.f )
	{
		Context.m_cMisses = 0;
		Context.m_cHits = 1;
	}
	else if( fAccuracy < 0.5f )
	{
		Context.m_cMisses = (uint32)( ( ( 1.f - fAccuracy ) / fAccuracy ) + 0.5f );
		Context.m_cHits = 1;
	}
	else 
	{
		Context.m_cMisses = 1;
		Context.m_cHits = (uint32)( ( fAccuracy / ( 1.f - fAccuracy ) ) + 0.5f );
	}

	// If we have met or exceeded the required number of misses, 
	// reset the counters.

	if( Context.m_iMiss >= Context.m_cMisses )
	{
		Context.m_iHit = 0;
		Context.m_iMiss = 0;
	}

	//
	// First take care of hits, then take care of misses.
	//

	// Hit.

	if( Context.m_iHit < Context.m_cHits )
	{
		++Context.m_iHit;

		// Blind fire.

		if( pAI->GetAIBlackBoard()->GetBBBlindFire() )
		{
			GetBlindFirePosition( pAI, outvShootPos, !FIRE_MISS );
			return false;
		}

		// Suppression fire at last known pos.

		if( pAI->GetAIBlackBoard()->GetBBSuppressionFire() )
		{
			HOBJECT hTarget = pAI->GetAIBlackBoard()->GetBBTargetObject();

			CAIWMFact factQuery;
			factQuery.SetFactType( kFact_Character );
			factQuery.SetTargetObject( hTarget );
			CAIWMFact* pFact = pAI->GetAIWorkingMemory()->FindWMFact( factQuery );
			if( pFact )
			{
				outvShootPos = pFact->GetPos();
			}
		}

		// Default fire.

		// If target has started moving or change directions recently,
		// factor in some inaccuracy.

		float fInnaccuracy = LTMAX( 0.f, pAI->GetTarget()->GetCurMovementInaccuracy() );
		if( fInnaccuracy > 0.f )
		{
			LTVector vShootOffset = LTVector(	GetRandom( -fInnaccuracy, fInnaccuracy ),
				GetRandom( -fInnaccuracy * 0.5f, fInnaccuracy * 0.5f ),
				GetRandom( -fInnaccuracy, fInnaccuracy ) );
			vShootOffset.Normalize();

			outvShootPos += vShootOffset * 100.0f;
		}
		
		return true;
	}

	// Miss.

	else 
	{
		++Context.m_iMiss;

		// Blind fire.

		if( pAI->GetAIBlackBoard()->GetBBBlindFire() )
		{
			GetBlindFirePosition( pAI, outvShootPos, FIRE_MISS );
			return false;
		}

		// Default fire.

		HOBJECT hTarget = pAI->GetAIBlackBoard()->GetBBTargetObject();
		if( !IsCharacter( hTarget ) )
		{
			return false;
		}

		CCharacter* pChar = (CCharacter*)g_pLTServer->HandleToObject( hTarget );
		if( !pChar )
		{
			return false;
		}

		// Intentionally shoot a little short of the target.

		LTVector vPos = pAI->GetAIBlackBoard()->GetBBTargetPosition();;

		// Suppression fire at last known pos.

		if( pAI->GetAIBlackBoard()->GetBBSuppressionFire() )
		{
			CAIWMFact factQuery;
			factQuery.SetFactType( kFact_Character );
			factQuery.SetTargetObject( hTarget );
			CAIWMFact* pFact = pAI->GetAIWorkingMemory()->FindWMFact( factQuery );
			if( pFact )
			{
				vPos = pFact->GetPos();
			}
		}

		float fDist = sqrt( pAI->GetTarget()->GetTargetDistSqr() );

		float fRadius = pChar->GetRadius();

		float fRand = GetRandom( 0.f, 1.f );
		fDist -= ( fRadius * 2.f ) + ( fRand * pAI->GetAccuracyMissPerturb() );

		// Calculate a position to the right or left of the target.

		LTVector vDir = vPos - pAI->GetPosition();
		if( vDir != LTVector::GetIdentity() )
		{
			vDir.Normalize();
		}

		vPos = pAI->GetPosition() + ( vDir * fDist );

		LTVector vRight = vDir.Cross( LTVector( 0.f, 1.f, 0.f ) );

		fRand = GetRandom( 0.f, 1.f );
		float fPerturb = ( ( pAI->GetAccuracyMissPerturb() * 2.f ) * fRand ) - pAI->GetAccuracyMissPerturb();
		vRight *= fPerturb;

		// Apply the offset to miss the target.

		outvShootPos = vPos + vRight;

		// Force bullets to land in front of the target, on the floor.

		if( m_pAIWeaponRecord->bForceMissToFloor )
		{
			float fFloor = pAI->GetAIBlackBoard()->GetBBTargetPosition().y;
			fFloor -= pAI->GetAIBlackBoard()->GetBBTargetDims().y;
			outvShootPos.y = fFloor;
		}

		return false;
	}

	return false;
}
Exemplo n.º 16
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);
}