diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /studiorender/studiorender.h | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'studiorender/studiorender.h')
| -rw-r--r-- | studiorender/studiorender.h | 931 |
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 |