summaryrefslogtreecommitdiff
path: root/studiorender/studiorender.h
diff options
context:
space:
mode:
Diffstat (limited to 'studiorender/studiorender.h')
-rw-r--r--studiorender/studiorender.h931
1 files changed, 931 insertions, 0 deletions
diff --git a/studiorender/studiorender.h b/studiorender/studiorender.h
new file mode 100644
index 0000000..50a875a
--- /dev/null
+++ b/studiorender/studiorender.h
@@ -0,0 +1,931 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#ifndef CSTUDIORENDER_H
+#define CSTUDIORENDER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "istudiorender.h"
+#include "studio.h"
+#include "materialsystem/imaterialsystem.h" // for LightDesc_t
+// wouldn't have to include these if it weren't for inlines.
+#include "materialsystem/imaterial.h"
+#include "mathlib/mathlib.h"
+#include "utllinkedlist.h"
+#include "utlvector.h"
+#include "tier1/utllinkedlist.h"
+#include "flexrenderdata.h"
+#include "mathlib/compressed_vector.h"
+#include "r_studiolight.h"
+#if defined( _WIN32 ) && !defined( _X360 )
+#include <xmmintrin.h>
+#endif
+#include "tier0/dbg.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class ITexture;
+class CPixelWriter;
+class CMeshBuilder;
+class IMaterialVar;
+struct mstudioeyeball_t;
+struct eyeballstate_t;
+struct lightpos_t;
+struct dworldlight_t;
+struct DecalClipState_t;
+class CStudioRender;
+struct StudioRenderContext_t;
+struct FlexWeights_t;
+
+namespace OptimizedModel
+{
+ struct FileHeader_t;
+ struct MeshHeader_t;
+ struct StripGroupHeader_t;
+ struct Vertex_t;
+ struct ModelLODHeader_t;
+}
+
+
+//-----------------------------------------------------------------------------
+// FIXME: Remove
+//-----------------------------------------------------------------------------
+class IStudioDataCache;
+extern IStudioDataCache *g_pStudioDataCache;
+
+
+//-----------------------------------------------------------------------------
+// Singleton
+//-----------------------------------------------------------------------------
+extern CStudioRender g_StudioRender;
+
+
+//-----------------------------------------------------------------------------
+// Defines + structs
+//-----------------------------------------------------------------------------
+#define MAXLOCALLIGHTS 4
+#define MAXLIGHTCOMPUTE 16
+
+enum StudioModelLighting_t
+{
+ LIGHTING_HARDWARE = 0,
+ LIGHTING_SOFTWARE,
+ LIGHTING_MOUTH
+};
+
+struct lightpos_t
+{
+ Vector delta; // unit vector from vertex to light
+ float falloff; // light distance falloff
+ float dot; // light direction * delta;
+
+ lightpos_t() {}
+
+private:
+ // Copy constructors are not allowed
+ lightpos_t( const lightpos_t& src );
+};
+
+struct eyeballstate_t
+{
+ const mstudioeyeball_t *peyeball;
+
+ matrix3x4_t mat;
+
+ Vector org; // world center of eyeball
+ Vector forward;
+ Vector right;
+ Vector up;
+
+ Vector cornea; // world center of cornea
+
+ eyeballstate_t() {}
+
+private:
+ // Copy constructors are not allowed
+ eyeballstate_t( const eyeballstate_t& src );
+};
+
+
+//-----------------------------------------------------------------------------
+// Store decal vertex data here
+//-----------------------------------------------------------------------------
+#pragma pack(1)
+struct DecalVertex_t
+{
+ mstudiomesh_t *GetMesh( studiohdr_t *pHdr )
+ {
+ if ((m_Body == 0xFFFF) || (m_Model == 0xFFFF) || (m_Mesh == 0xFFFF))
+ return NULL;
+
+ mstudiobodyparts_t *pBody = pHdr->pBodypart( m_Body );
+ mstudiomodel_t *pModel = pBody->pModel( m_Model );
+ return pModel->pMesh( m_Mesh );
+ }
+
+ IMorph *GetMorph( studiohdr_t *pHdr, studiomeshdata_t *pStudioMeshes )
+ {
+ if ( (m_Body == 0xFFFF) || (m_Model == 0xFFFF) || (m_Mesh == 0xFFFF) || (m_Group == 0xFFFF) )
+ return NULL;
+
+ mstudiobodyparts_t *pBody = pHdr->pBodypart( m_Body );
+ mstudiomodel_t *pModel = pBody->pModel( m_Model );
+ mstudiomesh_t *pMesh = pModel->pMesh( m_Mesh );
+ studiomeshdata_t* pMeshData = &pStudioMeshes[pMesh->meshid];
+ studiomeshgroup_t* pGroup = &pMeshData->m_pMeshGroup[m_Group];
+ return pGroup->m_pMorph;
+ }
+
+ // NOTE: m_Group + m_GroupIndex is necessary only for decals on
+ // hardware morphs. If COMPACT_DECAL_VERT is for console, we
+ // could remove group index + group
+#ifdef COMPACT_DECAL_VERT
+ Vector m_Position; // 12
+ Vector2d32 m_TexCoord; // 16
+ Vector48 m_Normal; // 22 (packed to m_Body)
+
+ byte m_Body; // 24
+ byte m_Model;
+ unsigned short m_MeshVertexIndex; // index into the mesh's vertex list
+ unsigned short m_Mesh;
+ unsigned short m_GroupIndex; // index into the mesh's vertex list
+ unsigned short m_Group;
+#else
+ Vector m_Position;
+ Vector m_Normal;
+ Vector2D m_TexCoord;
+
+ unsigned short m_MeshVertexIndex; // index into the mesh's vertex list
+ unsigned short m_Body;
+ unsigned short m_Model;
+ unsigned short m_Mesh;
+ unsigned short m_GroupIndex; // index into the group's index list
+ unsigned short m_Group;
+#endif
+
+ DecalVertex_t() {}
+ DecalVertex_t( const DecalVertex_t& src )
+ {
+ m_Position = src.m_Position;
+ m_Normal = src.m_Normal;
+ m_TexCoord = src.m_TexCoord;
+ m_MeshVertexIndex = src.m_MeshVertexIndex;
+ m_Body = src.m_Body;
+ m_Model = src.m_Model;
+ m_Mesh = src.m_Mesh;
+ m_GroupIndex = src.m_GroupIndex;
+ m_Group = src.m_Group;
+ }
+};
+#pragma pack()
+
+
+//-----------------------------------------------------------------------------
+// Temporary meshes
+//-----------------------------------------------------------------------------
+struct MeshVertexInfo_t
+{
+ mstudiomesh_t *m_pMesh;
+ int m_nIndex;
+};
+
+
+//-----------------------------------------------------------------------------
+// Vertex prefetch count for software skinning
+//-----------------------------------------------------------------------------
+enum
+{
+ PREFETCH_VERT_COUNT = 4
+};
+
+
+//-----------------------------------------------------------------------------
+// Class that actually renders stuff
+//-----------------------------------------------------------------------------
+class CStudioRender
+{
+public:
+ CStudioRender();
+ ~CStudioRender();
+
+ // Init, shutdown
+ InitReturnVal_t Init();
+ void Shutdown( void );
+
+ void EnableScissor( FlashlightState_t *state );
+ void DisableScissor();
+
+ void DrawModel( const DrawModelInfo_t& info, const StudioRenderContext_t& rc, matrix3x4_t *pBoneToWorld, const FlexWeights_t& flex, int flags = STUDIORENDER_DRAW_ENTIRE_MODEL );
+ void DrawModelArray( const DrawModelInfo_t &drawInfo, const StudioRenderContext_t &rc, int arrayCount, model_array_instance_t *pInstanceData, int instanceStride, int flags = STUDIORENDER_DRAW_ENTIRE_MODEL );
+
+ // Static-prop related draw methods
+ void DrawModelStaticProp( const DrawModelInfo_t& info, const StudioRenderContext_t &rc, const matrix3x4_t &modelToWorld, int flags = STUDIORENDER_DRAW_ENTIRE_MODEL );
+ void DrawStaticPropShadows( const DrawModelInfo_t &drawInfo, const StudioRenderContext_t &rc, const matrix3x4_t &modelToWorld, int flags );
+ void DrawStaticPropDecals( const DrawModelInfo_t &drawInfo, const StudioRenderContext_t &rc, const matrix3x4_t &modelToWorld );
+
+ void ModelStats( const DrawModelInfo_t& info, const StudioRenderContext_t &rc, matrix3x4_t *pBoneToWorld, const FlexWeights_t &flex, int flags );
+
+ // Create, destroy list of decals for a particular model
+ StudioDecalHandle_t CreateDecalList( studiohwdata_t *pHardwareData );
+ void DestroyDecalList( StudioDecalHandle_t handle );
+
+ // Add decals to a decal list by doing a planar projection along the ray
+ void AddDecal( StudioDecalHandle_t handle, const StudioRenderContext_t& rc, matrix3x4_t *pBoneToWorld, studiohdr_t *pStudioHdr,
+ const Ray_t & ray, const Vector& decalUp, IMaterial* pDecalMaterial,
+ float radius, int body, bool noPokethru, int maxLODToDecal = ADDDECAL_TO_ALL_LODS );
+
+ // Shadow state (affects the models as they are rendered)
+ void AddShadow( IMaterial* pMaterial, void* pProxyData, FlashlightState_t *pFlashlightState, VMatrix *pWorldToTexture, ITexture *pFlashlightDepthTexture );
+ void ClearAllShadows();
+
+ // Release/restore material system objects
+ void PrecacheGlint();
+ void UncacheGlint();
+
+ // Get the config
+ void R_MouthComputeLightingValues( float& fIllum, Vector& forward );
+ void R_MouthLighting( float fIllum, const Vector& normal, const Vector& forward, Vector& light );
+
+ // Performs the lighting computation
+ inline void R_ComputeLightAtPoint3( const Vector &pos, const Vector &norm, Vector &color );
+
+#if defined( _WIN32 ) && !defined( _X360 )
+ // sse-ized lighting pipeline. lights 4 vertices at once
+ inline void R_ComputeLightAtPoints3( const FourVectors &pos, const FourVectors &norm, FourVectors &color );
+ void R_MouthLighting( __m128 fIllum, const FourVectors& normal, const FourVectors& forward, FourVectors& light );
+#endif
+
+private:
+ enum
+ {
+ DECAL_DYNAMIC = 0x1,
+ DECAL_SECONDPASS = 0x2,
+ };
+
+ typedef unsigned short DecalId_t;
+
+ struct Decal_t
+ {
+ int m_IndexCount;
+ int m_VertexCount;
+ float m_FadeStartTime;
+ float m_FadeDuration;
+ int m_Flags;
+ };
+
+ struct DecalHistory_t
+ {
+ unsigned short m_Material;
+ unsigned short m_Decal;
+ DecalId_t m_nId;
+ unsigned short m_nPad;
+ };
+
+ typedef CUtlLinkedList<DecalVertex_t, unsigned short> DecalVertexList_t;
+
+ typedef CUtlVector<unsigned short> DecalIndexList_t;
+ typedef CUtlLinkedList<Decal_t, unsigned short> DecalList_t;
+ typedef CUtlLinkedList<DecalHistory_t, unsigned short> DecalHistoryList_t;
+
+ struct DecalMaterial_t
+ {
+ IMaterial* m_pMaterial;
+ DecalIndexList_t m_Indices;
+ DecalVertexList_t m_Vertices;
+ DecalList_t m_Decals;
+ };
+
+ struct DecalLod_t
+ {
+ unsigned short m_FirstMaterial;
+ DecalHistoryList_t m_DecalHistory;
+ };
+
+ struct DecalModelList_t
+ {
+ studiohwdata_t* m_pHardwareData;
+ DecalLod_t* m_pLod;
+ int m_nLods; // need to retain because hardware data could be flushed
+ };
+
+ // A temporary structure used to figure out new decal verts
+ struct DecalBuildVertexInfo_t
+ {
+ enum
+ {
+ FRONT_FACING = 0x1,
+ VALID_AREA = 0x2, // If you change this, change ProjectDecalOntoMesh
+ };
+
+ Vector2D m_UV;
+ unsigned short m_VertexIndex; // index into the DecalVertex_t list
+ unsigned char m_UniqueID;
+ unsigned char m_Flags;
+
+ private:
+ // No copy constructors
+ DecalBuildVertexInfo_t( const DecalBuildVertexInfo_t &src );
+ };
+
+ struct DecalBuildInfo_t
+ {
+ IMaterial **m_ppMaterials;
+ studiohdr_t *m_pStudioHdr;
+ mstudiomesh_t *m_pMesh;
+ studiomeshdata_t *m_pMeshData;
+ DecalMaterial_t *m_pDecalMaterial;
+ MeshVertexInfo_t *m_pMeshVertices;
+ const mstudio_meshvertexdata_t *m_pMeshVertexData;
+ const thinModelVertices_t *m_pMeshThinVertexData;
+ int m_nGlobalMeshIndex;
+ DecalBuildVertexInfo_t *m_pVertexBuffer;
+ float m_Radius;
+ DecalBuildVertexInfo_t *m_pVertexInfo;
+ int m_Body;
+ int m_Model;
+ int m_Mesh;
+ int m_Group;
+ DecalVertexList_t::IndexType_t m_FirstVertex;
+ unsigned short m_VertexCount;
+ bool m_UseClipVert;
+ bool m_NoPokeThru;
+ };
+
+ struct ShadowState_t
+ {
+ IMaterial* m_pMaterial;
+ void* m_pProxyData;
+ FlashlightState_t * m_pFlashlightState;
+ VMatrix * m_pWorldToTexture;
+ ITexture * m_pFlashlightDepthTexture;
+ };
+
+ struct BodyPartInfo_t
+ {
+ int m_nSubModelIndex;
+ mstudiomodel_t *m_pSubModel;
+ };
+
+ struct GlintRenderData_t
+ {
+ Vector2D m_vecPosition;
+ Vector m_vecIntensity;
+ };
+
+ // Global LRU for model decals
+ struct DecalLRU_t
+ {
+ StudioDecalHandle_t m_hDecalHandle;
+ DecalId_t m_nDecalId;
+ };
+
+ typedef CUtlFixedLinkedList< DecalLRU_t >::IndexType_t DecalLRUListIndex_t;
+
+private:
+ void SetLightingRenderState();
+
+ int R_StudioRenderModel( IMatRenderContext *pRenderContext, int skin, int body, int hitboxset, void /*IClientEntity*/ *pEntity,
+ IMaterial **ppMaterials, int *pMaterialFlags, int flags, int boneMask, int lod, ColorMeshInfo_t *pColorMeshes = NULL );
+ IMaterial* R_StudioSetupSkinAndLighting( IMatRenderContext *pRenderContext, int index, IMaterial **ppMaterials, int materialFlags,
+ void /*IClientEntity*/ *pClientEntity, ColorMeshInfo_t *pColorMeshes, StudioModelLighting_t &lighting );
+ int R_StudioDrawEyeball( IMatRenderContext *pRenderContext, mstudiomesh_t* pmesh, studiomeshdata_t* pMeshData,
+ StudioModelLighting_t lighting, IMaterial *pMaterial, int lod );
+ int R_StudioDrawPoints( IMatRenderContext *pRenderContext, int skin, void /*IClientEntity*/ *pClientEntity,
+ IMaterial **ppMaterials, int *pMaterialFlags, int boneMask, int lod, ColorMeshInfo_t *pColorMeshes );
+ int R_StudioDrawMesh( IMatRenderContext *pRenderContext, mstudiomesh_t* pmesh, studiomeshdata_t* pMeshData,
+ StudioModelLighting_t lighting, IMaterial *pMaterial, ColorMeshInfo_t *pColorMeshes, int lod );
+ int R_StudioRenderFinal( IMatRenderContext *pRenderContext,
+ int skin, int nBodyPartCount, BodyPartInfo_t *pBodyPartInfo, void /*IClientEntity*/ *pClientEntity,
+ IMaterial **ppMaterials, int *pMaterialFlags, int boneMask, int lod, ColorMeshInfo_t *pColorMeshes = NULL );
+ int R_StudioDrawStaticMesh( IMatRenderContext *pRenderContext, mstudiomesh_t* pmesh,
+ studiomeshgroup_t* pGroup, StudioModelLighting_t lighting, float r_blend, IMaterial* pMaterial,
+ int lod, ColorMeshInfo_t *pColorMeshes );
+ int R_StudioDrawDynamicMesh( IMatRenderContext *pRenderContext, mstudiomesh_t* pmesh,
+ studiomeshgroup_t* pGroup, StudioModelLighting_t lighting,
+ float r_blend, IMaterial* pMaterial, int lod );
+ int R_StudioDrawGroupHWSkin( IMatRenderContext *pRenderContext, studiomeshgroup_t* pGroup, IMesh* pMesh, ColorMeshInfo_t *pColorMeshInfo = NULL );
+ int R_StudioDrawGroupSWSkin( studiomeshgroup_t* pGroup, IMesh* pMesh );
+ void R_StudioDrawHulls( int hitboxset, bool translucent );
+ void R_StudioDrawBones (void);
+ void R_StudioVertBuffer( void );
+ void DrawNormal( const Vector& pos, float scale, const Vector& normal, const Vector& color );
+ void BoneMatToMaterialMat( matrix3x4_t& boneMat, float materialMat[4][4] );
+
+ // Various inner-loop methods
+ void R_StudioSoftwareProcessMesh( mstudiomesh_t* pmesh, CMeshBuilder& meshBuilder,
+ int numVertices, unsigned short* pGroupToMesh, StudioModelLighting_t lighting, bool doFlex, float r_blend,
+ bool bNeedsTangentSpace, bool bDX8Vertex, IMaterial *pMaterial );
+
+ void R_StudioSoftwareProcessMesh_Normals( mstudiomesh_t* pmesh, CMeshBuilder& meshBuilder,
+ int numVertices, unsigned short* pGroupToMesh, StudioModelLighting_t lighting, bool doFlex, float r_blend,
+ bool bShowNormals, bool bShowTangentFrame );
+
+ template< class T >
+ void ComputeFlexedVertex_StreamOffset( mstudioflex_t *pflex, T *pvanim, int vertCount, float w1, float w2, float w3, float w4 );
+
+ void R_StudioProcessFlexedMesh_StreamOffset( mstudiomesh_t* pmesh, int lod );
+
+ template <VertexCompressionType_t T> void FillFlexMeshGroupVB( CMeshBuilder & meshBuilder, studiomeshgroup_t *pGroup );
+ void R_StudioFlexMeshGroup( studiomeshgroup_t *pGroup );
+
+ template<VertexCompressionType_t T> void R_StudioRestoreMesh( mstudiomesh_t* pmesh, studiomeshgroup_t* pMeshData );
+ void R_StudioProcessFlexedMesh( mstudiomesh_t* pmesh, CMeshBuilder& meshBuilder,
+ int numVertices, unsigned short* pGroupToMesh );
+
+ // Eye rendering using vertex shaders
+ void SetEyeMaterialVars( IMaterial* pMaterial, mstudioeyeball_t* peyeball,
+ const Vector& eyeOrigin, const matrix3x4_t& irisTransform, const matrix3x4_t& glintTransform );
+
+ void ComputeEyelidStateFACS( mstudiomodel_t *pSubModel );
+
+ void R_StudioEyelidFACS( const mstudioeyeball_t *peyeball, const eyeballstate_t *pstate );
+
+ void R_StudioEyeballPosition( const mstudioeyeball_t *peyeball, eyeballstate_t *pstate );
+
+ // Computes the texture projection matrix for the glint texture
+ void ComputeGlintTextureProjection( eyeballstate_t const* pState,
+ const Vector& vright, const Vector& vup, matrix3x4_t& mat );
+
+ void R_StudioEyeballGlint( const eyeballstate_t *pstate, IMaterialVar *pGlintTextureVar,
+ const Vector& vright, const Vector& vup, const Vector& r_origin );
+ ITexture* RenderGlintTexture( const eyeballstate_t *pstate,
+ const Vector& vright, const Vector& vup, const Vector& r_origin );
+
+ int BuildGlintRenderData( GlintRenderData_t *pData, int nMaxGlints,
+ const eyeballstate_t *pstate, const Vector& vright, const Vector& vup, const Vector& r_origin );
+ void R_MouthSetupVertexShader( IMaterial* pMaterial );
+
+ // Computes a vertex format to use
+ VertexFormat_t ComputeSWSkinVertexFormat( IMaterial *pMaterial ) const;
+
+ inline bool R_TeethAreVisible( void )
+ {
+ return true;
+ /*
+ // FIXME: commented out until Gary can change them to just draw black
+ mstudiomouth_t *pMouth = m_pStudioHdr->pMouth( 0 );
+ float fIllum = m_FlexWeights[pMouth->flexdesc];
+ return fIllum > 0.0f;
+ */
+ }
+
+ inline StudioModelLighting_t R_StudioComputeLighting( IMaterial *pMaterial, int materialFlags, ColorMeshInfo_t *pColorMeshes );
+ inline void R_StudioTransform( Vector& in1, mstudioboneweight_t *pboneweight, Vector& out1 );
+ inline void R_StudioRotate( Vector& in1, mstudioboneweight_t *pboneweight, Vector& out1 );
+ inline void R_StudioRotate( Vector4D& in1, mstudioboneweight_t *pboneweight, Vector4D& out1 );
+ inline void R_StudioEyeballNormal( mstudioeyeball_t const* peyeball, Vector& org,
+ Vector& pos, Vector& normal );
+ void MaterialPlanerProjection( const matrix3x4_t& mat, int count, const Vector *psrcverts, Vector2D *pdesttexcoords );
+ void AddGlint( CPixelWriter &pixelWriter, float x, float y, const Vector& color );
+
+ // Methods associated with lighting
+ int R_LightGlintPosition( int index, const Vector& org, Vector& delta, Vector& intensity );
+ void R_LightEffectsWorld( const lightpos_t *light, const Vector& normal, const Vector &src, Vector &dest );
+
+ void R_GatherStats( studiomeshgroup_t *pGroup, CMeshBuilder &MeshBuilder, IMesh *pMesh, IMaterial *pMaterial );
+
+public:
+ // NJS: Messy, but needed for an externally optimized routine to set up the lighting.
+ void R_InitLightEffectsWorld3();
+ void (FASTCALL *R_LightEffectsWorld3)( const LightDesc_t *pLightDesc, const lightpos_t *light, const Vector& normal, Vector &dest );
+
+private:
+ inline float R_WorldLightAngle( const LightDesc_t *wl, const Vector& lnormal, const Vector& snormal, const Vector& delta );
+
+ void InitDebugMaterials( void );
+ void ShutdownDebugMaterials( void );
+ int SortMeshes( int* pIndices, IMaterial **ppMaterials, short* pskinref, const Vector& vforward, const Vector& r_origin );
+
+ // Computes pose to decal space transforms for decal creation
+ // returns false if it can't for some reason.
+ bool ComputePoseToDecal( Ray_t const& ray, const Vector& up );
+
+ bool AddDecalToModel( DecalBuildInfo_t& buildInfo );
+
+ // Helper methods for decal projection, projects pose space vertex data
+ bool TransformToDecalSpace( DecalBuildInfo_t& build, const Vector& pos, mstudioboneweight_t *pboneweight, Vector2D& uv );
+ bool ProjectDecalOntoMesh( DecalBuildInfo_t& build, DecalBuildVertexInfo_t* pVertexInfo, mstudiomesh_t *pMesh );
+ bool IsFrontFacing( const Vector * norm, const mstudioboneweight_t *pboneweight );
+ int ComputeClipFlags( DecalBuildVertexInfo_t* pVertexInfo, int i );
+ void ConvertMeshVertexToDecalVertex( DecalBuildInfo_t& build, int meshIndex, DecalVertex_t& decalVertex, int nGroupIndex = 0xFFFF );
+ unsigned short AddVertexToDecal( DecalBuildInfo_t& build, int meshIndex, int nGroupIndex = 0xFFFF );
+ unsigned short AddVertexToDecal( DecalBuildInfo_t& build, DecalVertex_t& vert );
+ void AddClippedDecalToTriangle( DecalBuildInfo_t& build, DecalClipState_t& clipState );
+ bool ClipDecal( DecalBuildInfo_t& build, int i1, int i2, int i3, int *pClipFlags );
+ void AddTriangleToDecal( DecalBuildInfo_t& build, int i1, int i2, int i3, int gi1, int gi2, int gi3 );
+ void AddDecalToMesh( DecalBuildInfo_t& build );
+ int GetDecalMaterial( DecalLod_t& decalLod, IMaterial* pDecalMaterial );
+ int AddDecalToMaterialList( DecalMaterial_t* pMaterial );
+
+ // Total number of meshes we have to deal with
+ int ComputeTotalMeshCount( int iRootLOD, int iMaxLOD, int body ) const;
+
+ // Project decals onto all meshes
+ void ProjectDecalsOntoMeshes( DecalBuildInfo_t& build, int nMeshCount );
+
+ // Set up the locations for vertices to use
+ int ComputeVertexAllocation( int iMaxLOD, int body, studiohwdata_t *pHardwareData, MeshVertexInfo_t *pVertexInfo );
+
+ // Removes a decal and associated vertices + indices from the history list
+ void RetireDecal( DecalModelList_t &list, DecalId_t nDecalID, int iLOD, int iMaxLOD );
+
+ // Helper methods related to drawing decals
+ void DrawSingleBoneDecals( CMeshBuilder& meshBuilder, DecalMaterial_t& decalMaterial );
+ bool DrawMultiBoneDecals( CMeshBuilder& meshBuilder, DecalMaterial_t& decalMaterial, studiohdr_t *pStudioHdr );
+ void DrawSingleBoneFlexedDecals( IMatRenderContext *pRenderContext, CMeshBuilder& meshBuilder, DecalMaterial_t& decalMaterial );
+ bool DrawMultiBoneFlexedDecals( IMatRenderContext *pRenderContext, CMeshBuilder& meshBuilder, DecalMaterial_t& decalMaterial, studiohdr_t *pStudioHdr, studioloddata_t *pStudioLOD );
+ void DrawDecalMaterial( IMatRenderContext *pRenderContext, DecalMaterial_t& decalMaterial, studiohdr_t *pStudioHdr, studioloddata_t *pStudioLOD );
+ void DrawDecal( const DrawModelInfo_t &drawInfo, int lod, int body );
+ bool PreDrawDecal( IMatRenderContext *pRenderContext, const DrawModelInfo_t &drawInfo );
+
+ // Draw shadows
+ void DrawShadows( const DrawModelInfo_t& info, int flags, int boneMask );
+
+ // Draw flashlight lighting on decals.
+ void DrawFlashlightDecals( const DrawModelInfo_t& info, int lod );
+
+ // Helper methods related to extracting and balancing
+ float RampFlexWeight( mstudioflex_t &flex, float w );
+
+ // Remove decal from LRU
+ void RemoveDecalListFromLRU( StudioDecalHandle_t h );
+
+ // Helper methods related to flexing vertices
+ void R_StudioFlexVerts( mstudiomesh_t *pmesh, int lod );
+
+ // Flex stats
+ void GetFlexStats( );
+
+ // Sets up the hw flex mesh
+ void ComputeFlexWeights( int nFlexCount, mstudioflex_t *pFlex, MorphWeight_t *pWeights );
+
+ // Generate morph accumulator
+ void GenerateMorphAccumulator( mstudiomodel_t *pSubModel );
+
+ // Computes eyeball state
+ void ComputeEyeballState( mstudiomodel_t *pSubModel );
+
+ // Avoid some warnings...
+ CStudioRender( CStudioRender const& );
+
+public:
+ // Render context (comes from queue)
+ StudioRenderContext_t *m_pRC;
+
+private:
+ // Stores all decals for a particular material and lod
+ CUtlLinkedList< DecalMaterial_t, unsigned short, true > m_DecalMaterial;
+
+ // Stores all decal lists that have been made
+ CUtlFixedLinkedList< DecalModelList_t > m_DecalList;
+ CThreadFastMutex m_DecalMutex;
+
+ // Stores all shadows to be cast on the current object
+ CUtlVector<ShadowState_t> m_ShadowState;
+
+ matrix3x4_t m_StaticPropRootToWorld;
+ matrix3x4_t *m_pBoneToWorld; // bone transformation matrix( comes from queue )
+
+ matrix3x4_t *m_PoseToWorld; // bone transformation matrix
+ matrix3x4_t *m_PoseToDecal; // bone transformation matrix
+
+ // Flex state, comes from queue
+ float *m_pFlexWeights;
+ float *m_pFlexDelayedWeights;
+
+ studiohdr_t *m_pStudioHdr;
+ mstudiomodel_t *m_pSubModel;
+ studiomeshdata_t *m_pStudioMeshes;
+
+ eyeballstate_t m_pEyeballState[16]; // MAXSTUDIOEYEBALLS
+
+ // debug materials
+ IMaterial *m_pMaterialMRMWireframe;
+ IMaterial *m_pMaterialMRMWireframeZBuffer;
+ IMaterial *m_pMaterialMRMNormals;
+ IMaterial *m_pMaterialTangentFrame;
+ IMaterial *m_pMaterialTranslucentModelHulls;
+ IMaterial *m_pMaterialSolidModelHulls;
+ IMaterial *m_pMaterialAdditiveVertexColorVertexAlpha;
+ IMaterial *m_pMaterialModelBones;
+ IMaterial *m_pMaterialWorldWireframe;
+ IMaterial *m_pMaterialModelEnvCubemap;
+
+ // Depth override material
+ IMaterial *m_pDepthWrite[2][2];
+ IMaterial *m_pSSAODepthWrite[2][2];
+
+ // GLINT data
+ ITexture* m_pGlintTexture;
+ ITexture* m_pGlintLODTexture;
+ IMaterial *m_pGlintBuildMaterial;
+ short m_GlintWidth;
+ short m_GlintHeight;
+
+ // Flex data
+ CCachedRenderData m_VertexCache;
+
+ // Cached variables:
+ bool m_bSkippedMeshes : 1;
+ bool m_bDrawTranslucentSubModels : 1;
+
+ DecalId_t m_nDecalId;
+ CUtlFixedLinkedList< DecalLRU_t > m_DecalLRU;
+
+ friend class CGlintTextureRegenerator;
+ friend struct mstudiomodel_t;
+ friend class CStudioRenderContext;
+};
+
+
+//-----------------------------------------------------------------------------
+// Converts matrices to a format material system wants
+//-----------------------------------------------------------------------------
+
+/*
+================
+R_StudioTransform
+================
+*/
+inline void CStudioRender::R_StudioTransform( Vector& in1, mstudioboneweight_t *pboneweight, Vector& out1 )
+{
+// MEASURECODE( "R_StudioTransform" );
+
+ Vector out2;
+ switch( pboneweight->numbones )
+ {
+ case 1:
+ VectorTransform( in1, m_PoseToWorld[(unsigned)pboneweight->bone[0]], out1 );
+ break;
+/*
+ case 2:
+ VectorTransform( in1, m_PoseToWorld[pboneweight->bone[0]], out1 );
+ out1 *= pboneweight->weight[0];
+ VectorTransform( in1, m_PoseToWorld[pboneweight->bone[1]], out2 );
+ VectorMA( out1, pboneweight->weight[1], out2, out1 );
+ break;
+
+ case 3:
+ VectorTransform( in1, m_PoseToWorld[pboneweight->bone[0]], out1 );
+ out1 *= pboneweight->weight[0];
+ VectorTransform( in1, m_PoseToWorld[pboneweight->bone[1]], out2 );
+ VectorMA( out1, pboneweight->weight[1], out2, out1 );
+ VectorTransform( in1, m_PoseToWorld[pboneweight->bone[2]], out2 );
+ VectorMA( out1, pboneweight->weight[2], out2, out1 );
+ break;
+*/
+ default:
+ VectorFill( out1, 0 );
+ for (int i = 0; i < pboneweight->numbones; i++)
+ {
+ VectorTransform( in1, m_PoseToWorld[(unsigned)pboneweight->bone[i]], out2 );
+ VectorMA( out1, pboneweight->weight[i], out2, out1 );
+ }
+ break;
+ }
+}
+
+
+/*
+================
+R_StudioRotate
+================
+*/
+inline void CStudioRender::R_StudioRotate( Vector& in1, mstudioboneweight_t *pboneweight, Vector& out1 )
+{
+ // NOTE: This only works to rotate normals if there's no scale in the
+ // pose to world transforms. If we ever add scale, we'll need to
+ // multiply by the inverse transpose of the pose to world
+
+ if (pboneweight->numbones == 1)
+ {
+ VectorRotate( in1, m_PoseToWorld[(unsigned)pboneweight->bone[0]], out1 );
+ }
+ else
+ {
+ Vector out2;
+
+ VectorFill( out1, 0 );
+
+ for (int i = 0; i < pboneweight->numbones; i++)
+ {
+ VectorRotate( in1, m_PoseToWorld[(unsigned)pboneweight->bone[i]], out2 );
+ VectorMA( out1, pboneweight->weight[i], out2, out1 );
+ }
+ VectorNormalize( out1 );
+ }
+}
+
+inline void CStudioRender::R_StudioRotate( Vector4D& realIn1, mstudioboneweight_t *pboneweight, Vector4D& realOut1 )
+{
+ // garymcthack - god this sucks.
+ Vector in1( realIn1[0], realIn1[1], realIn1[2] );
+ Vector out1;
+ if (pboneweight->numbones == 1)
+ {
+ VectorRotate( in1, m_PoseToWorld[(unsigned)pboneweight->bone[0]], out1 );
+ }
+ else
+ {
+ Vector out2;
+
+ VectorFill( out1, 0 );
+
+ for (int i = 0; i < pboneweight->numbones; i++)
+ {
+ VectorRotate( in1, m_PoseToWorld[(unsigned)pboneweight->bone[i]], out2 );
+ VectorMA( out1, pboneweight->weight[i], out2, out1 );
+ }
+ VectorNormalize( out1 );
+ }
+ realOut1.Init( out1[0], out1[1], out1[2], realIn1[3] );
+}
+
+
+//-----------------------------------------------------------------------------
+// Compute the contribution of a light depending on it's angle
+//-----------------------------------------------------------------------------
+/*
+ light_normal (lights normal translated to same space as other normals)
+ surface_normal
+ light_direction_normal | (light_pos - vertex_pos) |
+*/
+
+template< int nLightType >
+class CWorldLightAngleWrapper
+{
+public:
+ FORCEINLINE static float WorldLightAngle( const LightDesc_t *wl, const Vector& lnormal, const Vector& snormal, const Vector& delta )
+ {
+ float dot, dot2, ratio;
+
+ switch (nLightType)
+ {
+ case MATERIAL_LIGHT_POINT:
+#if 1
+ // half-lambert
+ dot = DotProduct( snormal, delta );
+ if (dot < 0.f)
+ return 0.f;
+#else
+ dot = DotProduct( snormal, delta ) * 0.5 + 0.5;
+ dot = dot * dot;
+#endif
+ return dot;
+
+ case MATERIAL_LIGHT_SPOT:
+#if 1
+ // half-lambert
+ dot = DotProduct( snormal, delta );
+ if (dot < 0.)
+ return 0.f;
+#else
+ dot = DotProduct( snormal, delta ) * 0.5 + 0.5;
+ dot = dot * dot;
+#endif
+
+ dot2 = -DotProduct (delta, lnormal);
+ if (dot2 <= wl->m_PhiDot)
+ return 0.f; // outside light cone
+
+ ratio = dot;
+ if (dot2 >= wl->m_ThetaDot)
+ return ratio; // inside inner cone
+
+ if ((wl->m_Falloff == 1.f) || (wl->m_Falloff == 0.f))
+ {
+ ratio *= (dot2 - wl->m_PhiDot) / (wl->m_ThetaDot - wl->m_PhiDot);
+ }
+ else
+ {
+ ratio *= pow((dot2 - wl->m_PhiDot) / (wl->m_ThetaDot - wl->m_PhiDot), wl->m_Falloff );
+ }
+ return ratio;
+
+ case MATERIAL_LIGHT_DIRECTIONAL:
+#if 1
+ // half-lambert
+ dot2 = -DotProduct( snormal, lnormal );
+ if (dot2 < 0.f)
+ return 0.f;
+#else
+ dot2 = -DotProduct( snormal, lnormal ) * 0.5 + 0.5;
+ dot2 = dot2 * dot2;
+#endif
+ return dot2;
+
+ case MATERIAL_LIGHT_DISABLE:
+ return 0.f;
+
+ NO_DEFAULT;
+ }
+ }
+};
+
+template< int nLightType >
+class CWorldLightAngleWrapperConstDirectional
+{
+public:
+ FORCEINLINE static float WorldLightAngle( const LightDesc_t *wl, const Vector& lnormal, const Vector& snormal, const Vector& delta, float directionalamount )
+ {
+ float dot, dot2, ratio;
+
+ // directional amount is constant
+ dot = directionalamount;
+ if (dot < 0.f)
+ return 0.f;
+
+ switch (nLightType)
+ {
+ case MATERIAL_LIGHT_POINT:
+ case MATERIAL_LIGHT_DIRECTIONAL:
+ return dot;
+
+ case MATERIAL_LIGHT_SPOT:
+ dot2 = -DotProduct (delta, lnormal);
+ if (dot2 <= wl->m_PhiDot)
+ return 0.f; // outside light cone
+
+ ratio = dot;
+ if (dot2 >= wl->m_ThetaDot)
+ return ratio; // inside inner cone
+
+ if ((wl->m_Falloff == 1.f) || (wl->m_Falloff == 0.f))
+ {
+ ratio *= (dot2 - wl->m_PhiDot) / (wl->m_ThetaDot - wl->m_PhiDot);
+ }
+ else
+ {
+ ratio *= pow((dot2 - wl->m_PhiDot) / (wl->m_ThetaDot - wl->m_PhiDot), wl->m_Falloff );
+ }
+ return ratio;
+
+ case MATERIAL_LIGHT_DISABLE:
+ return 0.f;
+
+ NO_DEFAULT;
+ }
+ }
+};
+
+inline float CStudioRender::R_WorldLightAngle( const LightDesc_t *wl, const Vector& lnormal, const Vector& snormal, const Vector& delta )
+{
+ switch (wl->m_Type)
+ {
+ case MATERIAL_LIGHT_DISABLE: return CWorldLightAngleWrapper<MATERIAL_LIGHT_DISABLE>::WorldLightAngle( wl, lnormal, snormal, delta );
+ case MATERIAL_LIGHT_POINT: return CWorldLightAngleWrapper<MATERIAL_LIGHT_POINT>::WorldLightAngle( wl, lnormal, snormal, delta );
+ case MATERIAL_LIGHT_DIRECTIONAL: return CWorldLightAngleWrapper<MATERIAL_LIGHT_DIRECTIONAL>::WorldLightAngle( wl, lnormal, snormal, delta );
+ case MATERIAL_LIGHT_SPOT: return CWorldLightAngleWrapper<MATERIAL_LIGHT_SPOT>::WorldLightAngle( wl, lnormal, snormal, delta );
+ NO_DEFAULT;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Draws eyeballs
+//-----------------------------------------------------------------------------
+inline void CStudioRender::R_StudioEyeballNormal( mstudioeyeball_t const* peyeball, Vector& org,
+ Vector& pos, Vector& normal )
+{
+ // inside of a flattened torus
+ VectorSubtract( pos, org, normal );
+ float flUpAmount = DotProduct( normal, peyeball->up );
+ VectorMA( normal, -0.5 * flUpAmount, peyeball->up, normal );
+ VectorNormalize( normal );
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// Stateless utility methods
+//
+//-----------------------------------------------------------------------------
+
+// Computes the submodel for a specified body + bodypart
+int R_StudioSetupModel( int nBodyPart, int nBody, mstudiomodel_t **pSubModel, const studiohdr_t *pStudioHdr );
+
+// Computes PoseToWorld from BoneToWorld
+void ComputePoseToWorld( matrix3x4_t *pPoseToWorld, studiohdr_t *pStudioHdr, int boneMask, const Vector& vecViewOrigin, const matrix3x4_t *pBoneToWorld );
+
+// Computes the model LOD
+inline int ComputeModelLODAndMetric( studiohwdata_t *pHardwareData, float flUnitSphereSize, float *pMetric )
+{
+ // NOTE: This function was split off since CStudioRender needs it also.
+ float flMetric = pHardwareData->LODMetric( flUnitSphereSize );
+ if ( pMetric )
+ {
+ *pMetric = flMetric;
+ }
+ return pHardwareData->GetLODForMetric( flMetric );
+}
+
+
+
+#endif // CSTUDIORENDER_H