2008-09-15 01:00:17 -05:00
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose: Draws grasses and other small objects
//
// $Revision: $
// $NoKeywords: $
//===========================================================================//
# include "cbase.h"
# include "DetailObjectSystem.h"
# include "GameBspFile.h"
# include "UtlBuffer.h"
# include "tier1/utlmap.h"
# include "view.h"
# include "ClientMode.h"
# include "IViewRender.h"
# include "BSPTreeData.h"
# include "tier0/vprof.h"
# include "engine/ivmodelinfo.h"
# include "materialsystem/IMesh.h"
# include "model_types.h"
# include "env_detail_controller.h"
# include "vstdlib/icommandline.h"
# include "c_world.h"
# if defined(DOD_DLL) || defined(CSTRIKE_DLL)
# define USE_DETAIL_SHAPES
# endif
# ifdef USE_DETAIL_SHAPES
# include "engine/ivdebugoverlay.h"
# include "playerenumerator.h"
# endif
# include "materialsystem/imaterialsystemhardwareconfig.h"
// memdbgon must be the last include file in a .cpp file!!!
# include "tier0/memdbgon.h"
# define DETAIL_SPRITE_MATERIAL "detail / detailsprites"
//-----------------------------------------------------------------------------
// forward declarations
//-----------------------------------------------------------------------------
struct model_t ;
ConVar cl_detaildist ( " cl_detaildist " , " 1200 " , 0 , " Distance at which detail props are no longer visible " ) ;
ConVar cl_detailfade ( " cl_detailfade " , " 400 " , 0 , " Distance across which detail props fade in " ) ;
# if defined( USE_DETAIL_SHAPES )
ConVar cl_detail_max_sway ( " cl_detail_max_sway " , " 0 " , FCVAR_ARCHIVE , " Amplitude of the detail prop sway " ) ;
ConVar cl_detail_avoid_radius ( " cl_detail_avoid_radius " , " 0 " , FCVAR_ARCHIVE , " radius around detail sprite to avoid players " ) ;
ConVar cl_detail_avoid_force ( " cl_detail_avoid_force " , " 0 " , FCVAR_ARCHIVE , " force with which to avoid players ( in units, percentage of the width of the detail sprite ) " ) ;
ConVar cl_detail_avoid_recover_speed ( " cl_detail_avoid_recover_speed " , " 0 " , FCVAR_ARCHIVE , " how fast to recover position after avoiding players " ) ;
# endif
// Per detail instance information
struct DetailModelAdvInfo_t
{
// precaculated angles for shaped sprites
Vector m_vecAnglesForward [ 3 ] ;
Vector m_vecAnglesRight [ 3 ] ; // better to save this mem and calc per sprite ?
Vector m_vecAnglesUp [ 3 ] ;
// direction we're avoiding the player
Vector m_vecCurrentAvoid ;
// yaw to sway on
float m_flSwayYaw ;
// size of the shape
float m_flShapeSize ;
int m_iShapeAngle ;
float m_flSwayAmount ;
} ;
//-----------------------------------------------------------------------------
// Detail models
//-----------------------------------------------------------------------------
struct SptrintInfo_t
{
unsigned short m_nSpriteIndex ;
float16 m_flScale ;
} ;
class CDetailModel : public IClientUnknown , public IClientRenderable
{
DECLARE_CLASS_NOBASE ( CDetailModel ) ;
public :
CDetailModel ( ) ;
~ CDetailModel ( ) ;
// Initialization
bool InitCommon ( int index , const Vector & org , const QAngle & angles ) ;
bool Init ( int index , const Vector & org , const QAngle & angles , model_t * pModel ,
ColorRGBExp32 lighting , int lightstyle , unsigned char lightstylecount , int orientation ) ;
bool InitSprite ( int index , const Vector & org , const QAngle & angles , unsigned short nSpriteIndex ,
ColorRGBExp32 lighting , int lightstyle , unsigned char lightstylecount , int orientation , float flScale ,
unsigned char type , unsigned char shapeAngle , unsigned char shapeSize , unsigned char swayAmount ) ;
void SetAlpha ( unsigned char alpha ) { m_Alpha = alpha ; }
// IClientUnknown overrides.
public :
virtual IClientUnknown * GetIClientUnknown ( ) { return this ; }
virtual ICollideable * GetCollideable ( ) { return 0 ; } // Static props DO implement this.
virtual IClientNetworkable * GetClientNetworkable ( ) { return 0 ; }
virtual IClientRenderable * GetClientRenderable ( ) { return this ; }
virtual IClientEntity * GetIClientEntity ( ) { return 0 ; }
virtual C_BaseEntity * GetBaseEntity ( ) { return 0 ; }
virtual IClientThinkable * GetClientThinkable ( ) { return 0 ; }
// IClientRenderable overrides.
public :
virtual int GetBody ( ) { return 0 ; }
virtual const Vector & GetRenderOrigin ( ) ;
virtual const QAngle & GetRenderAngles ( ) ;
virtual const matrix3x4_t & RenderableToWorldTransform ( ) ;
virtual bool ShouldDraw ( ) ;
virtual bool IsTransparent ( void ) ;
virtual const model_t * GetModel ( ) const ;
virtual int DrawModel ( int flags ) ;
virtual void ComputeFxBlend ( ) ;
virtual int GetFxBlend ( ) ;
virtual bool SetupBones ( matrix3x4_t * pBoneToWorldOut , int nMaxBones , int boneMask , float currentTime ) ;
virtual void SetupWeights ( void ) ;
virtual void DoAnimationEvents ( void ) ;
virtual void GetRenderBounds ( Vector & mins , Vector & maxs ) ;
virtual IPVSNotify * GetPVSNotifyInterface ( ) ;
virtual void GetRenderBoundsWorldspace ( Vector & mins , Vector & maxs ) ;
virtual bool ShouldReceiveProjectedTextures ( int flags ) ;
virtual bool GetShadowCastDistance ( float * pDist , ShadowType_t shadowType ) const { return false ; }
virtual bool GetShadowCastDirection ( Vector * pDirection , ShadowType_t shadowType ) const { return false ; }
virtual bool UsesFrameBufferTexture ( ) ;
virtual bool LODTest ( ) { return true ; }
virtual ClientShadowHandle_t GetShadowHandle ( ) const ;
virtual ClientRenderHandle_t & RenderHandle ( ) ;
virtual void GetShadowRenderBounds ( Vector & mins , Vector & maxs , ShadowType_t shadowType ) ;
virtual bool IsShadowDirty ( ) { return false ; }
virtual void MarkShadowDirty ( bool bDirty ) { }
virtual IClientRenderable * GetShadowParent ( ) { return NULL ; }
virtual IClientRenderable * FirstShadowChild ( ) { return NULL ; }
virtual IClientRenderable * NextShadowPeer ( ) { return NULL ; }
virtual ShadowType_t ShadowCastType ( ) { return SHADOWS_NONE ; }
virtual void CreateModelInstance ( ) { }
virtual ModelInstanceHandle_t GetModelInstance ( ) { return MODEL_INSTANCE_INVALID ; }
virtual int LookupAttachment ( const char * pAttachmentName ) { return - 1 ; }
virtual bool GetAttachment ( int number , matrix3x4_t & matrix ) ;
virtual bool GetAttachment ( int number , Vector & origin , QAngle & angles ) ;
virtual float * GetRenderClipPlane ( void ) { return NULL ; }
virtual int GetSkin ( void ) { return 0 ; }
void GetColorModulation ( float * color ) ;
// Computes the render angles for screen alignment
void ComputeAngles ( void ) ;
// Calls the correct rendering func
void DrawSprite ( CMeshBuilder & meshBuilder ) ;
// Returns the number of quads the sprite will draw
int QuadsToDraw ( ) const ;
// Draw functions for the different types of sprite
void DrawTypeSprite ( CMeshBuilder & meshBuilder ) ;
# ifdef USE_DETAIL_SHAPES
void DrawTypeShapeCross ( CMeshBuilder & meshBuilder ) ;
void DrawTypeShapeTri ( CMeshBuilder & meshBuilder ) ;
// check for players nearby and angle away from them
void UpdatePlayerAvoid ( void ) ;
void InitShapedSprite ( unsigned char shapeAngle , unsigned char shapeSize , unsigned char swayAmount ) ;
void InitShapeTri ( ) ;
void InitShapeCross ( ) ;
void DrawSwayingQuad ( CMeshBuilder & meshBuilder , Vector vecOrigin , Vector vecSway , Vector2D texul , Vector2D texlr , unsigned char * color ,
Vector width , Vector height ) ;
# endif
int GetType ( ) const { return m_Type ; }
unsigned char GetAlpha ( ) const { return m_Alpha ; }
bool IsDetailModelTranslucent ( ) ;
// IHandleEntity stubs.
public :
virtual void SetRefEHandle ( const CBaseHandle & handle ) { Assert ( false ) ; }
virtual const CBaseHandle & GetRefEHandle ( ) const { Assert ( false ) ; return * ( ( CBaseHandle * ) 0 ) ; }
//---------------------------------
struct LightStyleInfo_t
{
unsigned int m_LightStyle : 24 ;
unsigned int m_LightStyleCount : 8 ;
} ;
protected :
Vector m_Origin ;
QAngle m_Angles ;
ColorRGBExp32 m_Color ;
unsigned char m_Orientation : 2 ;
unsigned char m_Type : 2 ;
unsigned char m_bHasLightStyle : 1 ;
unsigned char m_bFlipped : 1 ;
unsigned char m_Alpha ;
static CUtlMap < CDetailModel * , LightStyleInfo_t > gm_LightStylesMap ;
# pragma warning( disable : 4201 ) //warning C4201: nonstandard extension used : nameless struct/union
union
{
model_t * m_pModel ;
SptrintInfo_t m_SpriteInfo ;
} ;
# pragma warning( default : 4201 )
# ifdef USE_DETAIL_SHAPES
// pointer to advanced properties
DetailModelAdvInfo_t * m_pAdvInfo ;
# endif
} ;
static ConVar mat_fullbright ( " mat_fullbright " , " 0 " , FCVAR_CHEAT ) ; // hook into engine's cvars..
extern ConVar r_DrawDetailProps ;
//-----------------------------------------------------------------------------
// Dictionary for detail sprites
//-----------------------------------------------------------------------------
struct DetailPropSpriteDict_t
{
Vector2D m_UL ; // Coordinate of upper left
Vector2D m_LR ; // Coordinate of lower right
Vector2D m_TexUL ; // Texcoords of upper left
Vector2D m_TexLR ; // Texcoords of lower left
} ;
//-----------------------------------------------------------------------------
// Responsible for managing detail objects
//-----------------------------------------------------------------------------
class CDetailObjectSystem : public IDetailObjectSystem , public ISpatialLeafEnumerator
{
public :
virtual char const * Name ( ) { return " DetailObjectSystem " ; }
// constructor, destructor
CDetailObjectSystem ( ) ;
virtual ~ CDetailObjectSystem ( ) ;
virtual bool IsPerFrame ( ) { return false ; }
// Init, shutdown
virtual bool Init ( )
{
m_flDefaultFadeStart = cl_detailfade . GetFloat ( ) ;
m_flDefaultFadeEnd = cl_detaildist . GetFloat ( ) ;
return true ;
}
virtual void Shutdown ( ) { }
// Level init, shutdown
virtual void LevelInitPreEntity ( ) ;
virtual void LevelInitPostEntity ( ) ;
virtual void LevelShutdownPreEntity ( ) ;
virtual void LevelShutdownPostEntity ( ) ;
virtual void OnSave ( ) { }
virtual void OnRestore ( ) { }
virtual void SafeRemoveIfDesired ( ) { }
// Gets a particular detail object
virtual IClientRenderable * GetDetailModel ( int idx ) ;
// Prepares detail for rendering
virtual void BuildDetailObjectRenderLists ( ) ;
// Renders all opaque detail objects in a particular set of leaves
virtual void RenderOpaqueDetailObjects ( int nLeafCount , LeafIndex_t * pLeafList ) ;
// Renders all translucent detail objects in a particular set of leaves
virtual void RenderTranslucentDetailObjects ( const Vector & viewOrigin , const Vector & viewForward , int nLeafCount , LeafIndex_t * pLeafList ) ;
// Renders all translucent detail objects in a particular leaf up to a particular point
virtual void RenderTranslucentDetailObjectsInLeaf ( const Vector & viewOrigin , const Vector & viewForward , int nLeaf , const Vector * pVecClosestPoint ) ;
// Call this before rendering translucent detail objects
virtual void BeginTranslucentDetailRendering ( ) ;
// Method of ISpatialLeafEnumerator
bool EnumerateLeaf ( int leaf , int context ) ;
DetailPropLightstylesLump_t & DetailLighting ( int i ) { return m_DetailLighting [ i ] ; }
DetailPropSpriteDict_t & DetailSpriteDict ( int i ) { return m_DetailSpriteDict [ i ] ; }
private :
struct DetailModelDict_t
{
model_t * m_pModel ;
} ;
struct EnumContext_t
{
float m_MaxSqDist ;
float m_FadeSqDist ;
float m_FalloffFactor ;
int m_BuildWorldListNumber ;
} ;
struct SortInfo_t
{
int m_nIndex ;
float m_flDistance ;
} ;
enum
{
MAX_SPRITES_PER_LEAF = 4096
} ;
// Unserialization
void UnserializeModelDict ( CUtlBuffer & buf ) ;
void UnserializeDetailSprites ( CUtlBuffer & buf ) ;
void UnserializeModels ( CUtlBuffer & buf ) ;
void UnserializeModelLighting ( CUtlBuffer & buf ) ;
// Count the number of detail sprites in the leaf list
int CountSpritesInLeafList ( int nLeafCount , LeafIndex_t * pLeafList ) ;
// Count the number of detail sprite quads in the leaf list
int CountSpriteQuadsInLeafList ( int nLeafCount , LeafIndex_t * pLeafList ) ;
// Sorts sprites in back-to-front order
static int __cdecl SortFunc ( const void * arg1 , const void * arg2 ) ;
int SortSpritesBackToFront ( int nLeaf , const Vector & viewOrigin , const Vector & viewForward , SortInfo_t * pSortInfo ) ;
// For fast detail object insertion
IterationRetval_t EnumElement ( int userId , int context ) ;
CUtlVector < DetailModelDict_t > m_DetailObjectDict ;
CUtlVector < CDetailModel > m_DetailObjects ;
CUtlVector < DetailPropSpriteDict_t > m_DetailSpriteDict ;
CUtlVector < DetailPropLightstylesLump_t > m_DetailLighting ;
// Necessary to get sprites to batch correctly
CMaterialReference m_DetailSpriteMaterial ;
CMaterialReference m_DetailWireframeMaterial ;
// State stored off for rendering detail sprites in a single leaf
int m_nSpriteCount ;
int m_nFirstSprite ;
int m_nSortedLeaf ;
SortInfo_t m_pSortInfo [ MAX_SPRITES_PER_LEAF ] ;
float m_flDefaultFadeStart ;
float m_flDefaultFadeEnd ;
} ;
//-----------------------------------------------------------------------------
// System for dealing with detail objects
//-----------------------------------------------------------------------------
static CDetailObjectSystem s_DetailObjectSystem ;
IDetailObjectSystem * DetailObjectSystem ( )
{
return & s_DetailObjectSystem ;
}
//-----------------------------------------------------------------------------
// Initialization
//-----------------------------------------------------------------------------
CUtlMap < CDetailModel * , CDetailModel : : LightStyleInfo_t > CDetailModel : : gm_LightStylesMap ( DefLessFunc ( CDetailModel * ) ) ;
bool CDetailModel : : InitCommon ( int index , const Vector & org , const QAngle & angles )
{
VectorCopy ( org , m_Origin ) ;
VectorCopy ( angles , m_Angles ) ;
m_Alpha = 255 ;
return true ;
}
//-----------------------------------------------------------------------------
// Inline methods
//-----------------------------------------------------------------------------
// NOTE: If DetailPropType_t enum changes, change CDetailModel::QuadsToDraw
static int s_pQuadCount [ 4 ] =
{
0 , //DETAIL_PROP_TYPE_MODEL
1 , //DETAIL_PROP_TYPE_SPRITE
4 , //DETAIL_PROP_TYPE_SHAPE_CROSS
3 , //DETAIL_PROP_TYPE_SHAPE_TRI
} ;
inline int CDetailModel : : QuadsToDraw ( ) const
{
return s_pQuadCount [ m_Type ] ;
}
//-----------------------------------------------------------------------------
// Data accessors
//-----------------------------------------------------------------------------
const Vector & CDetailModel : : GetRenderOrigin ( void )
{
return m_Origin ;
}
const QAngle & CDetailModel : : GetRenderAngles ( void )
{
return m_Angles ;
}
const matrix3x4_t & CDetailModel : : RenderableToWorldTransform ( )
{
// Setup our transform.
static matrix3x4_t mat ;
AngleMatrix ( GetRenderAngles ( ) , GetRenderOrigin ( ) , mat ) ;
return mat ;
}
bool CDetailModel : : GetAttachment ( int number , matrix3x4_t & matrix )
{
MatrixCopy ( RenderableToWorldTransform ( ) , matrix ) ;
return true ;
}
bool CDetailModel : : GetAttachment ( int number , Vector & origin , QAngle & angles )
{
origin = m_Origin ;
angles = m_Angles ;
return true ;
}
bool CDetailModel : : IsTransparent ( void )
{
return ( m_Alpha < 255 ) | | modelinfo - > IsTranslucent ( m_pModel ) ;
}
bool CDetailModel : : ShouldDraw ( )
{
// Don't draw in commander mode
return g_pClientMode - > ShouldDrawDetailObjects ( ) ;
}
void CDetailModel : : GetRenderBounds ( Vector & mins , Vector & maxs )
{
int nModelType = modelinfo - > GetModelType ( m_pModel ) ;
if ( nModelType = = mod_studio | | nModelType = = mod_brush )
{
modelinfo - > GetModelRenderBounds ( GetModel ( ) , mins , maxs ) ;
}
else
{
mins . Init ( 0 , 0 , 0 ) ;
maxs . Init ( 0 , 0 , 0 ) ;
}
}
IPVSNotify * CDetailModel : : GetPVSNotifyInterface ( )
{
return NULL ;
}
void CDetailModel : : GetRenderBoundsWorldspace ( Vector & mins , Vector & maxs )
{
DefaultRenderBoundsWorldspace ( this , mins , maxs ) ;
}
bool CDetailModel : : ShouldReceiveProjectedTextures ( int flags )
{
return false ;
}
bool CDetailModel : : UsesFrameBufferTexture ( )
{
return false ;
}
void CDetailModel : : GetShadowRenderBounds ( Vector & mins , Vector & maxs , ShadowType_t shadowType )
{
GetRenderBounds ( mins , maxs ) ;
}
ClientShadowHandle_t CDetailModel : : GetShadowHandle ( ) const
{
return CLIENTSHADOW_INVALID_HANDLE ;
}
ClientRenderHandle_t & CDetailModel : : RenderHandle ( )
{
AssertMsg ( 0 , " CDetailModel has no render handle " ) ;
return * ( ( ClientRenderHandle_t * ) NULL ) ;
}
//-----------------------------------------------------------------------------
// Render setup
//-----------------------------------------------------------------------------
bool CDetailModel : : SetupBones ( matrix3x4_t * pBoneToWorldOut , int nMaxBones , int boneMask , float currentTime )
{
if ( ! m_pModel )
return false ;
// Setup our transform.
matrix3x4_t parentTransform ;
const QAngle & vRenderAngles = GetRenderAngles ( ) ;
const Vector & vRenderOrigin = GetRenderOrigin ( ) ;
AngleMatrix ( vRenderAngles , parentTransform ) ;
parentTransform [ 0 ] [ 3 ] = vRenderOrigin . x ;
parentTransform [ 1 ] [ 3 ] = vRenderOrigin . y ;
parentTransform [ 2 ] [ 3 ] = vRenderOrigin . z ;
// Just copy it on down baby
studiohdr_t * pStudioHdr = modelinfo - > GetStudiomodel ( m_pModel ) ;
for ( int i = 0 ; i < pStudioHdr - > numbones ; i + + )
{
MatrixCopy ( parentTransform , pBoneToWorldOut [ i ] ) ;
}
return true ;
}
void CDetailModel : : SetupWeights ( void )
{
}
void CDetailModel : : DoAnimationEvents ( void )
{
}
//-----------------------------------------------------------------------------
// Render baby!
//-----------------------------------------------------------------------------
const model_t * CDetailModel : : GetModel ( ) const
{
return m_pModel ;
}
int CDetailModel : : DrawModel ( int flags )
{
if ( ( m_Alpha = = 0 ) | | ( ! m_pModel ) )
return 0 ;
int drawn = modelrender - > DrawModel (
flags ,
this ,
MODEL_INSTANCE_INVALID ,
- 1 , // no entity index
m_pModel ,
m_Origin ,
m_Angles ,
0 , // skin
0 , // body
0 // hitboxset
) ;
return drawn ;
}
//-----------------------------------------------------------------------------
// Determine alpha and blend amount for transparent objects based on render state info
//-----------------------------------------------------------------------------
void CDetailModel : : ComputeFxBlend ( )
{
// Do nothing, it's already calculate in our m_Alpha
}
int CDetailModel : : GetFxBlend ( )
{
return m_Alpha ;
}
//-----------------------------------------------------------------------------
// Detail models stuff
//-----------------------------------------------------------------------------
CDetailModel : : CDetailModel ( )
{
m_Color . r = m_Color . g = m_Color . b = 255 ;
m_Color . exponent = 0 ;
m_bFlipped = 0 ;
m_bHasLightStyle = 0 ;
# ifdef USE_DETAIL_SHAPES
m_pAdvInfo = NULL ;
# endif
}
//-----------------------------------------------------------------------------
// Destructor
//-----------------------------------------------------------------------------
CDetailModel : : ~ CDetailModel ( )
{
# ifdef USE_DETAIL_SHAPES
// delete advanced
if ( m_pAdvInfo )
{
delete m_pAdvInfo ;
m_pAdvInfo = NULL ;
}
# endif
if ( m_bHasLightStyle )
gm_LightStylesMap . Remove ( this ) ;
}
//-----------------------------------------------------------------------------
// Initialization
//-----------------------------------------------------------------------------
bool CDetailModel : : Init ( int index , const Vector & org , const QAngle & angles ,
model_t * pModel , ColorRGBExp32 lighting , int lightstyle , unsigned char lightstylecount ,
int orientation )
{
m_Color = lighting ;
if ( lightstylecount > 0 )
{
m_bHasLightStyle = 1 ;
int iInfo = gm_LightStylesMap . Insert ( this ) ;
if ( lightstyle > = 0x1000000 | | lightstylecount > = 100 )
Error ( " Light style overflow \n " ) ;
gm_LightStylesMap [ iInfo ] . m_LightStyle = lightstyle ;
gm_LightStylesMap [ iInfo ] . m_LightStyleCount = lightstylecount ;
}
m_Orientation = orientation ;
m_Type = DETAIL_PROP_TYPE_MODEL ;
m_pModel = pModel ;
return InitCommon ( index , org , angles ) ;
}
bool CDetailModel : : InitSprite ( int index , const Vector & org , const QAngle & angles , unsigned short nSpriteIndex ,
ColorRGBExp32 lighting , int lightstyle , unsigned char lightstylecount , int orientation , float flScale ,
unsigned char type , unsigned char shapeAngle , unsigned char shapeSize , unsigned char swayAmount )
{
m_Color = lighting ;
if ( lightstylecount > 0 )
{
m_bHasLightStyle = 1 ;
int iInfo = gm_LightStylesMap . Insert ( this ) ;
if ( lightstyle > = 0x1000000 | | lightstylecount > = 100 )
Error ( " Light style overflow \n " ) ;
gm_LightStylesMap [ iInfo ] . m_LightStyle = lightstyle ;
gm_LightStylesMap [ iInfo ] . m_LightStyleCount = lightstylecount ;
}
m_Orientation = orientation ;
m_SpriteInfo . m_nSpriteIndex = nSpriteIndex ;
m_Type = type ;
m_SpriteInfo . m_flScale . SetFloat ( flScale ) ;
# ifdef USE_DETAIL_SHAPES
m_pAdvInfo = NULL ;
Assert ( type < = 3 ) ;
// precalculate angles for shapes
if ( type = = DETAIL_PROP_TYPE_SHAPE_TRI | | type = = DETAIL_PROP_TYPE_SHAPE_CROSS | | swayAmount > 0 )
{
m_Angles = angles ;
InitShapedSprite ( shapeAngle , shapeSize , swayAmount ) ;
}
# endif
m_bFlipped = ( ( index & 0x1 ) = = 1 ) ;
return InitCommon ( index , org , angles ) ;
}
# ifdef USE_DETAIL_SHAPES
void CDetailModel : : InitShapedSprite ( unsigned char shapeAngle , unsigned char shapeSize , unsigned char swayAmount )
{
// Set up pointer to advanced shape properties object ( per instance )
Assert ( m_pAdvInfo = = NULL ) ;
m_pAdvInfo = new DetailModelAdvInfo_t ;
Assert ( m_pAdvInfo ) ;
if ( m_pAdvInfo )
{
m_pAdvInfo - > m_iShapeAngle = shapeAngle ;
m_pAdvInfo - > m_flSwayAmount = ( float ) swayAmount / 255.0f ;
m_pAdvInfo - > m_flShapeSize = ( float ) shapeSize / 255.0f ;
m_pAdvInfo - > m_vecCurrentAvoid = vec3_origin ;
m_pAdvInfo - > m_flSwayYaw = random - > RandomFloat ( 0 , 180 ) ;
}
switch ( m_Type )
{
case DETAIL_PROP_TYPE_SHAPE_TRI :
InitShapeTri ( ) ;
break ;
case DETAIL_PROP_TYPE_SHAPE_CROSS :
InitShapeCross ( ) ;
break ;
default : // sprite will get here
break ;
}
}
void CDetailModel : : InitShapeTri ( void )
{
// store the three sets of directions
matrix3x4_t matrix ;
// Convert roll/pitch only to matrix
AngleMatrix ( m_Angles , matrix ) ;
// calculate the vectors for the three sides so they can be used in the sorting test
// as well as in drawing
for ( int i = 0 ; i < 3 ; i + + )
{
// Convert desired rotation to angles
QAngle anglesRotated ( m_pAdvInfo - > m_iShapeAngle , i * 120 , 0 ) ;
Vector rotForward , rotRight , rotUp ;
AngleVectors ( anglesRotated , & rotForward , & rotRight , & rotUp ) ;
// Rotate direction vectors
VectorRotate ( rotForward , matrix , m_pAdvInfo - > m_vecAnglesForward [ i ] ) ;
VectorRotate ( rotRight , matrix , m_pAdvInfo - > m_vecAnglesRight [ i ] ) ;
VectorRotate ( rotUp , matrix , m_pAdvInfo - > m_vecAnglesUp [ i ] ) ;
}
}
void CDetailModel : : InitShapeCross ( void )
{
AngleVectors ( m_Angles ,
& m_pAdvInfo - > m_vecAnglesForward [ 0 ] ,
& m_pAdvInfo - > m_vecAnglesRight [ 0 ] ,
& m_pAdvInfo - > m_vecAnglesUp [ 0 ] ) ;
}
# endif
//-----------------------------------------------------------------------------
// Color, alpha modulation
//-----------------------------------------------------------------------------
void CDetailModel : : GetColorModulation ( float * color )
{
if ( mat_fullbright . GetInt ( ) = = 1 )
{
color [ 0 ] = color [ 1 ] = color [ 2 ] = 1.0f ;
return ;
}
Vector tmp ;
Vector normal ( 1 , 0 , 0 ) ;
engine - > ComputeDynamicLighting ( m_Origin , & normal , tmp ) ;
float val = engine - > LightStyleValue ( 0 ) ;
color [ 0 ] = tmp [ 0 ] + val * TexLightToLinear ( m_Color . r , m_Color . exponent ) ;
color [ 1 ] = tmp [ 1 ] + val * TexLightToLinear ( m_Color . g , m_Color . exponent ) ;
color [ 2 ] = tmp [ 2 ] + val * TexLightToLinear ( m_Color . b , m_Color . exponent ) ;
// Add in the lightstyles
if ( m_bHasLightStyle )
{
int iInfo = gm_LightStylesMap . Find ( this ) ;
Assert ( iInfo ! = gm_LightStylesMap . InvalidIndex ( ) ) ;
if ( iInfo ! = gm_LightStylesMap . InvalidIndex ( ) )
{
int nLightStyles = gm_LightStylesMap [ iInfo ] . m_LightStyleCount ;
int iLightStyle = gm_LightStylesMap [ iInfo ] . m_LightStyle ;
for ( int i = 0 ; i < nLightStyles ; + + i )
{
DetailPropLightstylesLump_t & lighting = s_DetailObjectSystem . DetailLighting ( iLightStyle + i ) ;
val = engine - > LightStyleValue ( lighting . m_Style ) ;
if ( val ! = 0 )
{
color [ 0 ] + = val * TexLightToLinear ( lighting . m_Lighting . r , lighting . m_Lighting . exponent ) ;
color [ 1 ] + = val * TexLightToLinear ( lighting . m_Lighting . g , lighting . m_Lighting . exponent ) ;
color [ 2 ] + = val * TexLightToLinear ( lighting . m_Lighting . b , lighting . m_Lighting . exponent ) ;
}
}
}
}
// Gamma correct....
engine - > LinearToGamma ( color , color ) ;
}
//-----------------------------------------------------------------------------
// Is the model itself translucent, regardless of modulation?
//-----------------------------------------------------------------------------
bool CDetailModel : : IsDetailModelTranslucent ( )
{
// FIXME: This is only true for my first pass of this feature
if ( m_Type > = DETAIL_PROP_TYPE_SPRITE )
return true ;
return modelinfo - > IsTranslucent ( GetModel ( ) ) ;
}
//-----------------------------------------------------------------------------
// Computes the render angles for screen alignment
//-----------------------------------------------------------------------------
void CDetailModel : : ComputeAngles ( void )
{
switch ( m_Orientation )
{
case 0 :
break ;
case 1 :
{
Vector vecDir ;
VectorSubtract ( CurrentViewOrigin ( ) , m_Origin , vecDir ) ;
VectorAngles ( vecDir , m_Angles ) ;
}
break ;
case 2 :
{
Vector vecDir ;
VectorSubtract ( CurrentViewOrigin ( ) , m_Origin , vecDir ) ;
vecDir . z = 0.0f ;
VectorAngles ( vecDir , m_Angles ) ;
}
break ;
}
}
//-----------------------------------------------------------------------------
// Select which rendering func to call
//-----------------------------------------------------------------------------
void CDetailModel : : DrawSprite ( CMeshBuilder & meshBuilder )
{
switch ( m_Type )
{
# ifdef USE_DETAIL_SHAPES
case DETAIL_PROP_TYPE_SHAPE_CROSS :
DrawTypeShapeCross ( meshBuilder ) ;
break ;
case DETAIL_PROP_TYPE_SHAPE_TRI :
DrawTypeShapeTri ( meshBuilder ) ;
break ;
# endif
case DETAIL_PROP_TYPE_SPRITE :
DrawTypeSprite ( meshBuilder ) ;
break ;
default :
Assert ( 0 ) ;
break ;
}
}
//-----------------------------------------------------------------------------
// Draws the single sprite type
//-----------------------------------------------------------------------------
void CDetailModel : : DrawTypeSprite ( CMeshBuilder & meshBuilder )
{
Assert ( m_Type = = DETAIL_PROP_TYPE_SPRITE ) ;
Vector vecColor ;
GetColorModulation ( vecColor . Base ( ) ) ;
unsigned char color [ 4 ] ;
color [ 0 ] = ( unsigned char ) ( vecColor [ 0 ] * 255.0f ) ;
color [ 1 ] = ( unsigned char ) ( vecColor [ 1 ] * 255.0f ) ;
color [ 2 ] = ( unsigned char ) ( vecColor [ 2 ] * 255.0f ) ;
color [ 3 ] = m_Alpha ;
DetailPropSpriteDict_t & dict = s_DetailObjectSystem . DetailSpriteDict ( m_SpriteInfo . m_nSpriteIndex ) ;
Vector vecOrigin , dx , dy ;
AngleVectors ( m_Angles , NULL , & dx , & dy ) ;
Vector2D ul , lr ;
float scale = m_SpriteInfo . m_flScale . GetFloat ( ) ;
Vector2DMultiply ( dict . m_UL , scale , ul ) ;
Vector2DMultiply ( dict . m_LR , scale , lr ) ;
# ifdef USE_DETAIL_SHAPES
UpdatePlayerAvoid ( ) ;
Vector vecSway = vec3_origin ;
if ( m_pAdvInfo )
{
vecSway = m_pAdvInfo - > m_vecCurrentAvoid * m_SpriteInfo . m_flScale . GetFloat ( ) ;
float flSwayAmplitude = m_pAdvInfo - > m_flSwayAmount * cl_detail_max_sway . GetFloat ( ) ;
if ( flSwayAmplitude > 0 )
{
// sway based on time plus a random seed that is constant for this instance of the sprite
vecSway + = dx * sin ( gpGlobals - > curtime + m_Origin . x ) * flSwayAmplitude ;
}
}
# endif
VectorMA ( m_Origin , ul . x , dx , vecOrigin ) ;
VectorMA ( vecOrigin , ul . y , dy , vecOrigin ) ;
dx * = ( lr . x - ul . x ) ;
dy * = ( lr . y - ul . y ) ;
Vector2D texul , texlr ;
texul = dict . m_TexUL ;
texlr = dict . m_TexLR ;
if ( ! m_bFlipped )
{
texul . x = dict . m_TexLR . x ;
texlr . x = dict . m_TexUL . x ;
}
# ifndef USE_DETAIL_SHAPES
meshBuilder . Position3fv ( vecOrigin . Base ( ) ) ;
# else
meshBuilder . Position3fv ( ( vecOrigin + vecSway ) . Base ( ) ) ;
# endif
meshBuilder . Color4ubv ( color ) ;
meshBuilder . TexCoord2fv ( 0 , texul . Base ( ) ) ;
meshBuilder . AdvanceVertex ( ) ;
vecOrigin + = dy ;
meshBuilder . Position3fv ( vecOrigin . Base ( ) ) ;
meshBuilder . Color4ubv ( color ) ;
meshBuilder . TexCoord2f ( 0 , texul . x , texlr . y ) ;
meshBuilder . AdvanceVertex ( ) ;
vecOrigin + = dx ;
meshBuilder . Position3fv ( vecOrigin . Base ( ) ) ;
meshBuilder . Color4ubv ( color ) ;
meshBuilder . TexCoord2fv ( 0 , texlr . Base ( ) ) ;
meshBuilder . AdvanceVertex ( ) ;
vecOrigin - = dy ;
# ifndef USE_DETAIL_SHAPES
meshBuilder . Position3fv ( vecOrigin . Base ( ) ) ;
# else
meshBuilder . Position3fv ( ( vecOrigin + vecSway ) . Base ( ) ) ;
# endif
meshBuilder . Color4ubv ( color ) ;
meshBuilder . TexCoord2f ( 0 , texlr . x , texul . y ) ;
meshBuilder . AdvanceVertex ( ) ;
}
//-----------------------------------------------------------------------------
// draws a procedural model, cross shape
// two perpendicular sprites
//-----------------------------------------------------------------------------
# ifdef USE_DETAIL_SHAPES
void CDetailModel : : DrawTypeShapeCross ( CMeshBuilder & meshBuilder )
{
Assert ( m_Type = = DETAIL_PROP_TYPE_SHAPE_CROSS ) ;
Vector vecColor ;
GetColorModulation ( vecColor . Base ( ) ) ;
unsigned char color [ 4 ] ;
color [ 0 ] = ( unsigned char ) ( vecColor [ 0 ] * 255.0f ) ;
color [ 1 ] = ( unsigned char ) ( vecColor [ 1 ] * 255.0f ) ;
color [ 2 ] = ( unsigned char ) ( vecColor [ 2 ] * 255.0f ) ;
color [ 3 ] = m_Alpha ;
DetailPropSpriteDict_t & dict = s_DetailObjectSystem . DetailSpriteDict ( m_SpriteInfo . m_nSpriteIndex ) ;
Vector2D texul , texlr ;
texul = dict . m_TexUL ;
texlr = dict . m_TexLR ;
// What a shameless re-use of bits (m_pModel == 0 when it should be flipped horizontally)
if ( ! m_pModel )
{
texul . x = dict . m_TexLR . x ;
texlr . x = dict . m_TexUL . x ;
}
Vector2D texumid , texlmid ;
texumid . y = texul . y ;
texlmid . y = texlr . y ;
texumid . x = texlmid . x = ( texul . x + texlr . x ) / 2 ;
Vector2D texll ;
texll . x = texul . x ;
texll . y = texlr . y ;
Vector2D ul , lr ;
float flScale = m_SpriteInfo . m_flScale . GetFloat ( ) ;
Vector2DMultiply ( dict . m_UL , flScale , ul ) ;
Vector2DMultiply ( dict . m_LR , flScale , lr ) ;
float flSizeX = ( lr . x - ul . x ) / 2 ;
float flSizeY = ( lr . y - ul . y ) ;
UpdatePlayerAvoid ( ) ;
// sway based on time plus a random seed that is constant for this instance of the sprite
Vector vecSway = ( m_pAdvInfo - > m_vecCurrentAvoid * flSizeX * 2 ) ;
float flSwayAmplitude = m_pAdvInfo - > m_flSwayAmount * cl_detail_max_sway . GetFloat ( ) ;
if ( flSwayAmplitude > 0 )
{
vecSway + = UTIL_YawToVector ( m_pAdvInfo - > m_flSwayYaw ) * sin ( gpGlobals - > curtime + m_Origin . x ) * flSwayAmplitude ;
}
Vector vecOrigin ;
VectorMA ( m_Origin , ul . y , m_pAdvInfo - > m_vecAnglesUp [ 0 ] , vecOrigin ) ;
Vector forward , right , up ;
forward = m_pAdvInfo - > m_vecAnglesForward [ 0 ] * flSizeX ;
right = m_pAdvInfo - > m_vecAnglesRight [ 0 ] * flSizeX ;
up = m_pAdvInfo - > m_vecAnglesUp [ 0 ] * flSizeY ;
// figure out drawing order so the branches sort properly
// do dot products with the forward and right vectors to determine the quadrant the viewer is in
// assume forward points North , right points East
/*
N
|
3 | 0
W - - - - - - - - - E
2 | 1
|
S
*/
// eg if they are in quadrant 0, set iBranch to 0, and the draw order will be
// 0, 1, 2, 3, or South, west, north, east
Vector viewOffset = CurrentViewOrigin ( ) - m_Origin ;
bool bForward = ( DotProduct ( forward , viewOffset ) > 0 ) ;
bool bRight = ( DotProduct ( right , viewOffset ) > 0 ) ;
int iBranch = bForward ? ( bRight ? 0 : 3 ) : ( bRight ? 1 : 2 ) ;
//debugoverlay->AddLineOverlay( m_Origin, m_Origin + right * 20, 255, 0, 0, true, 0.01 );
//debugoverlay->AddLineOverlay( m_Origin, m_Origin + forward * 20, 0, 0, 255, true, 0.01 );
int iDrawn = 0 ;
while ( iDrawn < 4 )
{
switch ( iBranch )
{
case 0 : // south
DrawSwayingQuad ( meshBuilder , vecOrigin , vecSway , texumid , texlr , color , - forward , up ) ;
break ;
case 1 : // west
DrawSwayingQuad ( meshBuilder , vecOrigin , vecSway , texumid , texll , color , - right , up ) ;
break ;
case 2 : // north
DrawSwayingQuad ( meshBuilder , vecOrigin , vecSway , texumid , texll , color , forward , up ) ;
break ;
case 3 : // east
DrawSwayingQuad ( meshBuilder , vecOrigin , vecSway , texumid , texlr , color , right , up ) ;
break ;
}
iDrawn + + ;
iBranch + + ;
if ( iBranch > 3 )
iBranch = 0 ;
}
}
# endif
//-----------------------------------------------------------------------------
// draws a procedural model, tri shape
//-----------------------------------------------------------------------------
# ifdef USE_DETAIL_SHAPES
void CDetailModel : : DrawTypeShapeTri ( CMeshBuilder & meshBuilder )
{
Assert ( m_Type = = DETAIL_PROP_TYPE_SHAPE_TRI ) ;
Vector vecColor ;
GetColorModulation ( vecColor . Base ( ) ) ;
unsigned char color [ 4 ] ;
color [ 0 ] = ( unsigned char ) ( vecColor [ 0 ] * 255.0f ) ;
color [ 1 ] = ( unsigned char ) ( vecColor [ 1 ] * 255.0f ) ;
color [ 2 ] = ( unsigned char ) ( vecColor [ 2 ] * 255.0f ) ;
color [ 3 ] = m_Alpha ;
DetailPropSpriteDict_t & dict = s_DetailObjectSystem . DetailSpriteDict ( m_SpriteInfo . m_nSpriteIndex ) ;
Vector2D texul , texlr ;
texul = dict . m_TexUL ;
texlr = dict . m_TexLR ;
// What a shameless re-use of bits (m_pModel == 0 when it should be flipped horizontally)
if ( ! m_pModel )
{
texul . x = dict . m_TexLR . x ;
texlr . x = dict . m_TexUL . x ;
}
Vector2D ul , lr ;
float flScale = m_SpriteInfo . m_flScale . GetFloat ( ) ;
Vector2DMultiply ( dict . m_UL , flScale , ul ) ;
Vector2DMultiply ( dict . m_LR , flScale , lr ) ;
// sort the sides relative to the view origin
Vector viewOffset = CurrentViewOrigin ( ) - m_Origin ;
// three sides, A, B, C, counter-clockwise from A is the unrotated side
bool bOutsideA = DotProduct ( m_pAdvInfo - > m_vecAnglesForward [ 0 ] , viewOffset ) > 0 ;
bool bOutsideB = DotProduct ( m_pAdvInfo - > m_vecAnglesForward [ 1 ] , viewOffset ) > 0 ;
bool bOutsideC = DotProduct ( m_pAdvInfo - > m_vecAnglesForward [ 2 ] , viewOffset ) > 0 ;
int iBranch = 0 ;
if ( bOutsideA & & ! bOutsideB )
iBranch = 1 ;
else if ( bOutsideB & & ! bOutsideC )
iBranch = 2 ;
float flHeight , flWidth ;
flHeight = ( lr . y - ul . y ) ;
flWidth = ( lr . x - ul . x ) ;
Vector vecSway ;
Vector vecOrigin ;
Vector vecHeight , vecWidth ;
UpdatePlayerAvoid ( ) ;
Vector vecSwayYaw = UTIL_YawToVector ( m_pAdvInfo - > m_flSwayYaw ) ;
float flSwayAmplitude = m_pAdvInfo - > m_flSwayAmount * cl_detail_max_sway . GetFloat ( ) ;
int iDrawn = 0 ;
while ( iDrawn < 3 )
{
vecHeight = m_pAdvInfo - > m_vecAnglesUp [ iBranch ] * flHeight ;
vecWidth = m_pAdvInfo - > m_vecAnglesRight [ iBranch ] * flWidth ;
VectorMA ( m_Origin , ul . x , m_pAdvInfo - > m_vecAnglesRight [ iBranch ] , vecOrigin ) ;
VectorMA ( vecOrigin , ul . y , m_pAdvInfo - > m_vecAnglesUp [ iBranch ] , vecOrigin ) ;
VectorMA ( vecOrigin , m_pAdvInfo - > m_flShapeSize * flWidth , m_pAdvInfo - > m_vecAnglesForward [ iBranch ] , vecOrigin ) ;
// sway is calculated per side so they don't sway exactly the same
Vector vecSway = ( m_pAdvInfo - > m_vecCurrentAvoid * flWidth ) +
vecSwayYaw * sin ( gpGlobals - > curtime + m_Origin . x + iBranch ) * flSwayAmplitude ;
DrawSwayingQuad ( meshBuilder , vecOrigin , vecSway , texul , texlr , color , vecWidth , vecHeight ) ;
iDrawn + + ;
iBranch + + ;
if ( iBranch > 2 )
iBranch = 0 ;
}
}
# endif
//-----------------------------------------------------------------------------
// checks for nearby players and pushes the detail to the side
//-----------------------------------------------------------------------------
# ifdef USE_DETAIL_SHAPES
void CDetailModel : : UpdatePlayerAvoid ( void )
{
float flForce = cl_detail_avoid_force . GetFloat ( ) ;
if ( flForce < 0.1 )
return ;
if ( m_pAdvInfo = = NULL )
return ;
// get players in a radius
float flRadius = cl_detail_avoid_radius . GetFloat ( ) ;
float flRecoverSpeed = cl_detail_avoid_recover_speed . GetFloat ( ) ;
Vector vecAvoid ;
C_BaseEntity * pEnt ;
float flMaxForce = 0 ;
Vector vecMaxAvoid ( 0 , 0 , 0 ) ;
CPlayerEnumerator avoid ( flRadius , m_Origin ) ;
partition - > EnumerateElementsInSphere ( PARTITION_CLIENT_SOLID_EDICTS , m_Origin , flRadius , false , & avoid ) ;
// Okay, decide how to avoid if there's anything close by
int c = avoid . GetObjectCount ( ) ;
for ( int i = 0 ; i < c + 1 ; i + + ) // +1 for the local player we tack on the end
{
if ( i = = c )
{
pEnt = C_BasePlayer : : GetLocalPlayer ( ) ;
if ( ! pEnt ) continue ;
}
else
pEnt = avoid . GetObject ( i ) ;
vecAvoid = m_Origin - pEnt - > GetAbsOrigin ( ) ;
vecAvoid . z = 0 ;
float flDist = vecAvoid . Length2D ( ) ;
if ( flDist > flRadius )
continue ;
float flForceScale = RemapValClamped ( flDist , 0 , flRadius , flForce , 0.0 ) ;
if ( flForceScale > flMaxForce )
{
flMaxForce = flForceScale ;
vecAvoid . NormalizeInPlace ( ) ;
vecAvoid * = flMaxForce ;
vecMaxAvoid = vecAvoid ;
}
}
// if we are being moved, move fast. Else we recover at a slow rate
if ( vecMaxAvoid . Length2D ( ) > m_pAdvInfo - > m_vecCurrentAvoid . Length2D ( ) )
flRecoverSpeed = 10 ; // fast approach
m_pAdvInfo - > m_vecCurrentAvoid [ 0 ] = Approach ( vecMaxAvoid [ 0 ] , m_pAdvInfo - > m_vecCurrentAvoid [ 0 ] , flRecoverSpeed ) ;
m_pAdvInfo - > m_vecCurrentAvoid [ 1 ] = Approach ( vecMaxAvoid [ 1 ] , m_pAdvInfo - > m_vecCurrentAvoid [ 1 ] , flRecoverSpeed ) ;
m_pAdvInfo - > m_vecCurrentAvoid [ 2 ] = Approach ( vecMaxAvoid [ 2 ] , m_pAdvInfo - > m_vecCurrentAvoid [ 2 ] , flRecoverSpeed ) ;
}
# endif
//-----------------------------------------------------------------------------
// draws a quad that sways on the top two vertices
// pass vecOrigin as the top left vertex position
//-----------------------------------------------------------------------------
# ifdef USE_DETAIL_SHAPES
void CDetailModel : : DrawSwayingQuad ( CMeshBuilder & meshBuilder , Vector vecOrigin , Vector vecSway , Vector2D texul , Vector2D texlr , unsigned char * color ,
Vector width , Vector height )
{
meshBuilder . Position3fv ( ( vecOrigin + vecSway ) . Base ( ) ) ;
meshBuilder . TexCoord2fv ( 0 , texul . Base ( ) ) ;
meshBuilder . Color4ubv ( color ) ;
meshBuilder . AdvanceVertex ( ) ;
vecOrigin + = height ;
meshBuilder . Position3fv ( vecOrigin . Base ( ) ) ;
meshBuilder . TexCoord2f ( 0 , texul . x , texlr . y ) ;
meshBuilder . Color4ubv ( color ) ;
meshBuilder . AdvanceVertex ( ) ;
vecOrigin + = width ;
meshBuilder . Position3fv ( vecOrigin . Base ( ) ) ;
meshBuilder . TexCoord2fv ( 0 , texlr . Base ( ) ) ;
meshBuilder . Color4ubv ( color ) ;
meshBuilder . AdvanceVertex ( ) ;
vecOrigin - = height ;
meshBuilder . Position3fv ( ( vecOrigin + vecSway ) . Base ( ) ) ;
meshBuilder . TexCoord2f ( 0 , texlr . x , texul . y ) ;
meshBuilder . Color4ubv ( color ) ;
meshBuilder . AdvanceVertex ( ) ;
}
# endif
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
CDetailObjectSystem : : CDetailObjectSystem ( ) : m_DetailSpriteDict ( 0 , 32 ) , m_DetailObjectDict ( 0 , 32 )
{
BuildExponentTable ( ) ;
}
CDetailObjectSystem : : ~ CDetailObjectSystem ( )
{
}
//-----------------------------------------------------------------------------
// Level init, shutdown
//-----------------------------------------------------------------------------
void CDetailObjectSystem : : LevelInitPreEntity ( )
{
// Prepare the translucent detail sprite material; we only have 1!
m_DetailSpriteMaterial . Init ( " detail/detailsprites " , TEXTURE_GROUP_OTHER ) ;
m_DetailWireframeMaterial . Init ( " debug/debugspritewireframe " , TEXTURE_GROUP_OTHER ) ;
// Version check
if ( engine - > GameLumpVersion ( GAMELUMP_DETAIL_PROPS ) < 4 )
{
Warning ( " Map uses old detail prop file format.. ignoring detail props \n " ) ;
return ;
}
// Unserialize
int size = engine - > GameLumpSize ( GAMELUMP_DETAIL_PROPS ) ;
CUtlMemory < unsigned char > fileMemory ;
fileMemory . EnsureCapacity ( size ) ;
if ( engine - > LoadGameLump ( GAMELUMP_DETAIL_PROPS , fileMemory . Base ( ) , size ) )
{
CUtlBuffer buf ( fileMemory . Base ( ) , size , CUtlBuffer : : READ_ONLY ) ;
UnserializeModelDict ( buf ) ;
switch ( engine - > GameLumpVersion ( GAMELUMP_DETAIL_PROPS ) )
{
case 4 :
UnserializeDetailSprites ( buf ) ;
UnserializeModels ( buf ) ;
break ;
}
}
if ( m_DetailObjects . Count ( ) ! = 0 )
{
// There are detail objects in the level, so precache the material
PrecacheMaterial ( DETAIL_SPRITE_MATERIAL ) ;
}
int detailPropLightingLump ;
if ( g_pMaterialSystemHardwareConfig - > GetHDRType ( ) ! = HDR_TYPE_NONE )
{
detailPropLightingLump = GAMELUMP_DETAIL_PROP_LIGHTING_HDR ;
}
else
{
detailPropLightingLump = GAMELUMP_DETAIL_PROP_LIGHTING ;
}
size = engine - > GameLumpSize ( detailPropLightingLump ) ;
fileMemory . EnsureCapacity ( size ) ;
if ( engine - > LoadGameLump ( detailPropLightingLump , fileMemory . Base ( ) , size ) )
{
CUtlBuffer buf ( fileMemory . Base ( ) , size , CUtlBuffer : : READ_ONLY ) ;
UnserializeModelLighting ( buf ) ;
}
}
void CDetailObjectSystem : : LevelInitPostEntity ( )
{
const char * pDetailSpriteMaterial = DETAIL_SPRITE_MATERIAL ;
C_World * pWorld = GetClientWorldEntity ( ) ;
if ( pWorld & & pWorld - > GetDetailSpriteMaterial ( ) & & * ( pWorld - > GetDetailSpriteMaterial ( ) ) )
{
pDetailSpriteMaterial = pWorld - > GetDetailSpriteMaterial ( ) ;
}
m_DetailSpriteMaterial . Init ( pDetailSpriteMaterial , TEXTURE_GROUP_OTHER ) ;
if ( GetDetailController ( ) )
{
2011-04-28 01:29:22 -05:00
cl_detailfade . SetValue ( MIN ( m_flDefaultFadeStart , GetDetailController ( ) - > m_flFadeStartDist ) ) ;
cl_detaildist . SetValue ( MIN ( m_flDefaultFadeEnd , GetDetailController ( ) - > m_flFadeEndDist ) ) ;
2008-09-15 01:00:17 -05:00
}
else
{
// revert to default values if the map doesn't specify
cl_detailfade . SetValue ( m_flDefaultFadeStart ) ;
cl_detaildist . SetValue ( m_flDefaultFadeEnd ) ;
}
}
void CDetailObjectSystem : : LevelShutdownPreEntity ( )
{
m_DetailObjects . Purge ( ) ;
m_DetailObjectDict . Purge ( ) ;
m_DetailSpriteDict . Purge ( ) ;
m_DetailLighting . Purge ( ) ;
m_DetailSpriteMaterial . Shutdown ( ) ;
}
void CDetailObjectSystem : : LevelShutdownPostEntity ( )
{
m_DetailWireframeMaterial . Shutdown ( ) ;
}
//-----------------------------------------------------------------------------
// Before each view, blat out the stored detail sprite state
//-----------------------------------------------------------------------------
void CDetailObjectSystem : : BeginTranslucentDetailRendering ( )
{
m_nSortedLeaf = - 1 ;
m_nSpriteCount = m_nFirstSprite = 0 ;
}
//-----------------------------------------------------------------------------
// Gets a particular detail object
//-----------------------------------------------------------------------------
IClientRenderable * CDetailObjectSystem : : GetDetailModel ( int idx )
{
if ( IsPC ( ) )
{
// FIXME: This is necessary because we have intermixed models + sprites
// in a single list (m_DetailObjects)
if ( m_DetailObjects [ idx ] . GetType ( ) ! = DETAIL_PROP_TYPE_MODEL )
return NULL ;
return & m_DetailObjects [ idx ] ;
}
else
{
return NULL ;
}
}
//-----------------------------------------------------------------------------
// Unserialization
//-----------------------------------------------------------------------------
void CDetailObjectSystem : : UnserializeModelDict ( CUtlBuffer & buf )
{
int count = buf . GetInt ( ) ;
m_DetailObjectDict . EnsureCapacity ( count ) ;
while ( - - count > = 0 )
{
DetailObjectDictLump_t lump ;
buf . Get ( & lump , sizeof ( DetailObjectDictLump_t ) ) ;
DetailModelDict_t dict ;
dict . m_pModel = ( model_t * ) engine - > LoadModel ( lump . m_Name , true ) ;
// Don't allow vertex-lit models
if ( modelinfo - > IsModelVertexLit ( dict . m_pModel ) )
{
Warning ( " Detail prop model %s is using vertex-lit materials! \n It must use unlit materials! \n " , lump . m_Name ) ;
dict . m_pModel = ( model_t * ) engine - > LoadModel ( " models/error.mdl " ) ;
}
m_DetailObjectDict . AddToTail ( dict ) ;
}
}
void CDetailObjectSystem : : UnserializeDetailSprites ( CUtlBuffer & buf )
{
int count = buf . GetInt ( ) ;
m_DetailSpriteDict . EnsureCapacity ( count ) ;
while ( - - count > = 0 )
{
int i = m_DetailSpriteDict . AddToTail ( ) ;
buf . Get ( & m_DetailSpriteDict [ i ] , sizeof ( DetailSpriteDictLump_t ) ) ;
}
}
void CDetailObjectSystem : : UnserializeModelLighting ( CUtlBuffer & buf )
{
int count = buf . GetInt ( ) ;
m_DetailLighting . EnsureCapacity ( count ) ;
while ( - - count > = 0 )
{
int i = m_DetailLighting . AddToTail ( ) ;
buf . Get ( & m_DetailLighting [ i ] , sizeof ( DetailPropLightstylesLump_t ) ) ;
}
}
//-----------------------------------------------------------------------------
// Unserialize all models
//-----------------------------------------------------------------------------
void CDetailObjectSystem : : UnserializeModels ( CUtlBuffer & buf )
{
int firstDetailObject = 0 ;
int detailObjectCount = 0 ;
int detailObjectLeaf = - 1 ;
int count = buf . GetInt ( ) ;
m_DetailObjects . EnsureCapacity ( count ) ;
while ( - - count > = 0 )
{
DetailObjectLump_t lump ;
buf . Get ( & lump , sizeof ( DetailObjectLump_t ) ) ;
// We rely on the fact that details objects are sorted by leaf in the
// bsp file for this
if ( detailObjectLeaf ! = lump . m_Leaf )
{
if ( detailObjectLeaf ! = - 1 )
{
ClientLeafSystem ( ) - > SetDetailObjectsInLeaf ( detailObjectLeaf ,
firstDetailObject , detailObjectCount ) ;
}
detailObjectLeaf = lump . m_Leaf ;
firstDetailObject = m_DetailObjects . Count ( ) ;
detailObjectCount = 0 ;
}
if ( lump . m_Type = = DETAIL_PROP_TYPE_MODEL )
{
if ( IsPC ( ) )
{
int newObj = m_DetailObjects . AddToTail ( ) ;
m_DetailObjects [ newObj ] . Init ( newObj , lump . m_Origin , lump . m_Angles ,
m_DetailObjectDict [ lump . m_DetailModel ] . m_pModel , lump . m_Lighting ,
lump . m_LightStyles , lump . m_LightStyleCount , lump . m_Orientation ) ;
+ + detailObjectCount ;
}
}
else
{
int newObj = m_DetailObjects . AddToTail ( ) ;
m_DetailObjects [ newObj ] . InitSprite ( newObj , lump . m_Origin , lump . m_Angles ,
lump . m_DetailModel , lump . m_Lighting ,
lump . m_LightStyles , lump . m_LightStyleCount , lump . m_Orientation , lump . m_flScale ,
lump . m_Type , lump . m_ShapeAngle , lump . m_ShapeSize , lump . m_SwayAmount ) ;
+ + detailObjectCount ;
}
}
if ( detailObjectLeaf ! = - 1 )
{
ClientLeafSystem ( ) - > SetDetailObjectsInLeaf ( detailObjectLeaf ,
firstDetailObject , detailObjectCount ) ;
}
}
//-----------------------------------------------------------------------------
// Renders all opaque detail objects in a particular set of leaves
//-----------------------------------------------------------------------------
void CDetailObjectSystem : : RenderOpaqueDetailObjects ( int nLeafCount , LeafIndex_t * pLeafList )
{
// FIXME: Implement!
}
//-----------------------------------------------------------------------------
// Count the number of detail sprites in the leaf list
//-----------------------------------------------------------------------------
int CDetailObjectSystem : : CountSpritesInLeafList ( int nLeafCount , LeafIndex_t * pLeafList )
{
VPROF_BUDGET ( " CDetailObjectSystem::CountSpritesInLeafList " , VPROF_BUDGETGROUP_DETAILPROP_RENDERING ) ;
int nPropCount = 0 ;
int nFirstDetailObject , nDetailObjectCount ;
for ( int i = 0 ; i < nLeafCount ; + + i )
{
// FIXME: This actually counts *everything* in the leaf, which is ok for now
// given how we're using it
ClientLeafSystem ( ) - > GetDetailObjectsInLeaf ( pLeafList [ i ] , nFirstDetailObject , nDetailObjectCount ) ;
nPropCount + = nDetailObjectCount ;
}
return nPropCount ;
}
//-----------------------------------------------------------------------------
// Count the number of detail sprite quads in the leaf list
//-----------------------------------------------------------------------------
int CDetailObjectSystem : : CountSpriteQuadsInLeafList ( int nLeafCount , LeafIndex_t * pLeafList )
{
# ifdef USE_DETAIL_SHAPES
VPROF_BUDGET ( " CDetailObjectSystem::CountSpritesInLeafList " , VPROF_BUDGETGROUP_DETAILPROP_RENDERING ) ;
int nQuadCount = 0 ;
int nFirstDetailObject , nDetailObjectCount ;
for ( int i = 0 ; i < nLeafCount ; + + i )
{
// FIXME: This actually counts *everything* in the leaf, which is ok for now
// given how we're using it
ClientLeafSystem ( ) - > GetDetailObjectsInLeaf ( pLeafList [ i ] , nFirstDetailObject , nDetailObjectCount ) ;
for ( int j = 0 ; j < nDetailObjectCount ; + + j )
{
nQuadCount + = m_DetailObjects [ j + nFirstDetailObject ] . QuadsToDraw ( ) ;
}
}
return nQuadCount ;
# else
return CountSpritesInLeafList ( nLeafCount , pLeafList ) ;
# endif
}
//-----------------------------------------------------------------------------
// Sorts sprites in back-to-front order
//-----------------------------------------------------------------------------
int __cdecl CDetailObjectSystem : : SortFunc ( const void * arg1 , const void * arg2 )
{
// Therefore, things that are farther away in front of us (has a greater + distance)
// need to appear at the front of the list, hence the somewhat misleading code below
float flDelta = ( ( SortInfo_t * ) arg1 ) - > m_flDistance - ( ( SortInfo_t * ) arg2 ) - > m_flDistance ;
if ( flDelta > 0 )
return - 1 ;
if ( flDelta < 0 )
return 1 ;
return 0 ;
}
int CDetailObjectSystem : : SortSpritesBackToFront ( int nLeaf , const Vector & viewOrigin , const Vector & viewForward , SortInfo_t * pSortInfo )
{
VPROF_BUDGET ( " CDetailObjectSystem::SortSpritesBackToFront " , VPROF_BUDGETGROUP_DETAILPROP_RENDERING ) ;
int nFirstDetailObject , nDetailObjectCount ;
ClientLeafSystem ( ) - > GetDetailObjectsInLeaf ( nLeaf , nFirstDetailObject , nDetailObjectCount ) ;
float flFactor = 1.0f ;
C_BasePlayer * pLocalPlayer = C_BasePlayer : : GetLocalPlayer ( ) ;
if ( pLocalPlayer )
{
flFactor = pLocalPlayer - > GetFOVDistanceAdjustFactor ( ) ;
}
float flMaxSqDist = cl_detaildist . GetFloat ( ) * cl_detaildist . GetFloat ( ) ;
float flFadeSqDist = cl_detaildist . GetFloat ( ) - cl_detailfade . GetFloat ( ) ;
flMaxSqDist / = flFactor ;
flFadeSqDist / = flFactor ;
if ( flFadeSqDist > 0 )
{
flFadeSqDist * = flFadeSqDist ;
}
else
{
flFadeSqDist = 0 ;
}
float flFalloffFactor = 255.0f / ( flMaxSqDist - flFadeSqDist ) ;
Vector vecDelta ;
int nCount = 0 ;
for ( int j = 0 ; j < nDetailObjectCount ; + + j )
{
CDetailModel & model = m_DetailObjects [ nFirstDetailObject + j ] ;
Vector v ;
VectorSubtract ( model . GetRenderOrigin ( ) , viewOrigin , v ) ;
float flSqDist = v . LengthSqr ( ) ;
if ( flSqDist > = flMaxSqDist )
continue ;
if ( ( flFadeSqDist > 0 ) & & ( flSqDist > flFadeSqDist ) )
{
model . SetAlpha ( flFalloffFactor * ( flMaxSqDist - flSqDist ) ) ;
}
else
{
model . SetAlpha ( 255 ) ;
}
// Perform screen alignment if necessary.
model . ComputeAngles ( ) ;
if ( IsPC ( ) & & ( ( model . GetType ( ) = = DETAIL_PROP_TYPE_MODEL ) | | ( model . GetAlpha ( ) = = 0 ) ) )
continue ;
pSortInfo [ nCount ] . m_nIndex = nFirstDetailObject + j ;
// Compute distance from the camera to each object
VectorSubtract ( model . GetRenderOrigin ( ) , viewOrigin , vecDelta ) ;
pSortInfo [ nCount ] . m_flDistance = vecDelta . LengthSqr ( ) ; //DotProduct( viewForward, vecDelta );
+ + nCount ;
}
qsort ( pSortInfo , nCount , sizeof ( SortInfo_t ) , SortFunc ) ;
return nCount ;
}
//-----------------------------------------------------------------------------
// Renders all translucent detail objects in a particular set of leaves
//-----------------------------------------------------------------------------
void CDetailObjectSystem : : RenderTranslucentDetailObjects ( const Vector & viewOrigin , const Vector & viewForward , int nLeafCount , LeafIndex_t * pLeafList )
{
VPROF_BUDGET ( " CDetailObjectSystem::RenderTranslucentDetailObjects " , VPROF_BUDGETGROUP_DETAILPROP_RENDERING ) ;
if ( nLeafCount = = 0 )
return ;
// We better not have any partially drawn leaf of detail sprites!
Assert ( m_nSpriteCount = = m_nFirstSprite ) ;
// Here, we must draw all detail objects back-to-front
// FIXME: Cache off a sorted list so we don't have to re-sort every frame
// Count the total # of detail quads we possibly could render
int nQuadCount = CountSpriteQuadsInLeafList ( nLeafCount , pLeafList ) ;
if ( nQuadCount = = 0 )
return ;
materials - > MatrixMode ( MATERIAL_MODEL ) ;
materials - > PushMatrix ( ) ;
materials - > LoadIdentity ( ) ;
IMaterial * pMaterial = m_DetailSpriteMaterial ;
if ( ShouldDrawInWireFrameMode ( ) | | r_DrawDetailProps . GetInt ( ) = = 2 )
{
pMaterial = m_DetailWireframeMaterial ;
}
CMeshBuilder meshBuilder ;
IMesh * pMesh = materials - > GetDynamicMesh ( true , NULL , NULL , pMaterial ) ;
int nMaxVerts , nMaxIndices ;
materials - > GetMaxToRender ( pMesh , false , & nMaxVerts , & nMaxIndices ) ;
int nMaxQuadsToDraw = nMaxIndices / 6 ;
if ( nMaxQuadsToDraw > nMaxVerts / 4 )
{
nMaxQuadsToDraw = nMaxVerts / 4 ;
}
int nQuadsToDraw = nQuadCount ;
if ( nQuadsToDraw > nMaxQuadsToDraw )
{
nQuadsToDraw = nMaxQuadsToDraw ;
}
meshBuilder . Begin ( pMesh , MATERIAL_QUADS , nQuadsToDraw ) ;
int nQuadsDrawn = 0 ;
for ( int i = 0 ; i < nLeafCount ; + + i )
{
int nLeaf = pLeafList [ i ] ;
int nFirstDetailObject , nDetailObjectCount ;
ClientLeafSystem ( ) - > GetDetailObjectsInLeaf ( nLeaf , nFirstDetailObject , nDetailObjectCount ) ;
// Sort detail sprites in each leaf independently; then render them
SortInfo_t * pSortInfo = ( SortInfo_t * ) stackalloc ( nDetailObjectCount * sizeof ( SortInfo_t ) ) ;
int nCount = SortSpritesBackToFront ( nLeaf , viewOrigin , viewForward , pSortInfo ) ;
for ( int j = 0 ; j < nCount ; + + j )
{
CDetailModel & model = m_DetailObjects [ pSortInfo [ j ] . m_nIndex ] ;
int nQuadsInModel = model . QuadsToDraw ( ) ;
// Prevent the batches from getting too large
if ( nQuadsDrawn + nQuadsInModel > nQuadsToDraw )
{
meshBuilder . End ( ) ;
pMesh - > Draw ( ) ;
nQuadCount - = nQuadsDrawn ;
nQuadsToDraw = nQuadCount ;
if ( nQuadsToDraw > nMaxQuadsToDraw )
{
nQuadsToDraw = nMaxQuadsToDraw ;
}
meshBuilder . Begin ( pMesh , MATERIAL_QUADS , nQuadsToDraw ) ;
nQuadsDrawn = 0 ;
}
model . DrawSprite ( meshBuilder ) ;
nQuadsDrawn + = nQuadsInModel ;
}
}
meshBuilder . End ( ) ;
pMesh - > Draw ( ) ;
materials - > PopMatrix ( ) ;
}
//-----------------------------------------------------------------------------
// Renders a subset of the detail objects in a particular leaf (for interleaving with other translucent entities)
//-----------------------------------------------------------------------------
void CDetailObjectSystem : : RenderTranslucentDetailObjectsInLeaf ( const Vector & viewOrigin , const Vector & viewForward , int nLeaf , const Vector * pVecClosestPoint )
{
VPROF_BUDGET ( " CDetailObjectSystem::RenderTranslucentDetailObjectsInLeaf " , VPROF_BUDGETGROUP_DETAILPROP_RENDERING ) ;
// We may have already sorted this leaf. If not, sort the leaf.
if ( m_nSortedLeaf ! = nLeaf )
{
m_nSortedLeaf = nLeaf ;
m_nSpriteCount = 0 ;
m_nFirstSprite = 0 ;
// Count the total # of detail sprites we possibly could render
LeafIndex_t nLeafIndex = nLeaf ;
int nSpriteCount = CountSpritesInLeafList ( 1 , & nLeafIndex ) ;
Assert ( nSpriteCount < = MAX_SPRITES_PER_LEAF ) ;
if ( nSpriteCount = = 0 )
return ;
// Sort detail sprites in each leaf independently; then render them
m_nSpriteCount = SortSpritesBackToFront ( nLeaf , viewOrigin , viewForward , m_pSortInfo ) ;
Assert ( m_nSpriteCount < = nSpriteCount ) ;
}
// No more to draw? Bye!
if ( m_nSpriteCount = = m_nFirstSprite )
return ;
float flMinDistance = 0.0f ;
if ( pVecClosestPoint )
{
Vector vecDelta ;
VectorSubtract ( * pVecClosestPoint , viewOrigin , vecDelta ) ;
flMinDistance = vecDelta . LengthSqr ( ) ;
}
if ( m_pSortInfo [ m_nFirstSprite ] . m_flDistance < flMinDistance )
return ;
materials - > MatrixMode ( MATERIAL_MODEL ) ;
materials - > PushMatrix ( ) ;
materials - > LoadIdentity ( ) ;
IMaterial * pMaterial = m_DetailSpriteMaterial ;
if ( ShouldDrawInWireFrameMode ( ) | | r_DrawDetailProps . GetInt ( ) = = 2 )
{
pMaterial = m_DetailWireframeMaterial ;
}
CMeshBuilder meshBuilder ;
IMesh * pMesh = materials - > GetDynamicMesh ( true , NULL , NULL , pMaterial ) ;
int nMaxVerts , nMaxIndices ;
materials - > GetMaxToRender ( pMesh , false , & nMaxVerts , & nMaxIndices ) ;
// needs to be * 4 since there are a max of 4 quads per detail object
int nQuadCount = ( m_nSpriteCount - m_nFirstSprite ) * 4 ;
int nMaxQuadsToDraw = nMaxIndices / 6 ;
if ( nMaxQuadsToDraw > nMaxVerts / 4 )
{
nMaxQuadsToDraw = nMaxVerts / 4 ;
}
int nQuadsToDraw = nQuadCount ;
if ( nQuadsToDraw > nMaxQuadsToDraw )
{
nQuadsToDraw = nMaxQuadsToDraw ;
}
meshBuilder . Begin ( pMesh , MATERIAL_QUADS , nQuadsToDraw ) ;
int nQuadsDrawn = 0 ;
while ( m_nFirstSprite < m_nSpriteCount & & m_pSortInfo [ m_nFirstSprite ] . m_flDistance > = flMinDistance )
{
CDetailModel & model = m_DetailObjects [ m_pSortInfo [ m_nFirstSprite ] . m_nIndex ] ;
int nQuadsInModel = model . QuadsToDraw ( ) ;
if ( nQuadsDrawn + nQuadsInModel > nQuadsToDraw )
{
meshBuilder . End ( ) ;
pMesh - > Draw ( ) ;
nQuadCount = ( m_nSpriteCount - m_nFirstSprite ) * 4 ;
nQuadsToDraw = nQuadCount ;
if ( nQuadsToDraw > nMaxQuadsToDraw )
{
nQuadsToDraw = nMaxQuadsToDraw ;
}
meshBuilder . Begin ( pMesh , MATERIAL_QUADS , nQuadsToDraw ) ;
nQuadsDrawn = 0 ;
}
model . DrawSprite ( meshBuilder ) ;
+ + m_nFirstSprite ;
nQuadsDrawn + = nQuadsInModel ;
}
meshBuilder . End ( ) ;
pMesh - > Draw ( ) ;
materials - > PopMatrix ( ) ;
}
//-----------------------------------------------------------------------------
// Gets called each view
//-----------------------------------------------------------------------------
bool CDetailObjectSystem : : EnumerateLeaf ( int leaf , int context )
{
VPROF_BUDGET ( " CDetailObjectSystem::EnumerateLeaf " , VPROF_BUDGETGROUP_DETAILPROP_RENDERING ) ;
Vector v ;
int firstDetailObject , detailObjectCount ;
EnumContext_t * pCtx = ( EnumContext_t * ) context ;
ClientLeafSystem ( ) - > DrawDetailObjectsInLeaf ( leaf , pCtx - > m_BuildWorldListNumber ,
firstDetailObject , detailObjectCount ) ;
if ( IsPC ( ) )
{
// Compute the translucency. Need to do it now cause we need to
// know that when we're rendering (opaque stuff is rendered first)
for ( int i = 0 ; i < detailObjectCount ; + + i )
{
// Calculate distance (badly)
CDetailModel & model = m_DetailObjects [ firstDetailObject + i ] ;
VectorSubtract ( model . GetRenderOrigin ( ) , CurrentViewOrigin ( ) , v ) ;
float sqDist = v . LengthSqr ( ) ;
if ( sqDist < pCtx - > m_MaxSqDist )
{
if ( ( pCtx - > m_FadeSqDist > 0 ) & & ( sqDist > pCtx - > m_FadeSqDist ) )
{
model . SetAlpha ( pCtx - > m_FalloffFactor * ( pCtx - > m_MaxSqDist - sqDist ) ) ;
}
else
{
model . SetAlpha ( 255 ) ;
}
// Perform screen alignment if necessary.
model . ComputeAngles ( ) ;
}
else
{
model . SetAlpha ( 0 ) ;
}
}
}
return true ;
}
//-----------------------------------------------------------------------------
// Gets called each view
//-----------------------------------------------------------------------------
void CDetailObjectSystem : : BuildDetailObjectRenderLists ( )
{
VPROF_BUDGET ( " CDetailObjectSystem::BuildDetailObjectRenderLists " , VPROF_BUDGETGROUP_DETAILPROP_RENDERING ) ;
if ( ! g_pClientMode - > ShouldDrawDetailObjects ( ) | | ( r_DrawDetailProps . GetInt ( ) = = 0 ) )
return ;
// Don't bother doing any of this if the level doesn't have detail props.
if ( m_DetailObjects . Count ( ) = = 0 )
return ;
EnumContext_t ctx ;
ctx . m_BuildWorldListNumber = view - > BuildWorldListsNumber ( ) ;
if ( IsPC ( ) )
{
// We need to recompute translucency information for all detail props
for ( int i = m_DetailObjectDict . Size ( ) ; - - i > = 0 ; )
{
if ( modelinfo - > ModelHasMaterialProxy ( m_DetailObjectDict [ i ] . m_pModel ) )
{
modelinfo - > RecomputeTranslucency ( m_DetailObjectDict [ i ] . m_pModel ) ;
}
}
float factor = 1.0f ;
C_BasePlayer * local = C_BasePlayer : : GetLocalPlayer ( ) ;
if ( local )
{
factor = local - > GetFOVDistanceAdjustFactor ( ) ;
}
// Compute factors to optimize rendering of the detail models
ctx . m_MaxSqDist = cl_detaildist . GetFloat ( ) * cl_detaildist . GetFloat ( ) ;
ctx . m_FadeSqDist = cl_detaildist . GetFloat ( ) - cl_detailfade . GetFloat ( ) ;
ctx . m_MaxSqDist / = factor ;
ctx . m_FadeSqDist / = factor ;
if ( ctx . m_FadeSqDist > 0 )
{
ctx . m_FadeSqDist * = ctx . m_FadeSqDist ;
}
else
{
ctx . m_FadeSqDist = 0 ;
}
ctx . m_FalloffFactor = 255.0f / ( ctx . m_MaxSqDist - ctx . m_FadeSqDist ) ;
}
ISpatialQuery * pQuery = engine - > GetBSPTreeQuery ( ) ;
pQuery - > EnumerateLeavesInSphere ( CurrentViewOrigin ( ) ,
cl_detaildist . GetFloat ( ) , this , ( int ) & ctx ) ;
}