|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//===========================================================================//
#ifndef MESHBASE_H
#define MESHBASE_H
#ifdef _WIN32
#pragma once
#endif
#include "materialsystem/imesh.h"
#include "materialsystem/imaterial.h"
//-----------------------------------------------------------------------------
// Base vertex buffer
//-----------------------------------------------------------------------------
abstract_class CVertexBufferBase : public IVertexBuffer { // Methods of IVertexBuffer
public: virtual void Spew( int nVertexCount, const VertexDesc_t &desc ); virtual void ValidateData( int nVertexCount, const VertexDesc_t& desc );
public: // constructor, destructor
CVertexBufferBase( const char *pBudgetGroupName ); virtual ~CVertexBufferBase();
// Displays the vertex format
static void PrintVertexFormat( VertexFormat_t vertexFormat );
// Used to construct vertex data
static void ComputeVertexDescription( unsigned char *pBuffer, VertexFormat_t vertexFormat, VertexDesc_t &desc );
// Returns the vertex format size
static int VertexFormatSize( VertexFormat_t vertexFormat );
protected: const char *m_pBudgetGroupName; };
//-----------------------------------------------------------------------------
// Base index buffer
//-----------------------------------------------------------------------------
abstract_class CIndexBufferBase : public IIndexBuffer { // Methods of IIndexBuffer
public: virtual void Spew( int nIndexCount, const IndexDesc_t &desc ); virtual void ValidateData( int nIndexCount, const IndexDesc_t& desc );
// Other public methods
public: // constructor, destructor
CIndexBufferBase( const char *pBudgetGroupName ); virtual ~CIndexBufferBase() {}
protected: const char *m_pBudgetGroupName; };
//-----------------------------------------------------------------------------
// Base mesh
//-----------------------------------------------------------------------------
class CMeshBase : public IMesh { // Methods of IMesh
public:
// Other public methods that need to be overridden
public: // Begins a pass
virtual void BeginPass( ) = 0;
// Draws a single pass of the mesh
virtual void RenderPass() = 0;
// Does it have a color mesh?
virtual bool HasColorMesh() const = 0;
// Am I using morph data?
virtual bool IsUsingMorphData() const = 0;
virtual bool HasFlexMesh() const = 0;
virtual IMesh *GetMesh() { return this; }
public: // constructor, destructor
CMeshBase(); virtual ~CMeshBase();
};
//-----------------------------------------------------------------------------
// Utility method for VertexDesc_t (don't want to expose it in public, in imesh.h)
//-----------------------------------------------------------------------------
inline void ComputeVertexDesc( unsigned char * pBuffer, VertexFormat_t vertexFormat, VertexDesc_t & desc ) { int i; int *pVertexSizesToSet[64]; int nVertexSizesToSet = 0; static ALIGN32 ModelVertexDX8_t temp[4]; float *dummyData = (float*)&temp; // should be larger than any CMeshBuilder command can set.
// Determine which vertex compression type this format specifies (affects element sizes/decls):
VertexCompressionType_t compression = CompressionType( vertexFormat ); desc.m_CompressionType = compression;
// We use fvf instead of flags here because we may pad out the fvf
// vertex structure to optimize performance
int offset = 0; // NOTE: At the moment, we assume that if you specify wrinkle, you also specify position
Assert( ( ( vertexFormat & VERTEX_WRINKLE ) == 0 ) || ( ( vertexFormat & VERTEX_POSITION ) != 0 ) ); if ( vertexFormat & VERTEX_POSITION ) { // UNDONE: compress position+wrinkle to SHORT4N, and roll the scale into the transform matrices
desc.m_pPosition = reinterpret_cast<float*>(pBuffer); offset += GetVertexElementSize( VERTEX_ELEMENT_POSITION, compression ); pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_Position;
if ( vertexFormat & VERTEX_WRINKLE ) { desc.m_pWrinkle = reinterpret_cast<float*>( pBuffer + offset ); offset += GetVertexElementSize( VERTEX_ELEMENT_WRINKLE, compression ); pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_Wrinkle; } else { desc.m_pWrinkle = dummyData; desc.m_VertexSize_Wrinkle = 0; } } else { desc.m_pPosition = dummyData; desc.m_VertexSize_Position = 0; desc.m_pWrinkle = dummyData; desc.m_VertexSize_Wrinkle = 0; }
// Bone weights/matrix indices
desc.m_NumBoneWeights = NumBoneWeights( vertexFormat );
Assert( ( desc.m_NumBoneWeights == 2 ) || ( desc.m_NumBoneWeights == 0 ) );
// We assume that if you have any indices/weights, you have exactly two of them
Assert( ( ( desc.m_NumBoneWeights == 2 ) && ( ( vertexFormat & VERTEX_BONE_INDEX ) != 0 ) ) || ( ( desc.m_NumBoneWeights == 0 ) && ( ( vertexFormat & VERTEX_BONE_INDEX ) == 0 ) ) );
if ( ( vertexFormat & VERTEX_BONE_INDEX ) != 0 ) { if ( desc.m_NumBoneWeights > 0 ) { Assert( desc.m_NumBoneWeights == 2 );
// Always exactly two weights
desc.m_pBoneWeight = reinterpret_cast<float*>(pBuffer + offset); offset += GetVertexElementSize( VERTEX_ELEMENT_BONEWEIGHTS2, compression ); pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_BoneWeight; } else { desc.m_pBoneWeight = dummyData; desc.m_VertexSize_BoneWeight = 0; }
desc.m_pBoneMatrixIndex = pBuffer + offset; offset += GetVertexElementSize( VERTEX_ELEMENT_BONEINDEX, compression ); pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_BoneMatrixIndex; } else { desc.m_pBoneWeight = dummyData; desc.m_VertexSize_BoneWeight = 0;
desc.m_pBoneMatrixIndex = (unsigned char*)dummyData; desc.m_VertexSize_BoneMatrixIndex = 0; }
if ( vertexFormat & VERTEX_NORMAL ) { desc.m_pNormal = reinterpret_cast<float*>(pBuffer + offset); // See PackNormal_[SHORT2|UBYTE4|HEND3N] in mathlib.h for the compression algorithm
offset += GetVertexElementSize( VERTEX_ELEMENT_NORMAL, compression ); pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_Normal; } else { desc.m_pNormal = dummyData; desc.m_VertexSize_Normal = 0; }
if ( vertexFormat & VERTEX_COLOR ) { desc.m_pColor = pBuffer + offset; offset += GetVertexElementSize( VERTEX_ELEMENT_COLOR, compression ); pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_Color; } else { desc.m_pColor = (unsigned char*)dummyData; desc.m_VertexSize_Color = 0; }
if ( vertexFormat & VERTEX_SPECULAR ) { desc.m_pSpecular = pBuffer + offset; offset += GetVertexElementSize( VERTEX_ELEMENT_SPECULAR, compression ); pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_Specular; } else { desc.m_pSpecular = (unsigned char*)dummyData; desc.m_VertexSize_Specular = 0; }
// Set up texture coordinates
for ( i = 0; i < VERTEX_MAX_TEXTURE_COORDINATES; ++i ) { // FIXME: compress texcoords to SHORT2N/SHORT4N, with a scale rolled into the texture transform
VertexElement_t texCoordElements[4] = { VERTEX_ELEMENT_TEXCOORD1D_0, VERTEX_ELEMENT_TEXCOORD2D_0, VERTEX_ELEMENT_TEXCOORD3D_0, VERTEX_ELEMENT_TEXCOORD4D_0 }; int nSize = TexCoordSize( i, vertexFormat ); if ( nSize != 0 ) { desc.m_pTexCoord[i] = reinterpret_cast<float*>(pBuffer + offset); VertexElement_t texCoordElement = (VertexElement_t)( texCoordElements[ nSize - 1 ] + i ); offset += GetVertexElementSize( texCoordElement, compression ); pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_TexCoord[i]; } else { desc.m_pTexCoord[i] = dummyData; desc.m_VertexSize_TexCoord[i] = 0; } }
// Binormal + tangent...
// Note we have to put these at the end so the vertex is FVF + stuff at end
if ( vertexFormat & VERTEX_TANGENT_S ) { // UNDONE: use normal compression here (use mem_dumpvballocs to see if this uses much memory)
desc.m_pTangentS = reinterpret_cast<float*>(pBuffer + offset); offset += GetVertexElementSize( VERTEX_ELEMENT_TANGENT_S, compression ); pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_TangentS; } else { desc.m_pTangentS = dummyData; desc.m_VertexSize_TangentS = 0; }
if ( vertexFormat & VERTEX_TANGENT_T ) { // UNDONE: use normal compression here (use mem_dumpvballocs to see if this uses much memory)
desc.m_pTangentT = reinterpret_cast<float*>(pBuffer + offset); offset += GetVertexElementSize( VERTEX_ELEMENT_TANGENT_T, compression ); pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_TangentT; } else { desc.m_pTangentT = dummyData; desc.m_VertexSize_TangentT = 0; }
// User data..
int userDataSize = UserDataSize( vertexFormat ); if ( userDataSize > 0 ) { desc.m_pUserData = reinterpret_cast<float*>(pBuffer + offset); VertexElement_t userDataElement = (VertexElement_t)( VERTEX_ELEMENT_USERDATA1 + ( userDataSize - 1 ) ); // See PackNormal_[SHORT2|UBYTE4|HEND3N] in mathlib.h for the compression algorithm
offset += GetVertexElementSize( userDataElement, compression );
pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_UserData; } else { desc.m_pUserData = dummyData; desc.m_VertexSize_UserData = 0; }
// We always use vertex sizes which are half-cache aligned (16 bytes)
// x360 compressed vertexes are not compatible with forced alignments
bool bCacheAlign = ( vertexFormat & VERTEX_FORMAT_USE_EXACT_FORMAT ) == 0; if ( bCacheAlign && ( offset > 16 ) && IsPC() ) { offset = (offset + 0xF) & (~0xF); } desc.m_ActualVertexSize = offset;
// Now set the m_VertexSize for all the members that were actually valid.
Assert( nVertexSizesToSet < sizeof(pVertexSizesToSet)/sizeof(pVertexSizesToSet[0]) ); for ( int iElement=0; iElement < nVertexSizesToSet; iElement++ ) { *pVertexSizesToSet[iElement] = offset; } }
#endif // MESHBASE_H
|