|
|
//========= Copyright � 1996-2008, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef FLEXRENDERDATA_H
#define FLEXRENDERDATA_H
#ifdef _WIN32
#pragma once
#endif
#include "mathlib/vector.h"
#include "mathlib/ssemath.h"
#include "utlvector.h"
#include "studio.h"
//-----------------------------------------------------------------------------
// forward declarations
//-----------------------------------------------------------------------------
struct mstudiomesh_t;
//-----------------------------------------------------------------------------
// Used by flex vertex data cache
//-----------------------------------------------------------------------------
struct CachedPosNormTan_t { Vector4D m_Position; Vector4D m_Normal; Vector4D m_TangentS;
CachedPosNormTan_t() {}
CachedPosNormTan_t( CachedPosNormTan_t const& src ) { Vector4DCopy( src.m_Position, m_Position ); Vector4DCopy( src.m_Normal, m_Normal ); Vector4DCopy( src.m_TangentS, m_TangentS ); Assert( m_TangentS.w == 1.0f || m_TangentS.w == -1.0f ); } };
//-----------------------------------------------------------------------------
// Used by world (decal) vertex data cache
//-----------------------------------------------------------------------------
struct CachedPosNorm_t { Vector4DAligned m_Position; Vector4DAligned m_Normal;
CachedPosNorm_t() {}
CachedPosNorm_t( CachedPosNorm_t const& src ) { Vector4DCopy( src.m_Position, m_Position ); Vector4DCopy( src.m_Normal, m_Normal ); } };
//-----------------------------------------------------------------------------
// Stores flex vertex data and world (decal) vertex data for the lifetime of the model rendering
//-----------------------------------------------------------------------------
class CCachedRenderData { public: // Constructor
CCachedRenderData();
// Call this when we start to render a new model
void StartModel();
// Used to hook ourselves into a particular body part, model, and mesh
void SetBodyPart( int bodypart ); void SetModel( int model ); void SetMesh( int mesh );
// For faster setup in the decal code
void SetBodyModelMesh( int body, int model, int mesh );
// Used to set up a flex computation
bool IsFlexComputationDone( ) const;
// Used to set up a computation (for world or flex data)
void SetupComputation( mstudiomesh_t *pMesh, bool flexComputation = false );
// Is a particular vertex flexed?
bool IsVertexFlexed( int vertex ) const; bool IsThinVertexFlexed( int vertex ) const;
// Checks to see if the vertex is defined
bool IsVertexPositionCached( int vertex ) const;
// Gets a flexed vertex
CachedPosNormTan_t* GetFlexVertex( int vertex );
// Gets a flexed vertex
CachedPosNorm_t* GetThinFlexVertex( int vertex );
// Creates a new flexed vertex to be associated with a vertex
CachedPosNormTan_t* CreateFlexVertex( int vertex );
// Creates a new flexed vertex to be associated with a vertex
CachedPosNorm_t* CreateThinFlexVertex( int vertex );
// Renormalizes the normals and tangents of the flex verts
void RenormalizeFlexVertices( bool bHasTangentData, bool bQuadList );
// Gets a decal vertex
CachedPosNorm_t* GetWorldVertex( int vertex );
// Creates a new decal vertex to be associated with a vertex
CachedPosNorm_t* CreateWorldVertex( int vertex );
template< class T > void ComputeFlexedVertex_StreamOffset( studiohdr_t *pStudioHdr, mstudioflex_t *pflex, T *pvanim, int vertCount, float w1, float w2, float w3, float w4 );
void ComputeFlexedVertex_StreamOffset_Optimized( studiohdr_t *pStudioHdr, mstudioflex_t *pflex, mstudiovertanim_t *pvanim, int vertCount, float w1, float w2, float w3, float w4); void ComputeFlexedVertexWrinkle_StreamOffset_Optimized( studiohdr_t *pStudioHdr, mstudioflex_t *pflex, mstudiovertanim_wrinkle_t *pvanim, int vertCount, float w1, float w2, float w3, float w4); private: // Used to create the flex render data. maps
struct CacheIndex_t { unsigned short m_Tag; unsigned short m_VertexIndex; };
// A dictionary for the cached data
struct CacheDict_t { unsigned short m_FirstIndex; unsigned short m_IndexCount; unsigned short m_Tag; unsigned short m_FlexTag;
CacheDict_t() : m_Tag(0), m_FlexTag(0) {} };
typedef CUtlVector< CacheDict_t > CacheMeshDict_t; typedef CUtlVector< CacheMeshDict_t > CacheModelDict_t; typedef CUtlVector< CacheModelDict_t > CacheBodyPartDict_t;
// Flex data, allocated for the lifespan of rendering
// Can't use UtlVector due to alignment issues
int m_FlexVertexCount; CachedPosNormTan_t m_pFlexVerts[MAXSTUDIOFLEXVERTS+1];
// Flex data, allocated for the lifespan of rendering
// Can't use UtlVector due to alignment issues
int m_ThinFlexVertexCount; CachedPosNorm_t m_pThinFlexVerts[MAXSTUDIOFLEXVERTS+1];
// World data, allocated for the lifespan of rendering
// Can't use UtlVector due to alignment issues
int m_WorldVertexCount; CachedPosNorm_t m_pWorldVerts[MAXSTUDIOVERTS+1];
// Maps actual mesh vertices into flex cache + world cache indices
int m_IndexCount; CacheIndex_t m_pFlexIndex[MAXSTUDIOVERTS+1]; CacheIndex_t m_pThinFlexIndex[MAXSTUDIOVERTS+1]; CacheIndex_t m_pWorldIndex[MAXSTUDIOVERTS+1];
CacheBodyPartDict_t m_CacheDict;
// The flex tag
unsigned short m_CurrentTag;
// the current body, model, and mesh
int m_Body; int m_Model; int m_Mesh;
// mapping for the current mesh to flex data
CacheIndex_t* m_pFirstFlexIndex; CacheIndex_t* m_pFirstThinFlexIndex; CacheIndex_t* m_pFirstWorldIndex;
friend class CStudioRender; };
//-----------------------------------------------------------------------------
// Checks to see if the vertex is defined
//-----------------------------------------------------------------------------
inline bool CCachedRenderData::IsVertexFlexed( int vertex ) const { return (m_pFirstFlexIndex && (m_pFirstFlexIndex[vertex].m_Tag == m_CurrentTag)); }
inline bool CCachedRenderData::IsThinVertexFlexed( int vertex ) const { return (m_pFirstThinFlexIndex && (m_pFirstThinFlexIndex[vertex].m_Tag == m_CurrentTag)); }
//-----------------------------------------------------------------------------
// Gets an existing flexed vertex associated with a vertex
//-----------------------------------------------------------------------------
inline CachedPosNormTan_t* CCachedRenderData::GetFlexVertex( int vertex ) { Assert( m_pFirstFlexIndex ); Assert( m_pFirstFlexIndex[vertex].m_Tag == m_CurrentTag ); return &m_pFlexVerts[ m_pFirstFlexIndex[vertex].m_VertexIndex ]; }
inline CachedPosNorm_t* CCachedRenderData::GetThinFlexVertex( int vertex ) { Assert( m_pFirstThinFlexIndex ); Assert( m_pFirstThinFlexIndex[vertex].m_Tag == m_CurrentTag ); return &m_pThinFlexVerts[ m_pFirstThinFlexIndex[vertex].m_VertexIndex ]; }
//-----------------------------------------------------------------------------
// Checks to see if the vertex is defined
//-----------------------------------------------------------------------------
inline bool CCachedRenderData::IsVertexPositionCached( int vertex ) const { return (m_pFirstWorldIndex && (m_pFirstWorldIndex[vertex].m_Tag == m_CurrentTag)); }
//-----------------------------------------------------------------------------
// Gets an existing world vertex associated with a vertex
//-----------------------------------------------------------------------------
inline CachedPosNorm_t* CCachedRenderData::GetWorldVertex( int vertex ) { Assert( m_pFirstWorldIndex ); Assert( m_pFirstWorldIndex[vertex].m_Tag == m_CurrentTag ); return &m_pWorldVerts[ m_pFirstWorldIndex[vertex].m_VertexIndex ]; }
//-----------------------------------------------------------------------------
// For faster setup in the decal code
//-----------------------------------------------------------------------------
inline void CCachedRenderData::SetBodyModelMesh( int body, int model, int mesh) { m_Body = body; m_Model = model; m_Mesh = mesh;
// At this point, we should have all 3 defined.
CacheDict_t& dict = m_CacheDict[m_Body][m_Model][m_Mesh];
if (dict.m_Tag == m_CurrentTag) { m_pFirstFlexIndex = &m_pFlexIndex[dict.m_FirstIndex]; m_pFirstThinFlexIndex = &m_pThinFlexIndex[dict.m_FirstIndex]; m_pFirstWorldIndex = &m_pWorldIndex[dict.m_FirstIndex]; } else { m_pFirstFlexIndex = 0; m_pFirstThinFlexIndex = 0; m_pFirstWorldIndex = 0; } }
//-----------------------------------------------------------------------------
// Purpose:
//
// ** Only execute this function if device supports stream offset **
//
// Input : pmesh - pointer to a studio mesh
// lod - integer lod (0 is most detailed)
// Output : none
//-----------------------------------------------------------------------------
template< class T > void CCachedRenderData::ComputeFlexedVertex_StreamOffset( studiohdr_t *pStudioHdr, mstudioflex_t *pflex, T *pvanim, int vertCount, float w1, float w2, float w3, float w4 ) { float w12 = w1 - w2; float w34 = w3 - w4; float flVertAnimFixedPointScale = pStudioHdr->VertAnimFixedPointScale();
CachedPosNorm_t *pFlexedVertex = NULL; for (int j = 0; j < pflex->numverts; j++) { int n = pvanim[j].index;
// only flex the indices that are (still) part of this mesh at this lod
if ( n >= vertCount ) continue;
float s = pvanim[j].speed; float b = pvanim[j].side;
Vector4DAligned vPosition, vNormal; pvanim[j].GetDeltaFixed4DAligned( &vPosition, flVertAnimFixedPointScale ); pvanim[j].GetNDeltaFixed4DAligned( &vNormal, flVertAnimFixedPointScale );
if ( !IsThinVertexFlexed(n) ) { // Add a new flexed vert to the flexed vertex list
pFlexedVertex = CreateThinFlexVertex(n);
Assert( pFlexedVertex != NULL);
pFlexedVertex->m_Position.InitZero(); pFlexedVertex->m_Normal.InitZero(); } else { pFlexedVertex = GetThinFlexVertex(n); }
s *= 1.0f / 255.0f; b *= 1.0f / 255.0f;
float wa = w2 + w12 * s; float wb = w4 + w34 * s; float w = wa + ( wb - wa ) * b; Vector4DWeightMAD( w, vPosition, pFlexedVertex->m_Position, vNormal, pFlexedVertex->m_Normal ); } }
#endif // FLEXRENDERDATA_H
|