|
|
//===== Copyright 1996-2005, 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; struct MeshRenderData_t; struct MeshRenderData2_t; struct BaseMeshRenderData_t; struct ShadowMeshRenderData_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
#define MAX_MAT_OVERRIDES 4
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 ) const { if ((m_Body == 0xFFFF) || (m_Model == 0xFFFF) || (m_Mesh == 0xFFFF)) return NULL;
mstudiobodyparts_t * RESTRICT pBody = pHdr->pBodypart( m_Body ); mstudiomodel_t * RESTRICT 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 BeginFrame( void ); void EndFrame( void );
void PushScissor( FlashlightState_t *state ); void PopScissor( FlashlightState_t *state );
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 StudioModelArrayInfo_t &drawInfo, const StudioRenderContext_t &rc, int arrayCount, StudioArrayInstanceData_t *pInstanceData, int instanceStride, int flags = STUDIORENDER_DRAW_ENTIRE_MODEL ); void DrawModelArray2( const StudioModelArrayInfo2_t &info, const StudioRenderContext_t &rc, int nCount, StudioArrayData_t *pArrayData, int nInstanceStride, int flags = STUDIORENDER_DRAW_ENTIRE_MODEL ); void DrawModelShadowArray( const StudioRenderContext_t &rc, int nCount, StudioArrayData_t *pShadowData, int nInstanceStride, int flags );
// 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 DrawModelArrayStaticProp( const DrawModelInfo_t& info, const StudioRenderContext_t &rc, int nInstanceCount, const MeshInstanceData_t *pInstanceData, ColorMeshInfo_t **pColorMeshes ); 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 );
// 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, void *pvProxyUserData = NULL, int nAdditionalDecalFlags = 0 );
// 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
#ifndef _CERT
void GatherRenderedFaceInfo( IStudioRender::FaceInfoCallbackFunc_t pFunc ); // Spew per-model-per-frame 'faces rendered' counters:
void UpdateModelFaceCounts( int nNumToSpew = 0, bool bClearHistory = 0 ); #endif // _CERT
int GetForcedMaterialOverrideIndex( int nMaterialIndex );
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; };
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; void *m_pvProxyUserData; };
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
};
// Render data for decals
struct DecalRenderData_t { DecalMaterial_t *m_pDecalMaterial; StudioArrayInstanceData_t *m_pInstance; IMaterial *m_pRenderMaterial; bool m_bIsVertexLit; };
// 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; float m_flMaxDepth; float m_flFrontFacingCosineCheck; 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; bool m_AllowBehindPointOfImpact; bool m_bEnforceProjectionRadiusZ; };
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; int m_nFlags; };
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, IMaterial *pMaterial ); void R_StudioSoftwareProcessMesh_NormalsBatched( IMatRenderContext *pRenderContext, mstudiomesh_t* pmesh, studiomeshgroup_t* pGroup, StudioModelLighting_t lighting, bool doFlex, float r_blend, bool bShowNormals, bool bShowTangent );
void R_StudioSoftwareProcessMesh_Normals( mstudiomesh_t* pmesh, CMeshBuilder& meshBuilder, int firstVertex, int numVertices, unsigned short* pGroupToMesh, StudioModelLighting_t lighting, bool doFlex, float r_blend, bool bShowNormals, bool bShowTangentS, bool bShowTangentT );
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( ) 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, matrix3x4_t *pPoseToWorld, Vector& out1 ); inline void R_StudioRotate( Vector& in1, mstudioboneweight_t *pboneweight, matrix3x4_t *pPoseToWorld, Vector& out1 ); inline void R_StudioRotate( Vector4D& in1, mstudioboneweight_t *pboneweight, matrix3x4_t *pPoseToWorld, 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 );
bool BTryToRetireDecal( StudioDecalHandle_t hDecal, DecalHistoryList_t *pHistoryList, bool bCanRetirePlayerSpray );
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( DecalBuildInfo_t& build, const Vector * norm, const mstudioboneweight_t *pboneweight ); bool IsDecalStartPointWithinZLimit( DecalBuildInfo_t& build, const Vector * ppos, 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, void *pvProxyUserData ); 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 );
// Same as above, but doesn't repeat a walk through the LRU list.
void RetireDecalAtAddress( DecalModelList_t &list, DecalLRUListIndex_t lruAddress, int iLOD, int iMaxLOD );
// Cleans up immediate mode decals.
void CleanupDecals();
// Helper methods related to drawing decals
void DrawSingleBoneDecals( CMeshBuilder& meshBuilder, const 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, bool bQuadList );
// 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 );
// Implementational methods of model array rendering
void DrawModelSubArray( IMatRenderContext* pRenderContext, const StudioModelArrayInfo_t &drawInfo, const StudioRenderContext_t &rc, int nCount, StudioArrayInstanceData_t *pInstanceData, int nInstanceStride, int nFlags );
// Implementation details for fast model rendering
int CountMeshesToDraw( const StudioModelArrayInfo_t &drawInfo, int nCount, StudioArrayInstanceData_t *pInstanceData, int nInstanceStride, int nTimesRendered ); int CountMeshesToDraw( const StudioModelArrayInfo2_t &drawInfo, int nCount, StudioArrayData_t *pArrayData, int nInstanceStride, int nTimesRendered );
static bool SortLessFunc( const MeshRenderData_t &left, const MeshRenderData_t &right ); static bool SortLessFunc2( const MeshRenderData2_t &left, const MeshRenderData2_t &right );
int BuildSortedRenderList( MeshRenderData_t *pRenderData, int *pTotalStripCount, const StudioModelArrayInfo_t &drawInfo, int nCount, StudioArrayInstanceData_t *pInstanceData, int nInstanceStride, int nFlags ); int BuildSortedRenderList( MeshRenderData2_t *pRenderData, int *pTotalStripCount, const StudioModelArrayInfo2_t &drawInfo, int nCount, StudioArrayData_t *pArrayData, int nInstanceStride, int nFlags ); void BuildForcedMaterialRenderList( MeshRenderData_t *pRenderData, int *pTotalStripCount, const StudioModelArrayInfo_t &drawInfo, const StudioRenderContext_t &rc, int nCount, StudioArrayInstanceData_t *pInstanceData, int nInstanceStride ); void BuildForcedMaterialRenderList( MeshRenderData2_t *pRenderData, int *pTotalStripCount, const StudioModelArrayInfo2_t &drawInfo, const StudioRenderContext_t &rc, int nCount, StudioArrayData_t *pArrayData, int nInstanceStride ); void RestoreMeshes( int nCount, BaseMeshRenderData_t *pRenderData, int nStride ); void DrawMeshRenderData( IMatRenderContext *pRenderContext, const StudioModelArrayInfo_t &drawInfo, int nCount, MeshRenderData_t *pRenderData, int nTotalStripCount, int nFlashlightMask ); void DrawMeshRenderData( IMatRenderContext *pRenderContext, const StudioModelArrayInfo2_t &drawInfo, int nCount, MeshRenderData2_t *pRenderData, int nTotalStripCount, int nFlashlightMask ); void DrawModelArrayFlashlight( IMatRenderContext *pRenderContext, const StudioModelArrayInfo_t &drawInfo, int nCount, MeshRenderData_t *pRenderData, int nTotalStripCount ); void DrawModelArrayFlashlight( IMatRenderContext *pRenderContext, const StudioModelArrayInfo2_t &drawInfo, int nCount, MeshRenderData2_t *pRenderData, int nTotalStripCount ); void BuildDecalIndices( CMeshBuilder &meshBuilder, const DecalMaterial_t& decalMaterial ); int CountDecalMeshesToDraw( int nCount, StudioArrayInstanceData_t *pInstanceData, int nInstanceStride ); static bool SortDecalsLessFunc( const DecalRenderData_t &left, const DecalRenderData_t &right ); int BuildSortedDecalRenderList( DecalRenderData_t *pDecalRenderData, int nCount, StudioArrayInstanceData_t *pInstanceData, int nInstanceStride ); void DrawInstancedMultiBoneDecals( CMeshBuilder& meshBuilder, const DecalMaterial_t& decalMaterial, studiohdr_t *pStudioHdr, matrix3x4_t *pPoseToWorld ); void DrawInstancedSingleBoneDecals( CMeshBuilder& meshBuilder, const DecalMaterial_t& decalMaterial, studiohdr_t *pStudioHdr, matrix3x4_t *pPoseToWorld ); void DrawModelArrayDecals( IMatRenderContext *pRenderContext, studiohdr_t *pStudioHdr, int nCount, DecalRenderData_t *pRenderData, int nFlashlightMask ); void DrawModelArrayFlashlightDecals( IMatRenderContext *pRenderContext, studiohdr_t *pStudioHdr, int nFlashlightCount, FlashlightInstance_t *pFlashlights, int nCount, DecalRenderData_t *pRenderData );
// Implementation details w/ respect to shadow depth rendering
int CountMeshesToDraw( int nCount, StudioArrayData_t *pShadowData, int nInstanceStride ); int BuildShadowRenderList( ShadowMeshRenderData_t *pRenderData, int *pTotalStripCount, int nCount, StudioArrayData_t *pShadowData, int nInstanceStride, int flags ); void DrawShadowMeshRenderData( IMatRenderContext *pRenderContext, int nCount, ShadowMeshRenderData_t *pRenderData, int nTotalStripCount ); void GetDepthWriteMaterial( IMaterial** ppDepthMaterial, bool *pIsAlphaTested, bool *pUsesTreeSway, IMaterial *pSrcMaterial, bool IsTranslucentUnderModulation, bool bIsSSAODepthWrite = false ); void SetupAlphaTestedDepthWrite( IMaterial* pDepthMaterial, IMaterial *pSrcMaterial ); void SetupTreeSwayDepthWrite( IMaterial* pDepthMaterial, IMaterial *pSrcMaterial ); static bool ShadowSortLessFunc( const ShadowMeshRenderData_t &left, const ShadowMeshRenderData_t &right );
void ComputeDiffuseModulation( Vector4D *pDiffuseModulation );
// Subdivision surface rendering methods
void SkinSubDCage( mstudiovertex_t *pVertices, int nNumVertices, matrix3x4_t *pPoseToWorld, CCachedRenderData &vertexCache, unsigned short* pGroupToMesh, fltx4 *vOutput, bool bDoFlex ); void GenerateBicubicPatches( mstudiomesh_t* pmesh, studiomeshgroup_t* pGroup, bool bDoFlex ); void SoftwareProcessQuadMesh( mstudiomesh_t* pmesh, CMeshBuilder& meshBuilder, int numFaces, unsigned short* pGroupToMesh, unsigned short *pIndices, bool bTangentSpace, bool bDoFlex );
// 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; studiohwdata_t *m_pStudioHWData;
eyeballstate_t m_pEyeballState[16]; // MAXSTUDIOEYEBALLS
// debug materials
IMaterial *m_pMaterialWireframe[2][2]; // Four flavors: (ZBuffer, DisplacementMapped)
IMaterial *m_pMaterialMRMNormals; IMaterial *m_pMaterialTangentFrame; IMaterial *m_pMaterialTranslucentModelHulls; IMaterial *m_pMaterialSolidModelHulls; IMaterial *m_pMaterialAdditiveVertexColorVertexAlpha; IMaterial *m_pMaterialModelBones; IMaterial *m_pMaterialWorldWireframe; IMaterial *m_pMaterialModelEnvCubemap; IMaterial *m_pMaterialSolidBackfacePrepass;
// Depth override material
IMaterial *m_pDepthWrite[ 2 ][ 2 ][ 2 ]; IMaterial *m_pSSAODepthWrite[ 2 ][ 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;
FlashlightState_t *m_pCurrentFlashlight; #if !defined( LINUX )
// Vectors of Vector4D's for CPU-side subdivision surface processing
CUtlVector< fltx4, CUtlMemoryAligned<fltx4, 16> > m_vSkinnedSubDVertices; #endif
#ifndef _CERT
// Each model counts how many rendered faces it accounts for each frame:
CUtlHash< studiohwdata_t * > m_ModelFaceCountHash; #endif // !_CERT
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, matrix3x4_t *pPoseToWorld, Vector& out1 ) { // MEASURECODE( "R_StudioTransform" );
Vector out2; switch( pboneweight->numbones ) { case 1: VectorTransform( in1, pPoseToWorld[pboneweight->bone[0]], out1 ); break; /*
case 2: VectorTransform( in1, pPoseToWorld[pboneweight->bone[0]], out1 ); out1 *= pboneweight->weight[0]; VectorTransform( in1, pPoseToWorld[pboneweight->bone[1]], out2 ); VectorMA( out1, pboneweight->weight[1], out2, out1 ); break;
case 3: VectorTransform( in1, pPoseToWorld[pboneweight->bone[0]], out1 ); out1 *= pboneweight->weight[0]; VectorTransform( in1, pPoseToWorld[pboneweight->bone[1]], out2 ); VectorMA( out1, pboneweight->weight[1], out2, out1 ); VectorTransform( in1, pPoseToWorld[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, pPoseToWorld[pboneweight->bone[i]], out2 ); VectorMA( out1, pboneweight->weight[i], out2, out1 ); } break; } }
/*
================ R_StudioRotate ================ */ inline void CStudioRender::R_StudioRotate( Vector& in1, mstudioboneweight_t *pboneweight, matrix3x4_t *pPoseToWorld, 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, pPoseToWorld[pboneweight->bone[0]], out1 ); } else { Vector out2;
VectorFill( out1, 0 );
for (int i = 0; i < pboneweight->numbones; i++) { VectorRotate( in1, pPoseToWorld[pboneweight->bone[i]], out2 ); VectorMA( out1, pboneweight->weight[i], out2, out1 ); } VectorNormalize( out1 ); } }
inline void CStudioRender::R_StudioRotate( Vector4D& realIn1, mstudioboneweight_t *pboneweight, matrix3x4_t *pPoseToWorld, Vector4D& realOut1 ) { // garymcthack - god this sucks.
Vector in1( realIn1[0], realIn1[1], realIn1[2] ); Vector out1; if (pboneweight->numbones == 1) { VectorRotate( in1, pPoseToWorld[pboneweight->bone[0]], out1 ); } else { Vector out2;
VectorFill( out1, 0 );
for (int i = 0; i < pboneweight->numbones; i++) { VectorRotate( in1, pPoseToWorld[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; } #ifdef _PS3
Assert( false ); // PS3 doesn't have true __assume (used in NO_DEFAULT), so a return value is expected
return 0.0f; #endif
} };
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; } #ifdef _PS3
Assert( false ); // PS3 doesn't have true __assume (used in NO_DEFAULT), so a return value is expected
return 0.0f; #endif
} };
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; } #ifdef _PS3
Assert( false ); // PS3 doesn't have true __assume (used in NO_DEFAULT), so a return value is expected
return 0.0f; #endif
}
//-----------------------------------------------------------------------------
// 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 ); }
// Helper to determine which material type to use depending on what strip header flags are set.
MaterialPrimitiveType_t GetPrimitiveTypeForStripHeaderFlags( unsigned char Flags );
#endif // CSTUDIORENDER_H
|