You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
625 lines
17 KiB
625 lines
17 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: particle system definitions |
|
// |
|
//===========================================================================// |
|
|
|
#include "cbase.h" |
|
#include "particles/particles.h" |
|
#include "baseparticleentity.h" |
|
#include "entityparticletrail_shared.h" |
|
#include "collisionutils.h" |
|
|
|
#if defined( CLIENT_DLL ) |
|
#include "c_pixel_visibility.h" |
|
#endif |
|
|
|
#ifdef TF_CLIENT_DLL |
|
#include "tf_shareddefs.h" |
|
#endif |
|
|
|
#ifdef GAME_DLL |
|
#include "ai_utils.h" |
|
#endif |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Interface to allow the particle system to call back into the game code |
|
//----------------------------------------------------------------------------- |
|
class CParticleSystemQuery : public CBaseAppSystem< IParticleSystemQuery > |
|
{ |
|
public: |
|
// Inherited from IParticleSystemQuery |
|
virtual void GetLightingAtPoint( const Vector& vecOrigin, Color &cTint ); |
|
virtual void TraceLine( const Vector& vecAbsStart, |
|
const Vector& vecAbsEnd, unsigned int mask, |
|
const IHandleEntity *ignore, |
|
int collisionGroup, CBaseTrace *ptr ); |
|
|
|
virtual bool MovePointInsideControllingObject( CParticleCollection *pParticles, |
|
void *pObject, |
|
Vector *pPnt ); |
|
virtual void GetRandomPointsOnControllingObjectHitBox( |
|
CParticleCollection *pParticles, |
|
int nControlPointNumber, |
|
int nNumPtsOut, |
|
float flBBoxScale, |
|
int nNumTrysToGetAPointInsideTheModel, |
|
Vector *pPntsOut, |
|
Vector vecDirectionalBias, |
|
Vector *pHitBoxRelativeCoordOut, |
|
int *pHitBoxIndexOut |
|
); |
|
|
|
virtual int GetCollisionGroupFromName( const char *pszCollisionGroupName ); |
|
|
|
|
|
virtual int GetControllingObjectHitBoxInfo( |
|
CParticleCollection *pParticles, |
|
int nControlPointNumber, |
|
int nBufSize, // # of output slots available |
|
ModelHitBoxInfo_t *pHitBoxOutputBuffer ); |
|
|
|
virtual bool IsPointInControllingObjectHitBox( |
|
CParticleCollection *pParticles, |
|
int nControlPointNumber, Vector vecPos, bool bBBoxOnly ); |
|
|
|
virtual Vector GetLocalPlayerPos( void ); |
|
virtual void GetLocalPlayerEyeVectors( Vector *pForward, Vector *pRight = NULL, Vector *pUp = NULL ); |
|
|
|
virtual float GetPixelVisibility( int *pQueryHandle, const Vector &vecOrigin, float flScale ); |
|
virtual void SetUpLightingEnvironment( const Vector& pos ); |
|
}; |
|
|
|
|
|
static CParticleSystemQuery s_ParticleSystemQuery; |
|
IParticleSystemQuery *g_pParticleSystemQuery = &s_ParticleSystemQuery; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Exposes the interface (so tools can get at it) |
|
//----------------------------------------------------------------------------- |
|
#ifdef CLIENT_DLL |
|
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CParticleSystemQuery, IParticleSystemQuery, PARTICLE_SYSTEM_QUERY_INTERFACE_VERSION, s_ParticleSystemQuery ); |
|
#endif |
|
|
|
static CThreadFastMutex s_LightMutex; |
|
|
|
// This mutex exists because EntityToWorldTransform was not threadsafe, and could potentially have been called from multiple |
|
// particle update threads. It has now been fixed to be threadsafe, so this mutex can safely just be a no-op (meaingful perf win for this). |
|
// static CThreadFastMutex s_BoneMutex; |
|
static CThreadNullMutex s_BoneMutex; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Inherited from IParticleSystemQuery |
|
//----------------------------------------------------------------------------- |
|
void CParticleSystemQuery::GetLightingAtPoint( const Vector& vecOrigin, Color &cTint ) |
|
{ |
|
#ifdef GAME_DLL |
|
|
|
// FIXME: Go through to the engine from the server to get these values |
|
cTint.SetColor( 255, 255, 255, 255 ); |
|
|
|
#else |
|
|
|
if ( engine->IsInGame() ) |
|
{ |
|
s_LightMutex.Lock(); |
|
// Compute our lighting at our position |
|
Vector totalColor = engine->GetLightForPoint( vecOrigin, true ); |
|
s_LightMutex.Unlock(); |
|
|
|
// Get our lighting information |
|
cTint.SetColor( totalColor.x*255, totalColor.y*255, totalColor.z*255, 0 ); |
|
} |
|
else |
|
{ |
|
// FIXME: Go through to the engine from the server to get these values |
|
cTint.SetColor( 255, 255, 255, 255 ); |
|
} |
|
|
|
#endif |
|
} |
|
|
|
void CParticleSystemQuery::SetUpLightingEnvironment( const Vector& pos ) |
|
{ |
|
#ifndef GAME_DLL |
|
if ( !engine->IsInGame() ) |
|
return; |
|
|
|
s_LightMutex.Lock(); |
|
modelrender->SetupLighting( pos ); |
|
s_LightMutex.Unlock(); |
|
#endif |
|
} |
|
|
|
void CParticleSystemQuery::TraceLine( const Vector& vecAbsStart, |
|
const Vector& vecAbsEnd, unsigned int mask, |
|
const IHandleEntity *ignore, |
|
int collisionGroup, CBaseTrace *ptr ) |
|
{ |
|
bool bDoTrace = false; |
|
#ifndef GAME_DLL |
|
bDoTrace = engine->IsInGame(); |
|
#endif |
|
if ( bDoTrace ) |
|
{ |
|
trace_t tempTrace; |
|
UTIL_TraceLine( vecAbsStart, vecAbsEnd, mask, ignore, collisionGroup, &tempTrace ); |
|
memcpy( ptr, &tempTrace, sizeof ( CBaseTrace ) ); |
|
} |
|
else |
|
{ |
|
ptr->startsolid = 0; |
|
ptr->fraction = 1.0; |
|
} |
|
|
|
} |
|
|
|
bool CParticleSystemQuery::MovePointInsideControllingObject( |
|
CParticleCollection *pParticles, void *pObject, Vector *pPnt ) |
|
{ |
|
#ifdef GAME_DLL |
|
return true; |
|
#else |
|
if (! pObject ) |
|
return true; // accept the input point unmodified |
|
|
|
Ray_t ray; |
|
trace_t tr; |
|
ray.Init( *pPnt, *pPnt ); |
|
enginetrace->ClipRayToEntity( ray, MASK_ALL, (CBaseEntity *) pObject, &tr ); |
|
|
|
return ( tr.startsolid ); |
|
#endif |
|
} |
|
|
|
static float GetSurfaceCoord( float flRand, float flMinX, float flMaxX ) |
|
{ |
|
return Lerp( flRand, flMinX, flMaxX ); |
|
|
|
} |
|
|
|
|
|
void CParticleSystemQuery::GetRandomPointsOnControllingObjectHitBox( |
|
CParticleCollection *pParticles, |
|
int nControlPointNumber, |
|
int nNumPtsOut, |
|
float flBBoxScale, |
|
int nNumTrysToGetAPointInsideTheModel, |
|
Vector *pPntsOut, |
|
Vector vecDirectionalBias, |
|
Vector *pHitBoxRelativeCoordOut, |
|
int *pHitBoxIndexOut |
|
) |
|
{ |
|
|
|
bool bSucesss = false; |
|
|
|
|
|
#ifndef GAME_DLL |
|
|
|
EHANDLE *phMoveParent = reinterpret_cast<EHANDLE *> ( pParticles->m_ControlPoints[nControlPointNumber].m_pObject ); |
|
CBaseEntity *pMoveParent = NULL; |
|
if ( phMoveParent ) |
|
{ |
|
pMoveParent = *( phMoveParent ); |
|
} |
|
if ( pMoveParent ) |
|
{ |
|
float flRandMax = flBBoxScale; |
|
float flRandMin = 1.0 - flBBoxScale; |
|
Vector vecBasePos; |
|
pParticles->GetControlPointAtTime( nControlPointNumber, pParticles->m_flCurTime, &vecBasePos ); |
|
|
|
s_BoneMutex.Lock(); |
|
C_BaseAnimating *pAnimating = pMoveParent->GetBaseAnimating(); |
|
if ( pAnimating ) |
|
{ |
|
|
|
matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; |
|
|
|
if ( pAnimating->HitboxToWorldTransforms( hitboxbones ) ) |
|
{ |
|
|
|
studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); |
|
|
|
if ( pStudioHdr ) |
|
{ |
|
mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() ); |
|
|
|
if ( set ) |
|
{ |
|
bSucesss = true; |
|
|
|
Vector vecWorldPosition(0, 0, 0); |
|
float u = 0, v = 0, w = 0; |
|
int nHitbox = 0; |
|
int nNumIters = nNumTrysToGetAPointInsideTheModel; |
|
if (! vecDirectionalBias.IsZero( 0.0001 ) ) |
|
nNumIters = MAX( nNumIters, 5 ); |
|
|
|
for( int i=0 ; i < nNumPtsOut; i++) |
|
{ |
|
int nTryCnt = nNumIters; |
|
float flBestPointGoodness = -1.0e20; |
|
do |
|
{ |
|
int nTryHitbox = pParticles->RandomInt( 0, set->numhitboxes - 1 ); |
|
mstudiobbox_t *pBox = set->pHitbox(nTryHitbox); |
|
|
|
float flTryU = pParticles->RandomFloat( flRandMin, flRandMax ); |
|
float flTryV = pParticles->RandomFloat( flRandMin, flRandMax ); |
|
float flTryW = pParticles->RandomFloat( flRandMin, flRandMax ); |
|
|
|
Vector vecLocalPosition; |
|
vecLocalPosition.x = GetSurfaceCoord( flTryU, pBox->bbmin.x * pAnimating->GetModelScale(), pBox->bbmax.x * pAnimating->GetModelScale() ); |
|
vecLocalPosition.y = GetSurfaceCoord( flTryV, pBox->bbmin.y * pAnimating->GetModelScale(), pBox->bbmax.y * pAnimating->GetModelScale() ); |
|
vecLocalPosition.z = GetSurfaceCoord( flTryW, pBox->bbmin.z * pAnimating->GetModelScale(), pBox->bbmax.z * pAnimating->GetModelScale() ); |
|
|
|
Vector vecTryWorldPosition; |
|
|
|
VectorTransform( vecLocalPosition, *hitboxbones[pBox->bone], vecTryWorldPosition ); |
|
|
|
|
|
float flPointGoodness = pParticles->RandomFloat( 0, 72 ) |
|
+ DotProduct( vecTryWorldPosition - vecBasePos, |
|
vecDirectionalBias ); |
|
|
|
if ( nNumTrysToGetAPointInsideTheModel ) |
|
{ |
|
// do a point in solid test |
|
Ray_t ray; |
|
trace_t tr; |
|
ray.Init( vecTryWorldPosition, vecTryWorldPosition ); |
|
enginetrace->ClipRayToEntity( ray, MASK_ALL, pMoveParent, &tr ); |
|
if ( tr.startsolid ) |
|
flPointGoodness += 1000.; // got a point inside! |
|
} |
|
if ( flPointGoodness > flBestPointGoodness ) |
|
{ |
|
u = flTryU; |
|
v = flTryV; |
|
w = flTryW; |
|
vecWorldPosition = vecTryWorldPosition; |
|
nHitbox = nTryHitbox; |
|
flBestPointGoodness = flPointGoodness; |
|
} |
|
} while ( nTryCnt-- ); |
|
*( pPntsOut++ ) = vecWorldPosition; |
|
if ( pHitBoxRelativeCoordOut ) |
|
( pHitBoxRelativeCoordOut++ )->Init( u, v, w ); |
|
if ( pHitBoxIndexOut ) |
|
*( pHitBoxIndexOut++ ) = nHitbox; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
if ( pMoveParent->IsBrushModel() ) |
|
{ |
|
Vector vecMin; |
|
Vector vecMax; |
|
matrix3x4_t matOrientation; |
|
Vector VecOrigin; |
|
pMoveParent->GetRenderBounds( vecMin, vecMax ); |
|
VecOrigin = pMoveParent->GetRenderOrigin(); |
|
matOrientation = pMoveParent->EntityToWorldTransform(); |
|
|
|
|
|
|
|
Vector vecWorldPosition(0, 0, 0); |
|
float u = 0, v = 0, w = 0; |
|
int nHitbox = 0; |
|
int nNumIters = nNumTrysToGetAPointInsideTheModel; |
|
if (! vecDirectionalBias.IsZero( 0.0001 ) ) |
|
nNumIters = MAX( nNumIters, 5 ); |
|
|
|
for( int i=0 ; i < nNumPtsOut; i++) |
|
{ |
|
int nTryCnt = nNumIters; |
|
float flBestPointGoodness = -1.0e20; |
|
do |
|
{ |
|
float flTryU = pParticles->RandomFloat( flRandMin, flRandMax ); |
|
float flTryV = pParticles->RandomFloat( flRandMin, flRandMax ); |
|
float flTryW = pParticles->RandomFloat( flRandMin, flRandMax ); |
|
|
|
Vector vecLocalPosition; |
|
vecLocalPosition.x = GetSurfaceCoord( flTryU, vecMin.x, vecMax.x ); |
|
vecLocalPosition.y = GetSurfaceCoord( flTryV, vecMin.y, vecMax.y ); |
|
vecLocalPosition.z = GetSurfaceCoord( flTryW, vecMin.z, vecMax.z ); |
|
|
|
Vector vecTryWorldPosition; |
|
VectorTransform( vecLocalPosition, matOrientation, vecTryWorldPosition ); |
|
|
|
float flPointGoodness = pParticles->RandomFloat( 0, 72 ) |
|
+ DotProduct( vecTryWorldPosition - vecBasePos, |
|
vecDirectionalBias ); |
|
|
|
if ( nNumTrysToGetAPointInsideTheModel ) |
|
{ |
|
// do a point in solid test |
|
Ray_t ray; |
|
trace_t tr; |
|
ray.Init( vecTryWorldPosition, vecTryWorldPosition ); |
|
enginetrace->ClipRayToEntity( ray, MASK_ALL, pMoveParent, &tr ); |
|
if ( tr.startsolid ) |
|
flPointGoodness += 1000.; // got a point inside! |
|
} |
|
if ( flPointGoodness > flBestPointGoodness ) |
|
{ |
|
u = flTryU; |
|
v = flTryV; |
|
w = flTryW; |
|
vecWorldPosition = vecTryWorldPosition; |
|
nHitbox = 0; |
|
flBestPointGoodness = flPointGoodness; |
|
} |
|
} while ( nTryCnt-- ); |
|
*( pPntsOut++ ) = vecWorldPosition; |
|
if ( pHitBoxRelativeCoordOut ) |
|
( pHitBoxRelativeCoordOut++ )->Init( u, v, w ); |
|
if ( pHitBoxIndexOut ) |
|
*( pHitBoxIndexOut++ ) = nHitbox; |
|
} |
|
} |
|
|
|
s_BoneMutex.Unlock(); |
|
} |
|
#endif |
|
if (! bSucesss ) |
|
{ |
|
// don't have a model or am in editor or something - fill return with control point |
|
for( int i=0 ; i < nNumPtsOut; i++) |
|
{ |
|
pPntsOut[i] = pParticles->m_ControlPoints[nControlPointNumber].m_Position; // fallback if anything goes wrong |
|
|
|
if ( pHitBoxIndexOut ) |
|
pHitBoxIndexOut[i] = 0; |
|
|
|
if ( pHitBoxRelativeCoordOut ) |
|
pHitBoxRelativeCoordOut[i].Init(); |
|
} |
|
} |
|
} |
|
|
|
|
|
int CParticleSystemQuery::GetControllingObjectHitBoxInfo( |
|
CParticleCollection *pParticles, |
|
int nControlPointNumber, |
|
int nBufSize, // # of output slots available |
|
ModelHitBoxInfo_t *pHitBoxOutputBuffer ) |
|
{ |
|
int nRet = 0; |
|
|
|
#ifndef GAME_DLL |
|
s_BoneMutex.Lock(); |
|
|
|
EHANDLE *phMoveParent = reinterpret_cast<EHANDLE *> ( pParticles->m_ControlPoints[nControlPointNumber].m_pObject ); |
|
CBaseEntity *pMoveParent = NULL; |
|
if ( phMoveParent ) |
|
{ |
|
pMoveParent = *( phMoveParent ); |
|
} |
|
|
|
if ( pMoveParent ) |
|
{ |
|
C_BaseAnimating *pAnimating = pMoveParent->GetBaseAnimating(); |
|
if ( pAnimating ) |
|
{ |
|
matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; |
|
|
|
if ( pAnimating->HitboxToWorldTransforms( hitboxbones ) ) |
|
{ |
|
|
|
studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); |
|
|
|
if ( pStudioHdr ) |
|
{ |
|
mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() ); |
|
|
|
if ( set ) |
|
{ |
|
nRet = MIN( nBufSize, set->numhitboxes ); |
|
for( int i=0 ; i < nRet; i++ ) |
|
{ |
|
mstudiobbox_t *pBox = set->pHitbox( i ); |
|
pHitBoxOutputBuffer[i].m_vecBoxMins.x = pBox->bbmin.x; |
|
pHitBoxOutputBuffer[i].m_vecBoxMins.y = pBox->bbmin.y; |
|
pHitBoxOutputBuffer[i].m_vecBoxMins.z = pBox->bbmin.z; |
|
|
|
pHitBoxOutputBuffer[i].m_vecBoxMaxes.x = pBox->bbmax.x; |
|
pHitBoxOutputBuffer[i].m_vecBoxMaxes.y = pBox->bbmax.y; |
|
pHitBoxOutputBuffer[i].m_vecBoxMaxes.z = pBox->bbmax.z; |
|
|
|
pHitBoxOutputBuffer[i].m_Transform = *hitboxbones[pBox->bone]; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
if ( pMoveParent->IsBrushModel() ) |
|
{ |
|
Vector vecMin; |
|
Vector vecMax; |
|
matrix3x4_t matOrientation; |
|
pMoveParent->GetRenderBounds( vecMin, vecMax ); |
|
matOrientation = pMoveParent->EntityToWorldTransform(); |
|
pHitBoxOutputBuffer[0].m_vecBoxMins = vecMin; |
|
pHitBoxOutputBuffer[0].m_vecBoxMaxes = vecMax; |
|
pHitBoxOutputBuffer[0].m_Transform = matOrientation; |
|
nRet = 1; |
|
} |
|
} |
|
s_BoneMutex.Unlock(); |
|
#endif |
|
return nRet; |
|
} |
|
|
|
|
|
|
|
bool CParticleSystemQuery::IsPointInControllingObjectHitBox( |
|
CParticleCollection *pParticles, |
|
int nControlPointNumber, Vector vecPos, bool bBBoxOnly ) |
|
{ |
|
bool bSuccess = false; |
|
#ifndef GAME_DLL |
|
|
|
EHANDLE *phMoveParent = reinterpret_cast<EHANDLE *> ( pParticles->m_ControlPoints[nControlPointNumber].m_pObject ); |
|
CBaseEntity *pMoveParent = NULL; |
|
if ( phMoveParent ) |
|
{ |
|
pMoveParent = *( phMoveParent ); |
|
} |
|
if ( pMoveParent ) |
|
{ |
|
s_BoneMutex.Lock(); |
|
C_BaseAnimating *pAnimating = pMoveParent->GetBaseAnimating(); |
|
|
|
bool bInBBox = false; |
|
Vector vecBBoxMin; |
|
Vector vecBBoxMax; |
|
Vector vecOrigin; |
|
|
|
vecBBoxMin = pMoveParent->CollisionProp()->OBBMins(); |
|
vecBBoxMax = pMoveParent->CollisionProp()->OBBMaxs(); |
|
|
|
matrix3x4_t matOrientation; |
|
matOrientation = pMoveParent->EntityToWorldTransform(); |
|
Vector vecLocalPos; |
|
VectorITransform( vecPos, matOrientation, vecLocalPos ); |
|
if ( IsPointInBox( vecLocalPos, vecBBoxMin, vecBBoxMax ) ) |
|
bInBBox = true; |
|
|
|
if ( bInBBox && bBBoxOnly ) |
|
bSuccess = true; |
|
else if ( pAnimating && bInBBox ) |
|
{ |
|
matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; |
|
if ( pAnimating->HitboxToWorldTransforms( hitboxbones ) ) |
|
{ |
|
|
|
studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); |
|
|
|
if ( pStudioHdr ) |
|
{ |
|
mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() ); |
|
|
|
if ( set ) |
|
{ |
|
// do a point in solid test |
|
Ray_t ray; |
|
trace_t tr; |
|
ray.Init( vecPos, vecPos ); |
|
enginetrace->ClipRayToEntity( ray, MASK_ALL, pMoveParent, &tr ); |
|
if ( tr.startsolid ) |
|
bSuccess = true; |
|
} |
|
} |
|
} |
|
} |
|
else if ( pMoveParent->IsBrushModel() && bInBBox ) |
|
{ |
|
// do a point in solid test |
|
Ray_t ray; |
|
trace_t tr; |
|
ray.Init( vecPos, vecPos ); |
|
enginetrace->ClipRayToEntity( ray, MASK_ALL, pMoveParent, &tr ); |
|
if ( tr.startsolid ) |
|
bSuccess = true; |
|
} |
|
|
|
s_BoneMutex.Unlock(); |
|
} |
|
#endif |
|
return bSuccess; |
|
} |
|
|
|
|
|
struct CollisionGroupNameRecord_t |
|
{ |
|
const char *m_pszGroupName; |
|
int m_nGroupID; |
|
}; |
|
|
|
|
|
static CollisionGroupNameRecord_t s_NameMap[]={ |
|
{ "NONE", COLLISION_GROUP_NONE }, |
|
{ "DEBRIS", COLLISION_GROUP_DEBRIS }, |
|
{ "INTERACTIVE", COLLISION_GROUP_INTERACTIVE }, |
|
{ "NPC", COLLISION_GROUP_NPC }, |
|
{ "ACTOR", COLLISION_GROUP_NPC_ACTOR }, |
|
{ "PASSABLE", COLLISION_GROUP_PASSABLE_DOOR }, |
|
#if defined( TF_CLIENT_DLL ) |
|
{ "ROCKETS", TFCOLLISION_GROUP_ROCKETS }, |
|
#endif |
|
}; |
|
|
|
|
|
int CParticleSystemQuery::GetCollisionGroupFromName( const char *pszCollisionGroupName ) |
|
{ |
|
for(int i = 0; i < ARRAYSIZE( s_NameMap ); i++ ) |
|
{ |
|
if ( ! stricmp( s_NameMap[i].m_pszGroupName, pszCollisionGroupName ) ) |
|
return s_NameMap[i].m_nGroupID; |
|
} |
|
return COLLISION_GROUP_NONE; |
|
} |
|
|
|
Vector CParticleSystemQuery::GetLocalPlayerPos( void ) |
|
{ |
|
#ifdef CLIENT_DLL |
|
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); |
|
if ( !pPlayer ) |
|
return vec3_origin; |
|
return pPlayer->WorldSpaceCenter(); |
|
#else |
|
CBasePlayer *pPlayer = AI_GetSinglePlayer(); |
|
if ( !pPlayer ) |
|
return vec3_origin; |
|
return pPlayer->WorldSpaceCenter(); |
|
#endif |
|
} |
|
|
|
void CParticleSystemQuery::GetLocalPlayerEyeVectors( Vector *pForward, Vector *pRight, Vector *pUp ) |
|
{ |
|
#ifdef CLIENT_DLL |
|
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); |
|
if ( !pPlayer ) |
|
{ |
|
*pForward = vec3_origin; |
|
*pRight = vec3_origin; |
|
*pUp = vec3_origin; |
|
return; |
|
} |
|
pPlayer->EyeVectors( pForward, pRight, pUp ); |
|
#else |
|
CBasePlayer *pPlayer = AI_GetSinglePlayer(); |
|
if ( !pPlayer ) |
|
{ |
|
*pForward = vec3_origin; |
|
*pRight = vec3_origin; |
|
*pUp = vec3_origin; |
|
return; |
|
} |
|
pPlayer->EyeVectors( pForward, pRight, pUp ); |
|
#endif |
|
} |
|
|
|
float CParticleSystemQuery::GetPixelVisibility( int *pQueryHandle, const Vector &vecOrigin, float flScale ) |
|
{ |
|
#ifdef CLIENT_DLL |
|
pixelvis_queryparams_t params; |
|
params.Init( vecOrigin, flScale, 1.0 ); |
|
float flVisibility = PixelVisibility_FractionVisible( params, pQueryHandle ); |
|
flVisibility = MAX( 0.0f, flVisibility ); |
|
return flVisibility; |
|
#else |
|
return 0.0f; |
|
#endif |
|
}
|
|
|