#ifndef IMESH_H #define IMESH_H #ifdef _WIN32 #pragma once #endif #include "interface.h" #include "imaterial.h" #include #include #include "dbg.h" #include "meshutils.h" #include "imaterialsystem.h" #ifdef OSX #endif class IMaterial; class CMeshBuilder; class IMaterialVar; typedef uint64 VertexFormat_t; struct ShaderStencilState_t; #ifdef _DEBUG #endif enum { VERTEX_MAX_TEXTURE_COORDINATES = 8, BONE_MATRIX_INDEX_INVALID = 255 }; enum { INDEX_BUFFER_SIZE = 32768, DYNAMIC_VERTEX_BUFFER_MEMORY = (1024 + 512) * 1024, DYNAMIC_VERTEX_BUFFER_MEMORY_SMALL = 384 * 1024, }; enum WriteCombineOrdering_t { MB_FIELD_NONE = -1, MB_FIELD_POSITION = 0, MB_FIELD_BONE_WEIGHTS, MB_FIELD_BONE_INDEX, MB_FIELD_NORMAL, MB_FIELD_COLOR, MB_FIELD_SPECULAR, MB_FIELD_TEXCOORD_FIRST, MB_FIELD_TEXCOORD_LAST = MB_FIELD_TEXCOORD_FIRST + VERTEX_MAX_TEXTURE_COORDINATES - 1, MB_FIELD_TANGENT_S, MB_FIELD_TANGENT_T, MB_FIELD_USERDATA, }; #define MB_FIELD_TEXCOORD( nStage ) ( MB_FIELD_TEXCOORD_FIRST + ( nStage ) ) struct VertexDesc_t { int m_VertexSize_Position; int m_VertexSize_BoneWeight; int m_VertexSize_BoneMatrixIndex; int m_VertexSize_Normal; int m_VertexSize_Color; int m_VertexSize_Specular; int m_VertexSize_TexCoord[VERTEX_MAX_TEXTURE_COORDINATES]; int m_VertexSize_TangentS; int m_VertexSize_TangentT; int m_VertexSize_Wrinkle; int m_VertexSize_UserData; int m_ActualVertexSize; VertexCompressionType_t m_CompressionType; int m_NumBoneWeights; float* m_pPosition; float* m_pBoneWeight; #ifndef NEW_SKINNING unsigned char* m_pBoneMatrixIndex; #else float* m_pBoneMatrixIndex; #endif float* m_pNormal; unsigned char* m_pColor; unsigned char* m_pSpecular; float* m_pTexCoord[VERTEX_MAX_TEXTURE_COORDINATES]; float* m_pTangentS; float* m_pTangentT; float* m_pWrinkle; float* m_pUserData; int m_nFirstVertex; unsigned int m_nOffset; #ifdef DEBUG_WRITE_COMBINE int m_nLastWrittenField; unsigned char* m_pLastWrittenAddress; #endif }; struct IndexDesc_t { unsigned short* m_pIndices; unsigned int m_nOffset; unsigned int m_nFirstIndex; unsigned int m_nIndexSize; }; struct MeshDesc_t : public VertexDesc_t, public IndexDesc_t { }; struct ModelVertexDX8_t { Vector m_vecPosition; Vector m_vecNormal; Vector2D m_vecTexCoord; Vector4D m_vecUserData; }; struct QuadTessVertex_t { Vector4D m_vTangent; Vector4D m_vUV01; Vector4D m_vUV23; }; struct MeshBoneRemap_t { DECLARE_BYTESWAP_DATADESC(); int m_nActualBoneIndex; int m_nSrcBoneIndex; }; struct MeshInstanceData_t { int m_nIndexOffset; int m_nIndexCount; int m_nBoneCount; MeshBoneRemap_t* m_pBoneRemap; matrix3x4_t* m_pPoseToWorld; const ITexture* m_pEnvCubemap; MaterialLightingState_t* m_pLightingState; MaterialPrimitiveType_t m_nPrimType; const IVertexBuffer* m_pVertexBuffer; int m_nVertexOffsetInBytes; const IIndexBuffer* m_pIndexBuffer; const IVertexBuffer* m_pColorBuffer; int m_nColorVertexOffsetInBytes; ShaderStencilState_t* m_pStencilState; Vector4D m_DiffuseModulation; }; struct MeshBuffersAllocationSettings_t { uint32 m_uiIbUsageFlags; }; inline float* OffsetFloatPointer(float* pBufferPointer, int nVertexCount, int vertexSize) { return reinterpret_cast( reinterpret_cast(pBufferPointer) + nVertexCount * vertexSize); } inline const float* OffsetFloatPointer(const float* pBufferPointer, int nVertexCount, int vertexSize) { return reinterpret_cast( reinterpret_cast(pBufferPointer) + nVertexCount * vertexSize); } inline void IncrementFloatPointer(float*& pBufferPointer, int vertexSize) { pBufferPointer = reinterpret_cast(reinterpret_cast(pBufferPointer) + vertexSize); } class CPrimList { public: CPrimList(); CPrimList(int nFirstIndex, int nIndexCount); int m_FirstIndex; int m_NumIndices; }; inline CPrimList::CPrimList() { } inline CPrimList::CPrimList(int nFirstIndex, int nIndexCount) { m_FirstIndex = nFirstIndex; m_NumIndices = nIndexCount; } abstract_class IVertexBuffer { public: virtual int VertexCount() const = 0; virtual VertexFormat_t GetVertexFormat() const = 0; virtual bool IsDynamic() const = 0; virtual void BeginCastBuffer(VertexFormat_t format) = 0; virtual void EndCastBuffer() = 0; virtual int GetRoomRemaining() const = 0; virtual bool Lock(int nVertexCount, bool bAppend, VertexDesc_t& desc) = 0; virtual void Unlock(int nVertexCount, VertexDesc_t& desc) = 0; virtual void Spew(int nVertexCount, const VertexDesc_t& desc) = 0; virtual void ValidateData(int nVertexCount, const VertexDesc_t& desc) = 0; }; abstract_class IIndexBuffer { public: virtual int IndexCount() const = 0; virtual MaterialIndexFormat_t IndexFormat() const = 0; virtual bool IsDynamic() const = 0; virtual void BeginCastBuffer(MaterialIndexFormat_t format) = 0; virtual void EndCastBuffer() = 0; virtual int GetRoomRemaining() const = 0; virtual bool Lock(int nMaxIndexCount, bool bAppend, IndexDesc_t& desc) = 0; virtual void Unlock(int nWrittenIndexCount, IndexDesc_t& desc) = 0; virtual void ModifyBegin(bool bReadOnly, int nFirstIndex, int nIndexCount, IndexDesc_t& desc) = 0; virtual void ModifyEnd(IndexDesc_t& desc) = 0; virtual void Spew(int nIndexCount, const IndexDesc_t& desc) = 0; virtual void ValidateData(int nIndexCount, const IndexDesc_t& desc) = 0; virtual IMesh* GetMesh() = 0; }; abstract_class ICachedPerFrameMeshData { public: virtual void Free() = 0; }; abstract_class IMesh : public IVertexBuffer, public IIndexBuffer { public: virtual void SetPrimitiveType(MaterialPrimitiveType_t type) = 0; virtual void Draw(int firstIndex = -1, int numIndices = 0) = 0; virtual void SetColorMesh(IMesh* pColorMesh, int nVertexOffset) = 0; virtual void Draw(CPrimList* pLists, int nLists) = 0; virtual void CopyToMeshBuilder( int iStartVert, int nVerts, int iStartIndex, int nIndices, int indexOffset, CMeshBuilder& builder) = 0; virtual void Spew(int numVerts, int numIndices, const MeshDesc_t& desc) = 0; virtual void ValidateData(int numVerts, int numIndices, const MeshDesc_t& desc) = 0; virtual void LockMesh(int numVerts, int numIndices, MeshDesc_t& desc, MeshBuffersAllocationSettings_t* pSettings) = 0; virtual void ModifyBegin(int firstVertex, int numVerts, int firstIndex, int numIndices, MeshDesc_t& desc) = 0; virtual void ModifyEnd(MeshDesc_t& desc) = 0; virtual void UnlockMesh(int numVerts, int numIndices, MeshDesc_t& desc) = 0; virtual void ModifyBeginEx(bool bReadOnly, int firstVertex, int numVerts, int firstIndex, int numIndices, MeshDesc_t& desc) = 0; virtual void SetFlexMesh(IMesh* pMesh, int nVertexOffset) = 0; virtual void DisableFlexMesh() = 0; virtual void MarkAsDrawn() = 0; virtual void DrawModulated(const Vector4D& vecDiffuseModulation, int firstIndex = -1, int numIndices = 0) = 0; virtual unsigned int ComputeMemoryUsed() = 0; virtual void* AccessRawHardwareDataStream(uint8 nRawStreamIndex, uint32 numBytes, uint32 uiFlags, void* pvContext) = 0; virtual ICachedPerFrameMeshData* GetCachedPerFrameMeshData() = 0; virtual void ReconstructFromCachedPerFrameMeshData(ICachedPerFrameMeshData* pData) = 0; }; #include "meshreader.h" #define INVALID_BUFFER_OFFSET 0xFFFFFFFFUL #define VTX_HAVEPOS 1 #define VTX_HAVENORMAL 2 #define VTX_HAVECOLOR 4 #define VTX_HAVEALL ( VTX_HAVEPOS | VTX_HAVENORMAL | VTX_HAVECOLOR ) class CVertexBuilder : private VertexDesc_t { public: CVertexBuilder(); CVertexBuilder(IVertexBuffer* pVertexBuffer, VertexFormat_t fmt = 0); ~CVertexBuilder(); bool Lock(int nMaxIndexCount, bool bAppend = false); void Unlock(); void SpewData(); int GetRoomRemaining() const; void Bind(IMatRenderContext* pContext, int nStreamID, VertexFormat_t usage = 0); int Offset() const; void SetCompressionType(VertexCompressionType_t compressionType); void ValidateCompressionType(); void Begin(IVertexBuffer* pVertexBuffer, int nVertexCount, int* nFirstVertex); void Begin(IVertexBuffer* pVertexBuffer, int nVertexCount); void End(bool bSpewData = false); void BeginModify(IVertexBuffer* pVertexBuffer, int nFirstVertex = 0, int nVertexCount = -1); void EndModify(bool bSpewData = false); int VertexCount() const; int TotalVertexCount() const; void Reset(); int VertexSize() { return m_ActualVertexSize; } int TextureCoordinateSize(int nTexCoordNumber) { return m_VertexSize_TexCoord[nTexCoordNumber]; } void* BaseVertexData(); void SelectVertex(int idx); void AdvanceVertex(void); template void AdvanceVertexF(void); void AdvanceVertices(int nVerts); int GetCurrentVertex() const; int GetFirstVertex() const; const float* Position() const; const float* Normal() const; unsigned int Color() const; unsigned char* Specular() const; const float* TexCoord(int stage) const; const float* TangentS() const; const float* TangentT() const; const float* BoneWeight() const; float Wrinkle() const; int NumBoneWeights() const; #ifndef NEW_SKINNING unsigned char* BoneMatrix() const; #else float* BoneMatrix() const; #endif void Position3f(float x, float y, float z); void Position3fv(const float* v); void Normal3f(float nx, float ny, float nz); void Normal3fv(const float* n); void NormalDelta3fv(const float* n); void NormalDelta3f(float nx, float ny, float nz); template void CompressedNormal3f(float nx, float ny, float nz); template void CompressedNormal3fv(const float* n); void Color3f(float r, float g, float b); void Color3fv(const float* rgb); void Color4f(float r, float g, float b, float a); void Color4fv(const float* rgba); void Color3ub(unsigned char r, unsigned char g, unsigned char b); void Color3ubv(unsigned char const* rgb); void Color4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a); void Color4ubv(unsigned char const* rgba); void Color4Packed(int packedColor); int PackColor4(unsigned char r, unsigned char g, unsigned char b, unsigned char a); void Specular3f(float r, float g, float b); void Specular3fv(const float* rgb); void Specular4f(float r, float g, float b, float a); void Specular4fv(const float* rgba); void Specular3ub(unsigned char r, unsigned char g, unsigned char b); void Specular3ubv(unsigned char const* c); void Specular4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a); void Specular4ubv(unsigned char const* c); void TexCoord1f(int stage, float s); void TexCoord2f(int stage, float s, float t); void TexCoord2fv(int stage, const float* st); void TexCoord3f(int stage, float s, float t, float u); void TexCoord3fv(int stage, const float* stu); void TexCoord4f(int stage, float s, float t, float u, float w); void TexCoord4fv(int stage, const float* stuv); void TexCoordSubRect2f(int stage, float s, float t, float offsetS, float offsetT, float scaleS, float scaleT); void TexCoordSubRect2fv(int stage, const float* st, const float* offset, const float* scale); void TangentS3f(float sx, float sy, float sz); void TangentS3fv(const float* s); void TangentT3f(float tx, float ty, float tz); void TangentT3fv(const float* t); void Wrinkle1f(float flWrinkle); void BoneWeight(int idx, float weight); void BoneWeights2(float weight1, float weight2); template void CompressedBoneWeight3fv(const float* pWeights); void BoneMatrix(int idx, int matrixIndex); void BoneMatrices4(int matrixIdx0, int matrixIdx1, int matrixIdx2, int matrixIdx3); void UserData(const float* pData); template void CompressedUserData(const float* pData); void FastVertex(const ModelVertexDX8_t& vertex); void FastVertexSSE(const ModelVertexDX8_t& vertex); void FastQuadVertexSSE(const QuadTessVertex_t& vertex); void FastAdvanceNVertices(int n); #if defined( _X360 ) void VertexDX8ToX360(const ModelVertexDX8_t& vertex); #endif void AttachBegin(IMesh* pMesh, int nMaxVertexCount, const MeshDesc_t& desc); void AttachEnd(); void AttachBeginModify(IMesh* pMesh, int nFirstVertex, int nVertexCount, const MeshDesc_t& desc); void AttachEndModify(); private: IVertexBuffer* m_pVertexBuffer; bool m_bModify; int m_nMaxVertexCount; int m_nVertexCount; mutable int m_nCurrentVertex; mutable float* m_pCurrPosition; mutable float* m_pCurrNormal; mutable unsigned char* m_pCurrColor; mutable float* m_pCurrTexCoord[VERTEX_MAX_TEXTURE_COORDINATES]; int m_nTotalVertexCount; unsigned int m_nBufferOffset; unsigned int m_nBufferFirstVertex; #if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) bool m_bWrittenNormal : 1; bool m_bWrittenUserData : 1; #endif friend class CMeshBuilder; }; inline CVertexBuilder::CVertexBuilder() { m_pVertexBuffer = NULL; m_nBufferOffset = INVALID_BUFFER_OFFSET; m_nBufferFirstVertex = 0; m_nVertexCount = 0; m_nCurrentVertex = 0; m_nMaxVertexCount = 0; m_nTotalVertexCount = 0; m_CompressionType = VERTEX_COMPRESSION_INVALID; #ifdef _DEBUG m_pCurrPosition = NULL; m_pCurrNormal = NULL; m_pCurrColor = NULL; memset(m_pCurrTexCoord, 0, sizeof(m_pCurrTexCoord)); m_bModify = false; #endif } inline CVertexBuilder::CVertexBuilder(IVertexBuffer* pVertexBuffer, VertexFormat_t fmt) { m_pVertexBuffer = pVertexBuffer; m_nBufferOffset = INVALID_BUFFER_OFFSET; m_nBufferFirstVertex = 0; m_nVertexCount = 0; m_nCurrentVertex = 0; m_nMaxVertexCount = 0; m_nTotalVertexCount = 0; m_CompressionType = VERTEX_COMPRESSION_INVALID; if (m_pVertexBuffer->IsDynamic()) { m_pVertexBuffer->BeginCastBuffer(fmt); } else { Assert(m_pVertexBuffer->GetVertexFormat() == fmt); } #ifdef _DEBUG m_pCurrPosition = NULL; m_pCurrNormal = NULL; m_pCurrColor = NULL; memset(m_pCurrTexCoord, 0, sizeof(m_pCurrTexCoord)); m_bModify = false; #endif } inline CVertexBuilder::~CVertexBuilder() { if (m_pVertexBuffer && m_pVertexBuffer->IsDynamic()) { m_pVertexBuffer->EndCastBuffer(); } } inline bool CVertexBuilder::Lock(int nMaxVertexCount, bool bAppend) { Assert(m_pVertexBuffer); m_bModify = false; m_nMaxVertexCount = nMaxVertexCount; bool bFirstLock = (m_nBufferOffset == INVALID_BUFFER_OFFSET); if (bFirstLock) { bAppend = false; } if (!bAppend) { m_nTotalVertexCount = 0; } if (!m_pVertexBuffer->Lock(m_nMaxVertexCount, bAppend, *this)) { m_nMaxVertexCount = 0; return false; } Reset(); if (bFirstLock) { m_nBufferOffset = m_nOffset; m_nBufferFirstVertex = m_nFirstVertex; } return true; } inline void CVertexBuilder::Unlock() { Assert(!m_bModify && m_pVertexBuffer); #ifdef _DEBUG m_pVertexBuffer->ValidateData(m_nVertexCount, *this); #endif m_pVertexBuffer->Unlock(m_nVertexCount, *this); m_nTotalVertexCount += m_nVertexCount; m_nMaxVertexCount = 0; #ifdef _DEBUG m_pCurrPosition = NULL; m_pCurrNormal = NULL; m_pCurrColor = NULL; memset(m_pCurrTexCoord, 0, sizeof(m_pCurrTexCoord)); memset(static_cast(this), 0, sizeof(VertexDesc_t)); #endif } inline void CVertexBuilder::SpewData() { m_pVertexBuffer->Spew(m_nVertexCount, *this); } inline void CVertexBuilder::Bind(IMatRenderContext* pContext, int nStreamID, VertexFormat_t usage) { if (m_pVertexBuffer && (m_nBufferOffset != INVALID_BUFFER_OFFSET)) { pContext->BindVertexBuffer(nStreamID, m_pVertexBuffer, m_nBufferOffset, m_nFirstVertex, m_nTotalVertexCount, usage ? usage : m_pVertexBuffer->GetVertexFormat()); } else { pContext->BindVertexBuffer(nStreamID, NULL, 0, 0, 0, 0); } } inline int CVertexBuilder::Offset() const { return m_nBufferOffset; } inline int CVertexBuilder::GetFirstVertex() const { return m_nBufferFirstVertex; } inline void CVertexBuilder::SetCompressionType(VertexCompressionType_t compressionType) { m_CompressionType = compressionType; } inline void CVertexBuilder::ValidateCompressionType() { #ifdef _DEBUG VertexCompressionType_t vbCompressionType = CompressionType(m_pVertexBuffer->GetVertexFormat()); if (vbCompressionType != VERTEX_COMPRESSION_NONE) { Assert(m_CompressionType == vbCompressionType); if (m_CompressionType != vbCompressionType) { Warning("ERROR: CVertexBuilder::SetCompressionType() must be called to specify the same vertex compression type (%s) as the vertex buffer being modified." "Junk vertices will be rendered, or there will be a crash in CVertexBuilder!\n", vbCompressionType == VERTEX_COMPRESSION_ON ? "VERTEX_COMPRESSION_ON" : "VERTEX_COMPRESSION_NONE"); } Assert(!m_pVertexBuffer->IsDynamic()); } #endif } inline void CVertexBuilder::Begin(IVertexBuffer* pVertexBuffer, int nVertexCount) { Assert(pVertexBuffer && (!m_pVertexBuffer)); m_pVertexBuffer = pVertexBuffer; m_bModify = false; m_nMaxVertexCount = nVertexCount; m_nVertexCount = 0; ValidateCompressionType(); m_pVertexBuffer->Lock(m_nMaxVertexCount, false, *this); Reset(); } inline void CVertexBuilder::End(bool bSpewData) { Assert(!m_bModify); if (bSpewData) { m_pVertexBuffer->Spew(m_nVertexCount, *this); } #ifdef _DEBUG m_pVertexBuffer->ValidateData(m_nVertexCount, *this); #endif m_pVertexBuffer->Unlock(m_nVertexCount, *this); m_pVertexBuffer = 0; m_nMaxVertexCount = 0; m_CompressionType = VERTEX_COMPRESSION_INVALID; #ifdef _DEBUG m_pCurrPosition = NULL; m_pCurrNormal = NULL; m_pCurrColor = NULL; memset(m_pCurrTexCoord, 0, sizeof(m_pCurrTexCoord)); memset(static_cast(this), 0, sizeof(VertexDesc_t)); #endif } inline void CVertexBuilder::AttachBegin(IMesh* pMesh, int nMaxVertexCount, const MeshDesc_t& desc) { m_pVertexBuffer = pMesh; memcpy(static_cast(this), static_cast(&desc), sizeof(VertexDesc_t)); m_nMaxVertexCount = nMaxVertexCount; m_NumBoneWeights = m_NumBoneWeights == 0 ? 0 : 2; m_nVertexCount = 0; m_bModify = false; ValidateCompressionType(); if (m_nBufferOffset == INVALID_BUFFER_OFFSET) { m_nTotalVertexCount = 0; m_nBufferOffset = static_cast(&desc)->m_nOffset; m_nBufferFirstVertex = desc.m_nFirstVertex; } } inline void CVertexBuilder::AttachEnd() { Assert(!m_bModify); m_nMaxVertexCount = 0; m_pVertexBuffer = NULL; m_CompressionType = VERTEX_COMPRESSION_INVALID; #ifdef _DEBUG m_pCurrPosition = NULL; m_pCurrNormal = NULL; m_pCurrColor = NULL; memset(m_pCurrTexCoord, 0, sizeof(m_pCurrTexCoord)); memset(static_cast(this), 0, sizeof(VertexDesc_t)); #endif } inline void CVertexBuilder::AttachBeginModify(IMesh* pMesh, int nFirstVertex, int nVertexCount, const MeshDesc_t& desc) { Assert(pMesh && (!m_pVertexBuffer)); m_pVertexBuffer = pMesh; memcpy(static_cast(this), static_cast(&desc), sizeof(VertexDesc_t)); m_nMaxVertexCount = m_nVertexCount = nVertexCount; m_NumBoneWeights = m_NumBoneWeights == 0 ? 0 : 2; m_bModify = true; ValidateCompressionType(); } inline void CVertexBuilder::AttachEndModify() { Assert(m_pVertexBuffer); Assert(m_bModify); m_pVertexBuffer = 0; m_nMaxVertexCount = 0; m_CompressionType = VERTEX_COMPRESSION_INVALID; #ifdef _DEBUG m_pCurrPosition = NULL; m_pCurrNormal = NULL; m_pCurrColor = NULL; memset(m_pCurrTexCoord, 0, sizeof(m_pCurrTexCoord)); memset(static_cast(this), 0, sizeof(VertexDesc_t)); #endif } inline unsigned char* FindMinAddress(void* pAddress1, void* pAddress2, int nAddress2Size) { if (nAddress2Size == 0) return (unsigned char*)pAddress1; if (!pAddress1) return (unsigned char*)pAddress2; return (pAddress1 < pAddress2) ? (unsigned char*)pAddress1 : (unsigned char*)pAddress2; } inline void CVertexBuilder::Reset() { m_nCurrentVertex = 0; m_pCurrPosition = m_pPosition; m_pCurrNormal = m_pNormal; for (size_t i = 0; i < NELEMS(m_pCurrTexCoord); i++) { m_pCurrTexCoord[i] = m_pTexCoord[i]; } m_pCurrColor = m_pColor; #if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) m_bWrittenNormal = false; m_bWrittenUserData = false; #endif #ifdef DEBUG_WRITE_COMBINE m_nLastWrittenField = MB_FIELD_NONE; m_pLastWrittenAddress = NULL; m_pLastWrittenAddress = FindMinAddress(m_pLastWrittenAddress, m_pPosition, m_VertexSize_Position); m_pLastWrittenAddress = FindMinAddress(m_pLastWrittenAddress, m_pBoneWeight, m_VertexSize_BoneWeight); m_pLastWrittenAddress = FindMinAddress(m_pLastWrittenAddress, m_pBoneMatrixIndex, m_VertexSize_BoneMatrixIndex); m_pLastWrittenAddress = FindMinAddress(m_pLastWrittenAddress, m_pNormal, m_VertexSize_Normal); m_pLastWrittenAddress = FindMinAddress(m_pLastWrittenAddress, m_pColor, m_VertexSize_Color); m_pLastWrittenAddress = FindMinAddress(m_pLastWrittenAddress, m_pSpecular, m_VertexSize_Specular); for (int i = 0; i < VERTEX_MAX_TEXTURE_COORDINATES; ++i) { m_pLastWrittenAddress = FindMinAddress(m_pLastWrittenAddress, m_pTexCoord[i], m_VertexSize_TexCoord[i]); } m_pLastWrittenAddress = FindMinAddress(m_pLastWrittenAddress, m_pTangentS, m_VertexSize_TangentS); m_pLastWrittenAddress = FindMinAddress(m_pLastWrittenAddress, m_pTangentT, m_VertexSize_TangentT); m_pLastWrittenAddress = FindMinAddress(m_pLastWrittenAddress, m_pUserData, m_VertexSize_UserData); #endif } inline int CVertexBuilder::VertexCount() const { return m_nVertexCount; } inline int CVertexBuilder::TotalVertexCount() const { return m_nTotalVertexCount; } inline void* CVertexBuilder::BaseVertexData() { Assert(m_pPosition); return m_pPosition; } inline void CVertexBuilder::SelectVertex(int nIndex) { Assert((nIndex >= 0) && (nIndex < m_nMaxVertexCount)); m_nCurrentVertex = nIndex; m_pCurrPosition = OffsetFloatPointer(m_pPosition, m_nCurrentVertex, m_VertexSize_Position); m_pCurrNormal = OffsetFloatPointer(m_pNormal, m_nCurrentVertex, m_VertexSize_Normal); COMPILE_TIME_ASSERT(VERTEX_MAX_TEXTURE_COORDINATES == 8); m_pCurrTexCoord[0] = OffsetFloatPointer(m_pTexCoord[0], m_nCurrentVertex, m_VertexSize_TexCoord[0]); m_pCurrTexCoord[1] = OffsetFloatPointer(m_pTexCoord[1], m_nCurrentVertex, m_VertexSize_TexCoord[1]); m_pCurrTexCoord[2] = OffsetFloatPointer(m_pTexCoord[2], m_nCurrentVertex, m_VertexSize_TexCoord[2]); m_pCurrTexCoord[3] = OffsetFloatPointer(m_pTexCoord[3], m_nCurrentVertex, m_VertexSize_TexCoord[3]); m_pCurrTexCoord[4] = OffsetFloatPointer(m_pTexCoord[4], m_nCurrentVertex, m_VertexSize_TexCoord[4]); m_pCurrTexCoord[5] = OffsetFloatPointer(m_pTexCoord[5], m_nCurrentVertex, m_VertexSize_TexCoord[5]); m_pCurrTexCoord[6] = OffsetFloatPointer(m_pTexCoord[6], m_nCurrentVertex, m_VertexSize_TexCoord[6]); m_pCurrTexCoord[7] = OffsetFloatPointer(m_pTexCoord[7], m_nCurrentVertex, m_VertexSize_TexCoord[7]); m_pCurrColor = m_pColor + m_nCurrentVertex * m_VertexSize_Color; #if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) m_bWrittenNormal = false; m_bWrittenUserData = false; #endif } template FORCEINLINE void CVertexBuilder::AdvanceVertexF() { if (++m_nCurrentVertex > m_nVertexCount) { m_nVertexCount = m_nCurrentVertex; } if (nFlags & VTX_HAVEPOS) IncrementFloatPointer(m_pCurrPosition, m_VertexSize_Position); if (nFlags & VTX_HAVENORMAL) IncrementFloatPointer(m_pCurrNormal, m_VertexSize_Normal); if (nFlags & VTX_HAVECOLOR) m_pCurrColor += m_VertexSize_Color; COMPILE_TIME_ASSERT(VERTEX_MAX_TEXTURE_COORDINATES == 8); if (nNumTexCoords > 0) IncrementFloatPointer(m_pCurrTexCoord[0], m_VertexSize_TexCoord[0]); if (nNumTexCoords > 1) IncrementFloatPointer(m_pCurrTexCoord[1], m_VertexSize_TexCoord[1]); if (nNumTexCoords > 2) IncrementFloatPointer(m_pCurrTexCoord[2], m_VertexSize_TexCoord[2]); if (nNumTexCoords > 3) IncrementFloatPointer(m_pCurrTexCoord[3], m_VertexSize_TexCoord[3]); if (nNumTexCoords > 4) IncrementFloatPointer(m_pCurrTexCoord[4], m_VertexSize_TexCoord[4]); if (nNumTexCoords > 5) IncrementFloatPointer(m_pCurrTexCoord[5], m_VertexSize_TexCoord[5]); if (nNumTexCoords > 6) IncrementFloatPointer(m_pCurrTexCoord[6], m_VertexSize_TexCoord[6]); if (nNumTexCoords > 7) IncrementFloatPointer(m_pCurrTexCoord[7], m_VertexSize_TexCoord[7]); #if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) m_bWrittenNormal = false; m_bWrittenUserData = false; #endif } inline void CVertexBuilder::AdvanceVertex() { AdvanceVertexF(); } inline void CVertexBuilder::AdvanceVertices(int nVerts) { m_nCurrentVertex += nVerts; if (m_nCurrentVertex > m_nVertexCount) { m_nVertexCount = m_nCurrentVertex; } IncrementFloatPointer(m_pCurrPosition, m_VertexSize_Position * nVerts); IncrementFloatPointer(m_pCurrNormal, m_VertexSize_Normal * nVerts); COMPILE_TIME_ASSERT(VERTEX_MAX_TEXTURE_COORDINATES == 8); IncrementFloatPointer(m_pCurrTexCoord[0], m_VertexSize_TexCoord[0] * nVerts); IncrementFloatPointer(m_pCurrTexCoord[1], m_VertexSize_TexCoord[1] * nVerts); IncrementFloatPointer(m_pCurrTexCoord[2], m_VertexSize_TexCoord[2] * nVerts); IncrementFloatPointer(m_pCurrTexCoord[3], m_VertexSize_TexCoord[3] * nVerts); IncrementFloatPointer(m_pCurrTexCoord[4], m_VertexSize_TexCoord[4] * nVerts); IncrementFloatPointer(m_pCurrTexCoord[5], m_VertexSize_TexCoord[5] * nVerts); IncrementFloatPointer(m_pCurrTexCoord[6], m_VertexSize_TexCoord[6] * nVerts); IncrementFloatPointer(m_pCurrTexCoord[7], m_VertexSize_TexCoord[7] * nVerts); m_pCurrColor += m_VertexSize_Color * nVerts; #if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) m_bWrittenNormal = false; m_bWrittenUserData = false; #endif } inline void CVertexBuilder::FastAdvanceNVertices(int n) { m_nCurrentVertex += n; m_nVertexCount = m_nCurrentVertex; } inline void CVertexBuilder::FastVertex(const ModelVertexDX8_t& vertex) { Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); Assert(m_nCurrentVertex < m_nMaxVertexCount); #if defined( _WIN32 ) && !defined( _X360 ) const void* pRead = &vertex; void* pCurrPos = m_pCurrPosition; __asm { mov esi, pRead mov edi, pCurrPos movq mm0, [esi + 0] movq mm1, [esi + 8] movq mm2, [esi + 16] movq mm3, [esi + 24] movq mm4, [esi + 32] movq mm5, [esi + 40] movntq[edi + 0], mm0 movntq[edi + 8], mm1 movntq[edi + 16], mm2 movntq[edi + 24], mm3 movntq[edi + 32], mm4 movntq[edi + 40], mm5 emms } #elif defined(GNUC) const void* pRead = &vertex; void* pCurrPos = m_pCurrPosition; __asm__ __volatile__( "movq (%0), %%mm0\n" "movq 8(%0), %%mm1\n" "movq 16(%0), %%mm2\n" "movq 24(%0), %%mm3\n" "movq 32(%0), %%mm4\n" "movq 40(%0), %%mm5\n" "movq 48(%0), %%mm6\n" "movq 56(%0), %%mm7\n" "movntq %%mm0, (%1)\n" "movntq %%mm1, 8(%1)\n" "movntq %%mm2, 16(%1)\n" "movntq %%mm3, 24(%1)\n" "movntq %%mm4, 32(%1)\n" "movntq %%mm5, 40(%1)\n" "movntq %%mm6, 48(%1)\n" "movntq %%mm7, 56(%1)\n" "emms\n" :: "r" (pRead), "r" (pCurrPos) : "memory"); #else Error("Implement CMeshBuilder::FastVertex(dx8)"); #endif IncrementFloatPointer(m_pCurrPosition, m_VertexSize_Position); #if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) m_bWrittenNormal = false; m_bWrittenUserData = false; #endif } inline void CVertexBuilder::FastVertexSSE(const ModelVertexDX8_t& vertex) { Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); Assert(m_nCurrentVertex < m_nMaxVertexCount); #if defined( _WIN32 ) && !defined( _X360 ) const void* pRead = &vertex; void* pCurrPos = m_pCurrPosition; __asm { mov esi, pRead mov edi, pCurrPos movaps xmm0, [esi + 0] movaps xmm1, [esi + 16] movaps xmm2, [esi + 32] movntps[edi + 0], xmm0 movntps[edi + 16], xmm1 movntps[edi + 32], xmm2 } #elif defined(GNUC) const void* pRead = &vertex; void* pCurrPos = m_pCurrPosition; __asm__ __volatile__( "movaps (%0), %%xmm0\n" "movaps 16(%0), %%xmm1\n" "movaps 32(%0), %%xmm2\n" "movaps 48(%0), %%xmm3\n" "movntps %%xmm0, (%1)\n" "movntps %%xmm1, 16(%1)\n" "movntps %%xmm2, 32(%1)\n" "movntps %%xmm3, 48(%1)\n" :: "r" (pRead), "r" (pCurrPos) : "memory"); #else Error("Implement CMeshBuilder::FastVertexSSE((dx8)"); #endif IncrementFloatPointer(m_pCurrPosition, m_VertexSize_Position); #if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) m_bWrittenNormal = false; m_bWrittenUserData = false; #endif } inline void CVertexBuilder::FastQuadVertexSSE(const QuadTessVertex_t& vertex) { Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); Assert(m_nCurrentVertex < m_nMaxVertexCount); #if defined( _WIN32 ) && !defined( _X360 ) const void* pRead = &vertex; void* pCurrPos = m_pCurrPosition; __asm { mov esi, pRead mov edi, pCurrPos movaps xmm0, [esi + 0] movaps xmm1, [esi + 16] movaps xmm2, [esi + 32] movntps[edi + 0], xmm0 movntps[edi + 16], xmm1 movntps[edi + 32], xmm2 } #endif IncrementFloatPointer(m_pCurrPosition, m_VertexSize_Position); #if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) m_bWrittenNormal = false; m_bWrittenUserData = false; #endif } inline int CVertexBuilder::GetCurrentVertex() const { return m_nCurrentVertex; } #if defined( _X360 ) inline void CVertexBuilder::VertexDX8ToX360(const ModelVertexDX8_t& vertex) { Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); Assert(m_nCurrentVertex < m_nMaxVertexCount); unsigned char* pDst = (unsigned char*)m_pCurrPosition; Assert(m_VertexSize_Position > 0); Assert(GetVertexElementSize(VERTEX_ELEMENT_POSITION, VERTEX_COMPRESSION_NONE) == sizeof(vertex.m_vecPosition)); memcpy(pDst, vertex.m_vecPosition.Base(), sizeof(vertex.m_vecPosition)); pDst += sizeof(vertex.m_vecPosition); if (m_VertexSize_Normal) { Assert(GetVertexElementSize(VERTEX_ELEMENT_NORMAL, VERTEX_COMPRESSION_NONE) == sizeof(vertex.m_vecNormal)); memcpy(pDst, vertex.m_vecNormal.Base(), sizeof(vertex.m_vecNormal)); pDst += sizeof(vertex.m_vecNormal); } if (m_VertexSize_TexCoord[0]) { Assert(GetVertexElementSize(VERTEX_ELEMENT_TEXCOORD2D_0, VERTEX_COMPRESSION_NONE) == sizeof(vertex.m_vecTexCoord)); memcpy(pDst, vertex.m_vecTexCoord.Base(), sizeof(vertex.m_vecTexCoord)); pDst += sizeof(vertex.m_vecTexCoord); } if (m_VertexSize_UserData) { Assert(GetVertexElementSize(VERTEX_ELEMENT_USERDATA4, VERTEX_COMPRESSION_NONE) == sizeof(vertex.m_vecUserData)); memcpy(pDst, vertex.m_vecUserData.Base(), sizeof(vertex.m_vecUserData)); pDst += sizeof(vertex.m_vecUserData); } Assert(pDst - (unsigned char*)m_pCurrPosition == m_VertexSize_Position); IncrementFloatPointer(m_pCurrPosition, m_VertexSize_Position); #if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) m_bWrittenNormal = false; m_bWrittenUserData = false; #endif } #endif inline const float* CVertexBuilder::Position() const { Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); Assert(m_nCurrentVertex < m_nMaxVertexCount); return m_pCurrPosition; } inline const float* CVertexBuilder::Normal() const { Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); Assert(m_nCurrentVertex < m_nMaxVertexCount); return m_pCurrNormal; } inline unsigned int CVertexBuilder::Color() const { Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); Assert(m_nCurrentVertex < m_nMaxVertexCount); unsigned int color; if (IsPC() || !IsX360()) { color = (m_pCurrColor[3] << 24) | (m_pCurrColor[0] << 16) | (m_pCurrColor[1] << 8) | (m_pCurrColor[2]); } else { color = (m_pCurrColor[1] << 24) | (m_pCurrColor[2] << 16) | (m_pCurrColor[3] << 8) | (m_pCurrColor[0]); } return color; } inline unsigned char* CVertexBuilder::Specular() const { Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); Assert(m_nCurrentVertex < m_nMaxVertexCount); return m_pSpecular + m_nCurrentVertex * m_VertexSize_Specular; } inline const float* CVertexBuilder::TexCoord(int stage) const { Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); Assert(m_nCurrentVertex < m_nMaxVertexCount); return m_pCurrTexCoord[stage]; } inline const float* CVertexBuilder::TangentS() const { Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); Assert(m_nCurrentVertex < m_nMaxVertexCount); return OffsetFloatPointer(m_pTangentS, m_nCurrentVertex, m_VertexSize_TangentS); } inline const float* CVertexBuilder::TangentT() const { Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); Assert(m_nCurrentVertex < m_nMaxVertexCount); return OffsetFloatPointer(m_pTangentT, m_nCurrentVertex, m_VertexSize_TangentT); } inline float CVertexBuilder::Wrinkle() const { Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); Assert(m_nCurrentVertex < m_nMaxVertexCount); return *OffsetFloatPointer(m_pWrinkle, m_nCurrentVertex, m_VertexSize_Wrinkle); } inline const float* CVertexBuilder::BoneWeight() const { Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); Assert(m_nCurrentVertex < m_nMaxVertexCount); return OffsetFloatPointer(m_pBoneWeight, m_nCurrentVertex, m_VertexSize_BoneWeight); } inline int CVertexBuilder::NumBoneWeights() const { return m_NumBoneWeights; } #ifndef NEW_SKINNING inline unsigned char* CVertexBuilder::BoneMatrix() const { Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); Assert(m_nCurrentVertex < m_nMaxVertexCount); return m_pBoneMatrixIndex + m_nCurrentVertex * m_VertexSize_BoneMatrixIndex; } #else inline float* CVertexBuilder::BoneMatrix() const { Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); Assert(m_nCurrentVertex < m_nMaxVertexCount); return m_pBoneMatrixIndex + m_nCurrentVertex * m_VertexSize_BoneMatrixIndex; } #endif inline void CVertexBuilder::Position3f(float x, float y, float z) { Assert(m_pPosition && m_pCurrPosition); Assert(IsFinite(x) && IsFinite(y) && IsFinite(z)); float* pDst = m_pCurrPosition; *pDst++ = x; *pDst++ = y; *pDst = z; } inline void CVertexBuilder::Position3fv(const float* v) { Assert(v); Assert(m_pPosition && m_pCurrPosition); float* pDst = m_pCurrPosition; *pDst++ = *v++; *pDst++ = *v++; *pDst = *v; } inline void CVertexBuilder::Normal3f(float nx, float ny, float nz) { Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); Assert(m_pNormal); Assert(IsFinite(nx) && IsFinite(ny) && IsFinite(nz)); Assert(nx >= -1.05f && nx <= 1.05f); Assert(ny >= -1.05f && ny <= 1.05f); Assert(nz >= -1.05f && nz <= 1.05f); float* pDst = m_pCurrNormal; *pDst++ = nx; *pDst++ = ny; *pDst = nz; } inline void CVertexBuilder::Normal3fv(const float* n) { Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); Assert(n); Assert(m_pNormal && m_pCurrNormal); Assert(IsFinite(n[0]) && IsFinite(n[1]) && IsFinite(n[2])); Assert(n[0] >= -1.05f && n[0] <= 1.05f); Assert(n[1] >= -1.05f && n[1] <= 1.05f); Assert(n[2] >= -1.05f && n[2] <= 1.05f); float* pDst = m_pCurrNormal; *pDst++ = *n++; *pDst++ = *n++; *pDst = *n; } inline void CVertexBuilder::NormalDelta3f(float nx, float ny, float nz) { Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); Assert(m_pNormal); Assert(IsFinite(nx) && IsFinite(ny) && IsFinite(nz)); float* pDst = m_pCurrNormal; *pDst++ = nx; *pDst++ = ny; *pDst = nz; } inline void CVertexBuilder::NormalDelta3fv(const float* n) { Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); Assert(n); Assert(m_pNormal && m_pCurrNormal); Assert(IsFinite(n[0]) && IsFinite(n[1]) && IsFinite(n[2])); float* pDst = m_pCurrNormal; *pDst++ = *n++; *pDst++ = *n++; *pDst = *n; } template inline void CVertexBuilder::CompressedNormal3f(float nx, float ny, float nz) { Assert(T == m_CompressionType); Assert(m_pNormal && m_pCurrNormal); Assert(IsFinite(nx) && IsFinite(ny) && IsFinite(nz)); Assert(nx >= -1.05f && nx <= 1.05f); Assert(ny >= -1.05f && ny <= 1.05f); Assert(nz >= -1.05f && nz <= 1.05f); if (T == VERTEX_COMPRESSION_ON) { #if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 ) PackNormal_SHORT2(nx, ny, nz, (unsigned int*)m_pCurrNormal); #else #ifdef _DEBUG Assert(m_bWrittenUserData == false); m_bWrittenNormal = true; #endif PackNormal_UBYTE4(nx, ny, nz, (unsigned int*)m_pCurrNormal); #endif } else { float* pDst = m_pCurrNormal; *pDst++ = nx; *pDst++ = ny; *pDst = nz; } } template inline void CVertexBuilder::CompressedNormal3fv(const float* n) { Assert(n); CompressedNormal3f(n[0], n[1], n[2]); } inline void CVertexBuilder::Color3f(float r, float g, float b) { Assert(m_pColor && m_pCurrColor); Assert(IsFinite(r) && IsFinite(g) && IsFinite(b)); Assert((r >= 0.0) && (g >= 0.0) && (b >= 0.0)); Assert((r <= 1.0) && (g <= 1.0) && (b <= 1.0)); int col = (FastFToC(b)) | (FastFToC(g) << 8) | (FastFToC(r) << 16) | 0xFF000000; *(int*)m_pCurrColor = col; } inline void CVertexBuilder::Color3fv(const float* rgb) { Assert(rgb); Assert(m_pColor && m_pCurrColor); Assert(IsFinite(rgb[0]) && IsFinite(rgb[1]) && IsFinite(rgb[2])); Assert((rgb[0] >= 0.0) && (rgb[1] >= 0.0) && (rgb[2] >= 0.0)); Assert((rgb[0] <= 1.0) && (rgb[1] <= 1.0) && (rgb[2] <= 1.0)); int col = (FastFToC(rgb[2])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[0]) << 16) | 0xFF000000; *(int*)m_pCurrColor = col; } inline void CVertexBuilder::Color4f(float r, float g, float b, float a) { Assert(m_pColor && m_pCurrColor); Assert(IsFinite(r) && IsFinite(g) && IsFinite(b) && IsFinite(a)); Assert((r >= 0.0) && (g >= 0.0) && (b >= 0.0) && (a >= 0.0)); Assert((r <= 1.0) && (g <= 1.0) && (b <= 1.0) && (a <= 1.0)); int col = (FastFToC(b)) | (FastFToC(g) << 8) | (FastFToC(r) << 16) | (FastFToC(a) << 24); *(int*)m_pCurrColor = col; } inline void CVertexBuilder::Color4fv(const float* rgba) { Assert(rgba); Assert(m_pColor && m_pCurrColor); Assert(IsFinite(rgba[0]) && IsFinite(rgba[1]) && IsFinite(rgba[2]) && IsFinite(rgba[3])); Assert((rgba[0] >= 0.0) && (rgba[1] >= 0.0) && (rgba[2] >= 0.0) && (rgba[3] >= 0.0)); Assert((rgba[0] <= 1.0) && (rgba[1] <= 1.0) && (rgba[2] <= 1.0) && (rgba[3] <= 1.0)); int col = (FastFToC(rgba[2])) | (FastFToC(rgba[1]) << 8) | (FastFToC(rgba[0]) << 16) | (FastFToC(rgba[3]) << 24); *(int*)m_pCurrColor = col; } inline void CVertexBuilder::Color3ub(unsigned char r, unsigned char g, unsigned char b) { Assert(m_pColor && m_pCurrColor); #ifdef OPENGL_SWAP_COLORS int col = r | (g << 8) | (b << 16) | 0xFF000000; #else int col = b | (g << 8) | (r << 16) | 0xFF000000; #endif * (int*)m_pCurrColor = col; } inline void CVertexBuilder::Color3ubv(unsigned char const* rgb) { Assert(rgb); Assert(m_pColor && m_pCurrColor); #ifdef OPENGL_SWAP_COLORS int col = rgb[0] | (rgb[1] << 8) | (rgb[2] << 16) | 0xFF000000; #else int col = rgb[2] | (rgb[1] << 8) | (rgb[0] << 16) | 0xFF000000; #endif * (int*)m_pCurrColor = col; } inline void CVertexBuilder::Color4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { Assert(m_pColor && m_pCurrColor); #ifdef OPENGL_SWAP_COLORS int col = r | (g << 8) | (b << 16) | (a << 24); #else int col = b | (g << 8) | (r << 16) | (a << 24); #endif * (int*)m_pCurrColor = col; } inline void CVertexBuilder::Color4ubv(unsigned char const* rgba) { Assert(rgba); Assert(m_pColor && m_pCurrColor); #ifdef OPENGL_SWAP_COLORS int col = rgba[0] | (rgba[1] << 8) | (rgba[2] << 16) | (rgba[3] << 24); #else int col = rgba[2] | (rgba[1] << 8) | (rgba[0] << 16) | (rgba[3] << 24); #endif * (int*)m_pCurrColor = col; } FORCEINLINE void CVertexBuilder::Color4Packed(int packedColor) { *(int*)m_pCurrColor = packedColor; } FORCEINLINE int CVertexBuilder::PackColor4(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { return b | (g << 8) | (r << 16) | (a << 24); } inline void CVertexBuilder::Specular3f(float r, float g, float b) { Assert(m_pSpecular); Assert(IsFinite(r) && IsFinite(g) && IsFinite(b)); Assert((r >= 0.0) && (g >= 0.0) && (b >= 0.0)); Assert((r <= 1.0) && (g <= 1.0) && (b <= 1.0)); unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; int col = (FastFToC(b)) | (FastFToC(g) << 8) | (FastFToC(r) << 16) | 0xFF000000; *(int*)pSpecular = col; } inline void CVertexBuilder::Specular3fv(const float* rgb) { Assert(rgb); Assert(m_pSpecular); Assert(IsFinite(rgb[0]) && IsFinite(rgb[1]) && IsFinite(rgb[2])); Assert((rgb[0] >= 0.0) && (rgb[1] >= 0.0) && (rgb[2] >= 0.0)); Assert((rgb[0] <= 1.0) && (rgb[1] <= 1.0) && (rgb[2] <= 1.0)); unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; int col = (FastFToC(rgb[2])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[0]) << 16) | 0xFF000000; *(int*)pSpecular = col; } inline void CVertexBuilder::Specular4f(float r, float g, float b, float a) { Assert(m_pSpecular); Assert(IsFinite(r) && IsFinite(g) && IsFinite(b) && IsFinite(a)); Assert((r >= 0.0) && (g >= 0.0) && (b >= 0.0) && (a >= 0.0)); Assert((r <= 1.0) && (g <= 1.0) && (b <= 1.0) && (a <= 1.0f)); unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; int col = (FastFToC(b)) | (FastFToC(g) << 8) | (FastFToC(r) << 16) | (FastFToC(a) << 24); *(int*)pSpecular = col; } inline void CVertexBuilder::Specular4fv(const float* rgb) { Assert(rgb); Assert(m_pSpecular); Assert(IsFinite(rgb[0]) && IsFinite(rgb[1]) && IsFinite(rgb[2]) && IsFinite(rgb[3])); Assert((rgb[0] >= 0.0) && (rgb[1] >= 0.0) && (rgb[2] >= 0.0) && (rgb[3] >= 0.0)); Assert((rgb[0] <= 1.0) && (rgb[1] <= 1.0) && (rgb[2] <= 1.0) && (rgb[3] <= 1.0)); unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; int col = (FastFToC(rgb[2])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[0]) << 16) | (FastFToC(rgb[3]) << 24); *(int*)pSpecular = col; } inline void CVertexBuilder::Specular3ub(unsigned char r, unsigned char g, unsigned char b) { Assert(m_pSpecular); unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; #ifdef OPENGL_SWAP_COLORS int col = r | (g << 8) | (b << 16) | 0xFF000000; #else int col = b | (g << 8) | (r << 16) | 0xFF000000; #endif * (int*)pSpecular = col; } inline void CVertexBuilder::Specular3ubv(unsigned char const* c) { Assert(m_pSpecular); unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; #ifdef OPENGL_SWAP_COLORS int col = c[0] | (c[1] << 8) | (c[2] << 16) | 0xFF000000; #else int col = c[2] | (c[1] << 8) | (c[0] << 16) | 0xFF000000; #endif * (int*)pSpecular = col; } inline void CVertexBuilder::Specular4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { Assert(m_pSpecular); unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; #ifdef OPENGL_SWAP_COLORS int col = r | (g << 8) | (b << 16) | (a << 24); #else int col = b | (g << 8) | (r << 16) | (a << 24); #endif * (int*)pSpecular = col; } inline void CVertexBuilder::Specular4ubv(unsigned char const* c) { Assert(m_pSpecular); unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; #ifdef OPENGL_SWAP_COLORS int col = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24); #else int col = c[2] | (c[1] << 8) | (c[0] << 16) | (c[3] << 24); #endif * (int*)pSpecular = col; } inline void CVertexBuilder::TexCoord1f(int nStage, float s) { Assert(m_pTexCoord[nStage] && m_pCurrTexCoord[nStage]); Assert(IsFinite(s)); float* pDst = m_pCurrTexCoord[nStage]; *pDst = s; } inline void CVertexBuilder::TexCoord2f(int nStage, float s, float t) { Assert(m_pTexCoord[nStage] && m_pCurrTexCoord[nStage]); Assert(IsFinite(s) && IsFinite(t)); float* pDst = m_pCurrTexCoord[nStage]; *pDst++ = s; *pDst = t; } inline void CVertexBuilder::TexCoord2fv(int nStage, const float* st) { Assert(st); Assert(m_pTexCoord[nStage] && m_pCurrTexCoord[nStage]); Assert(IsFinite(st[0]) && IsFinite(st[1])); float* pDst = m_pCurrTexCoord[nStage]; *pDst++ = *st++; *pDst = *st; } inline void CVertexBuilder::TexCoord3f(int stage, float s, float t, float u) { Assert(m_pTexCoord[stage] && m_pCurrTexCoord[stage]); Assert(IsFinite(s) && IsFinite(t) && IsFinite(u)); float* pDst = m_pCurrTexCoord[stage]; *pDst++ = s; *pDst++ = t; *pDst = u; } inline void CVertexBuilder::TexCoord3fv(int stage, const float* stu) { Assert(stu); Assert(m_pTexCoord[stage] && m_pCurrTexCoord[stage]); Assert(IsFinite(stu[0]) && IsFinite(stu[1]) && IsFinite(stu[2])); float* pDst = m_pCurrTexCoord[stage]; *pDst++ = *stu++; *pDst++ = *stu++; *pDst = *stu; } inline void CVertexBuilder::TexCoord4f(int stage, float s, float t, float u, float v) { Assert(m_pTexCoord[stage] && m_pCurrTexCoord[stage]); Assert(IsFinite(s) && IsFinite(t) && IsFinite(u)); float* pDst = m_pCurrTexCoord[stage]; *pDst++ = s; *pDst++ = t; *pDst++ = u; *pDst = v; } inline void CVertexBuilder::TexCoord4fv(int stage, const float* stuv) { Assert(stuv); Assert(m_pTexCoord[stage] && m_pCurrTexCoord[stage]); Assert(IsFinite(stuv[0]) && IsFinite(stuv[1]) && IsFinite(stuv[2])); float* pDst = m_pCurrTexCoord[stage]; *pDst++ = *stuv++; *pDst++ = *stuv++; *pDst++ = *stuv++; *pDst = *stuv; } inline void CVertexBuilder::TexCoordSubRect2f(int stage, float s, float t, float offsetS, float offsetT, float scaleS, float scaleT) { Assert(m_pTexCoord[stage] && m_pCurrTexCoord[stage]); Assert(IsFinite(s) && IsFinite(t)); float* pDst = m_pCurrTexCoord[stage]; *pDst++ = (s * scaleS) + offsetS; *pDst = (t * scaleT) + offsetT; } inline void CVertexBuilder::TexCoordSubRect2fv(int stage, const float* st, const float* offset, const float* scale) { Assert(st); Assert(m_pTexCoord[stage] && m_pCurrTexCoord[stage]); Assert(IsFinite(st[0]) && IsFinite(st[1])); float* pDst = m_pCurrTexCoord[stage]; *pDst++ = (*st++ * *scale++) + *offset++; *pDst = (*st * *scale) + *offset; } inline void CVertexBuilder::TangentS3f(float sx, float sy, float sz) { Assert(m_pTangentS); Assert(IsFinite(sx) && IsFinite(sy) && IsFinite(sz)); float* pTangentS = OffsetFloatPointer(m_pTangentS, m_nCurrentVertex, m_VertexSize_TangentS); *pTangentS++ = sx; *pTangentS++ = sy; *pTangentS = sz; } inline void CVertexBuilder::TangentS3fv(const float* s) { Assert(s); Assert(m_pTangentS); Assert(IsFinite(s[0]) && IsFinite(s[1]) && IsFinite(s[2])); float* pTangentS = OffsetFloatPointer(m_pTangentS, m_nCurrentVertex, m_VertexSize_TangentS); *pTangentS++ = *s++; *pTangentS++ = *s++; *pTangentS = *s; } inline void CVertexBuilder::TangentT3f(float tx, float ty, float tz) { Assert(m_pTangentT); Assert(IsFinite(tx) && IsFinite(ty) && IsFinite(tz)); float* pTangentT = OffsetFloatPointer(m_pTangentT, m_nCurrentVertex, m_VertexSize_TangentT); *pTangentT++ = tx; *pTangentT++ = ty; *pTangentT = tz; } inline void CVertexBuilder::TangentT3fv(const float* t) { Assert(t); Assert(m_pTangentT); Assert(IsFinite(t[0]) && IsFinite(t[1]) && IsFinite(t[2])); float* pTangentT = OffsetFloatPointer(m_pTangentT, m_nCurrentVertex, m_VertexSize_TangentT); *pTangentT++ = *t++; *pTangentT++ = *t++; *pTangentT = *t; } inline void CVertexBuilder::Wrinkle1f(float flWrinkle) { Assert(m_pWrinkle); Assert(IsFinite(flWrinkle)); float* pWrinkle = OffsetFloatPointer(m_pWrinkle, m_nCurrentVertex, m_VertexSize_Wrinkle); *pWrinkle = flWrinkle; } inline void CVertexBuilder::BoneWeight(int idx, float weight) { Assert(m_pBoneWeight); Assert(IsFinite(weight)); Assert(idx >= 0); Assert(m_NumBoneWeights == 2); if (idx < m_NumBoneWeights) { float* pBoneWeight = OffsetFloatPointer(m_pBoneWeight, m_nCurrentVertex, m_VertexSize_BoneWeight); pBoneWeight[idx] = weight; } } inline void CVertexBuilder::BoneWeights2(float weight1, float weight2) { Assert(m_pBoneWeight); Assert(IsFinite(weight1) && IsFinite(weight2)); AssertOnce(m_NumBoneWeights == 2); float* pBoneWeight = OffsetFloatPointer(m_pBoneWeight, m_nCurrentVertex, m_VertexSize_BoneWeight); pBoneWeight[0] = weight1; pBoneWeight[1] = weight2; } inline void CVertexBuilder::BoneMatrix(int idx, int matrixIdx) { Assert(m_pBoneMatrixIndex); Assert(idx >= 0); Assert(idx < 4); if (matrixIdx == BONE_MATRIX_INDEX_INVALID) { matrixIdx = 0; } Assert((matrixIdx >= 0) && (matrixIdx < 53)); #ifndef NEW_SKINNING unsigned char* pBoneMatrix = &m_pBoneMatrixIndex[m_nCurrentVertex * m_VertexSize_BoneMatrixIndex]; if (IsX360()) { idx = 3 - idx; } pBoneMatrix[idx] = (unsigned char)matrixIdx; #else float* pBoneMatrix = &m_pBoneMatrixIndex[m_nCurrentVertex * m_VertexSize_BoneMatrixIndex]; pBoneMatrix[idx] = matrixIdx; #endif } inline void CVertexBuilder::BoneMatrices4(int matrixIdx0, int matrixIdx1, int matrixIdx2, int matrixIdx3) { Assert(m_pBoneMatrixIndex); Assert(matrixIdx0 != BONE_MATRIX_INDEX_INVALID); Assert(matrixIdx1 != BONE_MATRIX_INDEX_INVALID); Assert(matrixIdx2 != BONE_MATRIX_INDEX_INVALID); Assert(matrixIdx3 != BONE_MATRIX_INDEX_INVALID); #ifndef NEW_SKINNING int nVal; if (IsX360()) { nVal = matrixIdx3 | (matrixIdx2 << 8) | (matrixIdx1 << 16) | (matrixIdx0 << 24); } else { nVal = matrixIdx0 | (matrixIdx1 << 8) | (matrixIdx2 << 16) | (matrixIdx3 << 24); } int* pBoneMatrix = (int*)(&m_pBoneMatrixIndex[m_nCurrentVertex * m_VertexSize_BoneMatrixIndex]); *pBoneMatrix = nVal; #else float* pBoneMatrix = &m_pBoneMatrixIndex[m_nCurrentVertex * m_VertexSize_BoneMatrixIndex]; pBoneMatrix[0] = matrixIdx0; pBoneMatrix[1] = matrixIdx1; pBoneMatrix[2] = matrixIdx2; pBoneMatrix[3] = matrixIdx3; #endif } template inline void CVertexBuilder::CompressedBoneWeight3fv(const float* pWeights) { Assert(T == m_CompressionType); Assert(m_pBoneWeight); Assert(pWeights); float* pDestWeights = OffsetFloatPointer(m_pBoneWeight, m_nCurrentVertex, m_VertexSize_BoneWeight); if (T == VERTEX_COMPRESSION_ON) { Assert(m_NumBoneWeights <= 2); const int WEIGHT0_SHIFT = IsX360() ? 16 : 0; const int WEIGHT1_SHIFT = IsX360() ? 0 : 16; unsigned int* weights = (unsigned int*)pDestWeights; Assert(IsFinite(pWeights[0]) && (pWeights[0] >= 0.0f) && (pWeights[0] <= 1.0f)); unsigned int weight0 = Float2Int(pWeights[0] * 32768.0f); *weights = (0x0000FFFF & (weight0 - 1)) << WEIGHT0_SHIFT; #ifdef DEBUG if (m_NumBoneWeights == 1) { Assert(IsFinite(pWeights[1]) && (pWeights[1] >= 0.0f) && (pWeights[1] <= 1.0f)); unsigned int weight1 = Float2Int(pWeights[1] * 32768.0f); Assert((weight0 + weight1) <= 32768); } #endif if (m_NumBoneWeights > 1) { Assert(m_NumBoneWeights == 2); Assert(IsFinite(pWeights[1]) && (pWeights[1] >= 0.0f) && (pWeights[1] <= 1.0f)); Assert(IsFinite(pWeights[2]) && (pWeights[2] >= 0.0f) && (pWeights[2] <= 1.0f)); unsigned int weight1 = Float2Int(pWeights[1] * 32768.0f); unsigned int weight2 = Float2Int(pWeights[2] * 32768.0f); Assert((weight0 + weight1 + weight2) <= 32768); unsigned int residual = 32768 - (weight0 + weight1 + weight2); weight1 += residual; *weights |= (0x0000FFFF & (weight1 - 1)) << WEIGHT1_SHIFT; } } else { pDestWeights[0] = pWeights[0]; pDestWeights[1] = pWeights[1]; } } inline void CVertexBuilder::UserData(const float* pData) { Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); Assert(pData); int userDataSize = 4; float* pUserData = OffsetFloatPointer(m_pUserData, m_nCurrentVertex, m_VertexSize_UserData); memcpy(pUserData, pData, sizeof(float) * userDataSize); } template inline void CVertexBuilder::CompressedUserData(const float* pData) { Assert(T == m_CompressionType); Assert(pData); Assert(IsFinite(pData[0]) && IsFinite(pData[1]) && IsFinite(pData[2])); Assert(pData[0] >= -1.05f && pData[0] <= 1.05f); Assert(pData[1] >= -1.05f && pData[1] <= 1.05f); Assert(pData[2] >= -1.05f && pData[2] <= 1.05f); Assert(pData[3] == +1.0f || pData[3] == -1.0f); if (T == VERTEX_COMPRESSION_ON) { float binormalSign = pData[3]; #if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 ) float* pUserData = OffsetFloatPointer(m_pUserData, m_nCurrentVertex, m_VertexSize_UserData); PackNormal_SHORT2(pData, (unsigned int*)pUserData, binormalSign); #else unsigned int existingNormalData = *(unsigned int*)m_pCurrNormal; Assert((existingNormalData & 0xFFFF0000) == 0); #ifdef _DEBUG Assert(m_bWrittenNormal == true); m_bWrittenUserData = true; #endif bool bIsTangent = true; unsigned int tangentData = 0; PackNormal_UBYTE4(pData, &tangentData, bIsTangent, binormalSign); *(unsigned int*)m_pCurrNormal = existingNormalData | tangentData; #endif } else { int userDataSize = 4; float* pUserData = OffsetFloatPointer(m_pUserData, m_nCurrentVertex, m_VertexSize_UserData); memcpy(pUserData, pData, sizeof(float) * userDataSize); } } class CIndexBuilder : private IndexDesc_t { public: CIndexBuilder(); CIndexBuilder(IIndexBuffer* pIndexBuffer, MaterialIndexFormat_t fmt = MATERIAL_INDEX_FORMAT_UNKNOWN); ~CIndexBuilder(); bool Lock(int nMaxIndexCount, int nIndexOffset, bool bAppend = false); void Unlock(); void SpewData(); int GetRoomRemaining() const; void Bind(IMatRenderContext* pContext); int Offset() const; void Begin(IIndexBuffer* pIndexBuffer, int nMaxIndexCount, int nIndexOffset = 0); void End(bool bSpewData = false); void BeginModify(IIndexBuffer* pIndexBuffer, int firstIndex = 0, int numIndices = 0, int nIndexOffset = 0); void EndModify(bool bSpewData = false); int IndexCount() const; int TotalIndexCount() const; void Reset(); void SelectIndex(int nBufferIndex); void AdvanceIndex(); void AdvanceIndices(int numIndices); int GetCurrentIndex(); int GetFirstIndex() const; unsigned short const* Index() const; void Index(unsigned short nIndex); void FastIndex(unsigned short nIndex); void FastIndex2(unsigned short nIndex1, unsigned short nIndex2); void GenerateIndices(MaterialPrimitiveType_t primitiveType, int numIndices); void AttachBegin(IMesh* pMesh, int nMaxIndexCount, const MeshDesc_t& desc); void AttachEnd(); void AttachBeginModify(IMesh* pMesh, int firstIndex, int numIndices, const MeshDesc_t& desc); void AttachEndModify(); void FastTriangle(int startVert); void FastQuad(int startVert); void FastPolygon(int startVert, int numTriangles); void FastPolygonList(int startVert, int* pVertexCount, int polygonCount); void FastIndexList(const unsigned short* pIndexList, int startVert, int indexCount); private: IIndexBuffer* m_pIndexBuffer; int m_nMaxIndexCount; int m_nIndexCount; int m_nIndexOffset; mutable int m_nCurrentIndex; int m_nTotalIndexCount; unsigned int m_nBufferOffset; unsigned int m_nBufferFirstIndex; bool m_bModify; }; inline CIndexBuilder::CIndexBuilder() : m_pIndexBuffer(0), m_nMaxIndexCount(0), m_nIndexCount(0), m_nCurrentIndex(0) { m_nTotalIndexCount = 0; m_nBufferOffset = INVALID_BUFFER_OFFSET; m_nBufferFirstIndex = 0; #ifdef _DEBUG m_bModify = false; #endif } inline CIndexBuilder::CIndexBuilder(IIndexBuffer* pIndexBuffer, MaterialIndexFormat_t fmt) { m_pIndexBuffer = pIndexBuffer; m_nBufferOffset = INVALID_BUFFER_OFFSET; m_nBufferFirstIndex = 0; m_nIndexCount = 0; m_nCurrentIndex = 0; m_nMaxIndexCount = 0; m_nTotalIndexCount = 0; if (m_pIndexBuffer->IsDynamic()) { m_pIndexBuffer->BeginCastBuffer(fmt); } else { Assert(m_pIndexBuffer->IndexFormat() == fmt); } #ifdef _DEBUG m_bModify = false; #endif } inline CIndexBuilder::~CIndexBuilder() { if (m_pIndexBuffer && m_pIndexBuffer->IsDynamic()) { m_pIndexBuffer->EndCastBuffer(); } } inline bool CIndexBuilder::Lock(int nMaxIndexCount, int nIndexOffset, bool bAppend) { Assert(m_pIndexBuffer); m_bModify = false; m_nIndexOffset = nIndexOffset; m_nMaxIndexCount = nMaxIndexCount; m_nIndexCount = 0; bool bFirstLock = (m_nBufferOffset == INVALID_BUFFER_OFFSET); if (bFirstLock) { bAppend = false; } if (!bAppend) { m_nTotalIndexCount = 0; } Reset(); if (!m_pIndexBuffer->Lock(m_nMaxIndexCount, bAppend, *this)) { m_nMaxIndexCount = 0; return false; } if (bFirstLock) { m_nBufferOffset = m_nOffset; m_nBufferFirstIndex = m_nFirstIndex; } return true; } inline void CIndexBuilder::Unlock() { Assert(!m_bModify && m_pIndexBuffer); m_pIndexBuffer->Unlock(m_nIndexCount, *this); m_nTotalIndexCount += m_nIndexCount; m_nMaxIndexCount = 0; #ifdef _DEBUG memset((IndexDesc_t*)this, 0, sizeof(IndexDesc_t)); #endif } inline void CIndexBuilder::SpewData() { m_pIndexBuffer->Spew(m_nIndexCount, *this); } inline void CIndexBuilder::Bind(IMatRenderContext* pContext) { if (m_pIndexBuffer && (m_nBufferOffset != INVALID_BUFFER_OFFSET)) { pContext->BindIndexBuffer(m_pIndexBuffer, m_nBufferOffset); } else { pContext->BindIndexBuffer(NULL, 0); } } inline int CIndexBuilder::Offset() const { return m_nBufferOffset; } inline int CIndexBuilder::GetFirstIndex() const { return m_nBufferFirstIndex; } inline void CIndexBuilder::Begin(IIndexBuffer* pIndexBuffer, int nMaxIndexCount, int nIndexOffset) { Assert(pIndexBuffer && (!m_pIndexBuffer)); m_pIndexBuffer = pIndexBuffer; m_nIndexCount = 0; m_nMaxIndexCount = nMaxIndexCount; m_nIndexOffset = nIndexOffset; m_bModify = false; m_pIndexBuffer->Lock(m_nMaxIndexCount, false, *this); Reset(); } inline void CIndexBuilder::End(bool bSpewData) { Assert(!m_bModify); if (bSpewData) { m_pIndexBuffer->Spew(m_nIndexCount, *this); } m_pIndexBuffer->Unlock(m_nIndexCount, *this); m_pIndexBuffer = 0; m_nMaxIndexCount = 0; #ifdef _DEBUG memset((IndexDesc_t*)this, 0, sizeof(IndexDesc_t)); #endif } inline void CIndexBuilder::BeginModify(IIndexBuffer* pIndexBuffer, int nFirstIndex, int nIndexCount, int nIndexOffset) { m_pIndexBuffer = pIndexBuffer; m_nIndexCount = nIndexCount; m_nMaxIndexCount = nIndexCount; m_nIndexOffset = nIndexOffset; m_bModify = true; m_pIndexBuffer->ModifyBegin(false, nFirstIndex, nIndexCount, *this); Reset(); } inline void CIndexBuilder::EndModify(bool bSpewData) { Assert(m_pIndexBuffer); Assert(m_bModify); if (bSpewData) { m_pIndexBuffer->Spew(m_nIndexCount, *this); } m_pIndexBuffer->ModifyEnd(*this); m_pIndexBuffer = 0; m_nMaxIndexCount = 0; #ifdef _DEBUG memset((IndexDesc_t*)this, 0, sizeof(IndexDesc_t)); #endif } inline void CIndexBuilder::AttachBegin(IMesh* pMesh, int nMaxIndexCount, const MeshDesc_t& desc) { m_pIndexBuffer = pMesh; m_nIndexCount = 0; m_nMaxIndexCount = nMaxIndexCount; m_bModify = false; m_nIndexOffset = desc.m_nFirstVertex; m_pIndices = desc.m_pIndices; m_nIndexSize = desc.m_nIndexSize; Reset(); } inline void CIndexBuilder::AttachEnd() { Assert(m_pIndexBuffer); Assert(!m_bModify); m_pIndexBuffer = 0; m_nMaxIndexCount = 0; #ifdef _DEBUG memset((IndexDesc_t*)this, 0, sizeof(IndexDesc_t)); #endif } inline void CIndexBuilder::AttachBeginModify(IMesh* pMesh, int nFirstIndex, int nIndexCount, const MeshDesc_t& desc) { m_pIndexBuffer = pMesh; m_nIndexCount = nIndexCount; m_nMaxIndexCount = nIndexCount; m_bModify = true; m_nIndexOffset = desc.m_nFirstVertex; m_pIndices = desc.m_pIndices; m_nIndexSize = desc.m_nIndexSize; Reset(); } inline void CIndexBuilder::AttachEndModify() { Assert(m_pIndexBuffer); Assert(m_bModify); m_pIndexBuffer = 0; m_nMaxIndexCount = 0; #ifdef _DEBUG memset((IndexDesc_t*)this, 0, sizeof(IndexDesc_t)); #endif } inline void CIndexBuilder::Reset() { m_nCurrentIndex = 0; } inline int CIndexBuilder::IndexCount() const { return m_nIndexCount; } inline int CIndexBuilder::TotalIndexCount() const { return m_nTotalIndexCount; } inline void CIndexBuilder::AdvanceIndex() { m_nCurrentIndex += m_nIndexSize; if (m_nCurrentIndex > m_nIndexCount) { m_nIndexCount = m_nCurrentIndex; } } inline void CIndexBuilder::AdvanceIndices(int nIndices) { m_nCurrentIndex += nIndices * m_nIndexSize; if (m_nCurrentIndex > m_nIndexCount) { m_nIndexCount = m_nCurrentIndex; } } inline int CIndexBuilder::GetCurrentIndex() { return m_nCurrentIndex; } inline unsigned short const* CIndexBuilder::Index() const { Assert(m_nCurrentIndex < m_nMaxIndexCount); return &m_pIndices[m_nCurrentIndex]; } inline void CIndexBuilder::SelectIndex(int nIndex) { Assert((nIndex >= 0) && (nIndex < m_nIndexCount)); m_nCurrentIndex = nIndex * m_nIndexSize; } inline void CIndexBuilder::Index(unsigned short nIndex) { Assert(m_pIndices); Assert(m_nCurrentIndex < m_nMaxIndexCount); m_pIndices[m_nCurrentIndex] = (unsigned short)(m_nIndexOffset + nIndex); } inline void CIndexBuilder::FastIndex(unsigned short nIndex) { Assert(m_pIndices); Assert(m_nCurrentIndex < m_nMaxIndexCount); m_pIndices[m_nCurrentIndex] = (unsigned short)(m_nIndexOffset + nIndex); m_nCurrentIndex += m_nIndexSize; m_nIndexCount = m_nCurrentIndex; } FORCEINLINE void CIndexBuilder::FastTriangle(int startVert) { startVert += m_nIndexOffset; unsigned short* pIndices = &m_pIndices[m_nCurrentIndex]; *pIndices++ = startVert++; *pIndices++ = startVert++; *pIndices++ = startVert; AdvanceIndices(3); } FORCEINLINE void CIndexBuilder::FastQuad(int startVert) { startVert += m_nIndexOffset; unsigned short* pIndices = &m_pIndices[m_nCurrentIndex]; *pIndices++ = startVert++; *pIndices++ = startVert++; *pIndices++ = startVert; *pIndices++ = startVert - 2; *pIndices++ = startVert++; *pIndices++ = startVert; AdvanceIndices(6); } inline void CIndexBuilder::FastPolygon(int startVert, int triangleCount) { unsigned short* pIndex = &m_pIndices[m_nCurrentIndex]; startVert += m_nIndexOffset; if (!IsX360()) { Assert(m_nIndexSize == 0 || m_nIndexSize == 1); triangleCount *= m_nIndexSize; } for (int v = 0; v < triangleCount; ++v) { *pIndex++ = startVert; *pIndex++ = startVert + v + 1; *pIndex++ = startVert + v + 2; } AdvanceIndices(triangleCount * 3); } inline void CIndexBuilder::FastPolygonList(int startVert, int* pVertexCount, int polygonCount) { unsigned short* pIndex = &m_pIndices[m_nCurrentIndex]; startVert += m_nIndexOffset; int indexOut = 0; if (!IsX360()) { Assert(m_nIndexSize == 0 || m_nIndexSize == 1); polygonCount *= m_nIndexSize; } for (int i = 0; i < polygonCount; i++) { int vertexCount = pVertexCount[i]; int triangleCount = vertexCount - 2; for (int v = 0; v < triangleCount; ++v) { *pIndex++ = startVert; *pIndex++ = startVert + v + 1; *pIndex++ = startVert + v + 2; } startVert += vertexCount; indexOut += triangleCount * 3; } AdvanceIndices(indexOut); } inline void CIndexBuilder::FastIndexList(const unsigned short* pIndexList, int startVert, int indexCount) { unsigned short* pIndexOut = &m_pIndices[m_nCurrentIndex]; startVert += m_nIndexOffset; if (!IsX360()) { Assert(m_nIndexSize == 0 || m_nIndexSize == 1); indexCount *= m_nIndexSize; } for (int i = 0; i < indexCount; ++i) { pIndexOut[i] = startVert + pIndexList[i]; } AdvanceIndices(indexCount); } inline void CIndexBuilder::FastIndex2(unsigned short nIndex1, unsigned short nIndex2) { Assert(m_pIndices); Assert(m_nCurrentIndex < m_nMaxIndexCount - 1); #ifndef _X360 unsigned int nIndices = ((unsigned int)nIndex1 + m_nIndexOffset) | (((unsigned int)nIndex2 + m_nIndexOffset) << 16); #else unsigned int nIndices = ((unsigned int)nIndex2 + m_nIndexOffset) | (((unsigned int)nIndex1 + m_nIndexOffset) << 16); #endif * (int*)(&m_pIndices[m_nCurrentIndex]) = nIndices; m_nCurrentIndex += m_nIndexSize + m_nIndexSize; m_nIndexCount = m_nCurrentIndex; } inline void CIndexBuilder::GenerateIndices(MaterialPrimitiveType_t primitiveType, int nIndexCount) { if (m_nIndexSize == 0) return; int nMaxIndices = m_nMaxIndexCount - m_nCurrentIndex; nIndexCount = MIN(nMaxIndices, nIndexCount); if (nIndexCount == 0) return; unsigned short* pIndices = &m_pIndices[m_nCurrentIndex]; switch (primitiveType) { case MATERIAL_INSTANCED_QUADS: Assert(0); break; case MATERIAL_QUADS: GenerateQuadIndexBuffer(pIndices, nIndexCount, m_nIndexOffset); break; case MATERIAL_POLYGON: GeneratePolygonIndexBuffer(pIndices, nIndexCount, m_nIndexOffset); break; case MATERIAL_LINE_STRIP: GenerateLineStripIndexBuffer(pIndices, nIndexCount, m_nIndexOffset); break; case MATERIAL_LINE_LOOP: GenerateLineLoopIndexBuffer(pIndices, nIndexCount, m_nIndexOffset); break; case MATERIAL_POINTS: Assert(0); break; case MATERIAL_SUBD_QUADS_EXTRA: case MATERIAL_SUBD_QUADS_REG: default: GenerateSequentialIndexBuffer(pIndices, nIndexCount, m_nIndexOffset); break; } AdvanceIndices(nIndexCount); } class CMeshBuilder : public MeshDesc_t { public: CMeshBuilder(); ~CMeshBuilder() { Assert(!m_pMesh); } operator CIndexBuilder& () { return m_IndexBuilder; } void SetCompressionType(VertexCompressionType_t compressionType); void Begin(IMesh* pMesh, MaterialPrimitiveType_t type, int numPrimitives); void Begin(IMesh* pMesh, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount, int* nFirstVertex); void Begin(IMesh* pMesh, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount); void Begin(IVertexBuffer* pVertexBuffer, MaterialPrimitiveType_t type, int numPrimitives); void Begin(IVertexBuffer* pVertexBuffer, IIndexBuffer* pIndexBuffer, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount, int* nFirstVertex); void Begin(IVertexBuffer* pVertexBuffer, IIndexBuffer* pIndexBuffer, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount); void End(bool bSpewData = false, bool bDraw = false); void BeginModify(IMesh* pMesh, int nFirstVertex = 0, int nVertexCount = -1, int nFirstIndex = 0, int nIndexCount = 0); void EndModify(bool bSpewData = false); void DrawQuad(IMesh* pMesh, const float* v1, const float* v2, const float* v3, const float* v4, unsigned char const* pColor, bool wireframe = false); int VertexCount() const; int IndexCount() const; void Reset(); int VertexSize() { return m_ActualVertexSize; } int TextureCoordinateSize(int nTexCoordNumber) { return m_VertexSize_TexCoord[nTexCoordNumber]; } void* BaseVertexData(); void SelectVertex(int idx); void SelectIndex(int idx); void SelectVertexFromIndex(int idx); void AdvanceVertex(); template void AdvanceVertexF(); void AdvanceVertices(int nVerts); void AdvanceIndex(); void AdvanceIndices(int nIndices); int GetCurrentVertex(); int GetCurrentIndex(); const float* Position() const; const float* Normal() const; unsigned int Color() const; unsigned char* Specular() const; const float* TexCoord(int stage) const; const float* TangentS() const; const float* TangentT() const; const float* BoneWeight() const; float Wrinkle() const; int NumBoneWeights() const; #ifndef NEW_SKINNING unsigned char* BoneMatrix() const; #else float* BoneMatrix() const; #endif unsigned short const* Index() const; void Position3f(float x, float y, float z); void Position3fv(const float* v); void Normal3f(float nx, float ny, float nz); void Normal3fv(const float* n); void NormalDelta3fv(const float* n); void NormalDelta3f(float nx, float ny, float nz); template void CompressedNormal3f(float nx, float ny, float nz); template void CompressedNormal3fv(const float* n); void Color3f(float r, float g, float b); void Color3fv(const float* rgb); void Color4f(float r, float g, float b, float a); void Color4fv(const float* rgba); void Color3ub(unsigned char r, unsigned char g, unsigned char b); void Color3ubv(unsigned char const* rgb); void Color4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a); void Color4ubv(unsigned char const* rgba); void Color4Packed(int packedColor); int PackColor4(unsigned char r, unsigned char g, unsigned char b, unsigned char a); void Specular3f(float r, float g, float b); void Specular3fv(const float* rgb); void Specular4f(float r, float g, float b, float a); void Specular4fv(const float* rgba); void Specular3ub(unsigned char r, unsigned char g, unsigned char b); void Specular3ubv(unsigned char const* c); void Specular4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a); void Specular4ubv(unsigned char const* c); void TexCoord1f(int stage, float s); void TexCoord2f(int stage, float s, float t); void TexCoord2fv(int stage, const float* st); void TexCoord3f(int stage, float s, float t, float u); void TexCoord3fv(int stage, const float* stu); void TexCoord4f(int stage, float s, float t, float u, float w); void TexCoord4fv(int stage, const float* stuv); void TexCoordSubRect2f(int stage, float s, float t, float offsetS, float offsetT, float scaleS, float scaleT); void TexCoordSubRect2fv(int stage, const float* st, const float* offset, const float* scale); void TangentS3f(float sx, float sy, float sz); void TangentS3fv(const float* s); void TangentT3f(float tx, float ty, float tz); void TangentT3fv(const float* t); void Wrinkle1f(float flWrinkle); void BoneWeight(int idx, float weight); void BoneWeights2(float weight1, float weight2); template void CompressedBoneWeight3fv(const float* pWeights); void BoneMatrix(int idx, int matrixIndex); void BoneMatrices4(int matrixIdx0, int matrixIdx1, int matrixIdx2, int matrixIdx3); void UserData(const float* pData); template void CompressedUserData(const float* pData); void Index(unsigned short index); void FastIndex2(unsigned short nIndex1, unsigned short nIndex2); void FastIndex(unsigned short index); void FastQuad(int index); void FastVertex(const ModelVertexDX8_t& vertex); void FastVertexSSE(const ModelVertexDX8_t& vertex); void FastQuadVertexSSE(const QuadTessVertex_t& vertex); void FastAdvanceNVertices(int n); #if defined( _X360 ) void VertexDX8ToX360(const ModelVertexDX8_t& vertex); #endif FORCEINLINE void* GetVertexDataPtr(int nWhatSizeIThinkItIs) { if (m_VertexBuilder.m_VertexSize_Position != nWhatSizeIThinkItIs) return NULL; return m_VertexBuilder.m_pCurrPosition; } private: void ComputeNumVertsAndIndices(int* pMaxVertices, int* pMaxIndices, MaterialPrimitiveType_t type, int nPrimitiveCount); int IndicesFromVertices(MaterialPrimitiveType_t type, int nVertexCount); IMesh* m_pMesh; MaterialPrimitiveType_t m_Type; bool m_bGenerateIndices; CIndexBuilder m_IndexBuilder; CVertexBuilder m_VertexBuilder; }; inline void CMeshBuilder::Begin(IVertexBuffer* pVertexBuffer, MaterialPrimitiveType_t type, int numPrimitives) { Assert(0); } inline void CMeshBuilder::Begin(IVertexBuffer* pVertexBuffer, IIndexBuffer* pIndexBuffer, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount, int* nFirstVertex) { Assert(0); } inline void CMeshBuilder::Begin(IVertexBuffer* pVertexBuffer, IIndexBuffer* pIndexBuffer, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount) { Assert(0); } inline CMeshBuilder::CMeshBuilder() : m_pMesh(0), m_bGenerateIndices(false) { } inline void CMeshBuilder::ComputeNumVertsAndIndices(int* pMaxVertices, int* pMaxIndices, MaterialPrimitiveType_t type, int nPrimitiveCount) { switch (type) { case MATERIAL_POINTS: *pMaxVertices = *pMaxIndices = nPrimitiveCount; break; case MATERIAL_LINES: *pMaxVertices = *pMaxIndices = nPrimitiveCount * 2; break; case MATERIAL_LINE_STRIP: *pMaxVertices = nPrimitiveCount + 1; *pMaxIndices = nPrimitiveCount * 2; break; case MATERIAL_LINE_LOOP: *pMaxVertices = nPrimitiveCount; *pMaxIndices = nPrimitiveCount * 2; break; case MATERIAL_TRIANGLES: *pMaxVertices = *pMaxIndices = nPrimitiveCount * 3; break; case MATERIAL_TRIANGLE_STRIP: *pMaxVertices = *pMaxIndices = nPrimitiveCount + 2; break; case MATERIAL_QUADS: *pMaxVertices = nPrimitiveCount * 4; *pMaxIndices = nPrimitiveCount * 6; break; case MATERIAL_INSTANCED_QUADS: *pMaxVertices = nPrimitiveCount; *pMaxIndices = 0; break; case MATERIAL_POLYGON: *pMaxVertices = nPrimitiveCount; *pMaxIndices = (nPrimitiveCount - 2) * 3; break; default: Assert(0); } Assert(*pMaxVertices <= 32768); Assert(*pMaxIndices <= 32768); } inline int CMeshBuilder::IndicesFromVertices(MaterialPrimitiveType_t type, int nVertexCount) { switch (type) { case MATERIAL_QUADS: Assert((nVertexCount & 0x3) == 0); return (nVertexCount * 6) / 4; case MATERIAL_INSTANCED_QUADS: return 0; case MATERIAL_POLYGON: Assert(nVertexCount >= 3); return (nVertexCount - 2) * 3; case MATERIAL_LINE_STRIP: Assert(nVertexCount >= 2); return (nVertexCount - 1) * 2; case MATERIAL_LINE_LOOP: Assert(nVertexCount >= 3); return nVertexCount * 2; default: return nVertexCount; } } inline void CMeshBuilder::SetCompressionType(VertexCompressionType_t vertexCompressionType) { m_CompressionType = vertexCompressionType; m_VertexBuilder.SetCompressionType(vertexCompressionType); } inline void CMeshBuilder::Begin(IMesh* pMesh, MaterialPrimitiveType_t type, int numPrimitives) { Assert(pMesh && (!m_pMesh)); Assert(type != MATERIAL_HETEROGENOUS); m_pMesh = pMesh; m_bGenerateIndices = true; m_Type = type; int nMaxVertexCount, nMaxIndexCount; ComputeNumVertsAndIndices(&nMaxVertexCount, &nMaxIndexCount, type, numPrimitives); switch (type) { case MATERIAL_INSTANCED_QUADS: m_pMesh->SetPrimitiveType(MATERIAL_INSTANCED_QUADS); break; case MATERIAL_QUADS: case MATERIAL_POLYGON: m_pMesh->SetPrimitiveType(MATERIAL_TRIANGLES); break; case MATERIAL_LINE_STRIP: case MATERIAL_LINE_LOOP: m_pMesh->SetPrimitiveType(MATERIAL_LINES); break; default: m_pMesh->SetPrimitiveType(type); } m_pMesh->LockMesh(nMaxVertexCount, nMaxIndexCount, *this, NULL); m_IndexBuilder.AttachBegin(pMesh, nMaxIndexCount, *this); m_VertexBuilder.AttachBegin(pMesh, nMaxVertexCount, *this); Reset(); } inline void CMeshBuilder::Begin(IMesh* pMesh, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount, int* nFirstVertex) { Begin(pMesh, type, nVertexCount, nIndexCount); *nFirstVertex = m_VertexBuilder.m_nFirstVertex * m_VertexBuilder.VertexSize(); } inline void CMeshBuilder::Begin(IMesh* pMesh, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount) { Assert(pMesh && (!m_pMesh)); Assert((type != MATERIAL_QUADS) && (type != MATERIAL_INSTANCED_QUADS) && (type != MATERIAL_POLYGON) && (type != MATERIAL_LINE_STRIP) && (type != MATERIAL_LINE_LOOP)); Assert(type != MATERIAL_POINTS); m_pMesh = pMesh; m_bGenerateIndices = false; m_Type = type; m_pMesh->SetPrimitiveType(type); m_pMesh->LockMesh(nVertexCount, nIndexCount, *this, NULL); m_IndexBuilder.AttachBegin(pMesh, nIndexCount, *this); m_VertexBuilder.AttachBegin(pMesh, nVertexCount, *this); Reset(); } inline void CMeshBuilder::End(bool bSpewData, bool bDraw) { if (m_bGenerateIndices) { int nIndexCount = IndicesFromVertices(m_Type, m_VertexBuilder.VertexCount()); m_IndexBuilder.GenerateIndices(m_Type, nIndexCount); } if (bSpewData) { m_pMesh->Spew(m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this); } #ifdef _DEBUG m_pMesh->ValidateData(m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this); #endif m_pMesh->UnlockMesh(m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this); m_IndexBuilder.AttachEnd(); m_VertexBuilder.AttachEnd(); if (bDraw) { m_pMesh->Draw(); } m_pMesh = 0; #ifdef _DEBUG memset((MeshDesc_t*)this, 0, sizeof(MeshDesc_t)); #endif } inline void CMeshBuilder::BeginModify(IMesh* pMesh, int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount) { Assert(pMesh && (!m_pMesh)); if (nVertexCount < 0) { nVertexCount = pMesh->VertexCount(); } m_pMesh = pMesh; m_bGenerateIndices = false; pMesh->ModifyBeginEx(false, nFirstVertex, nVertexCount, nFirstIndex, nIndexCount, *this); m_IndexBuilder.AttachBeginModify(pMesh, nFirstIndex, nIndexCount, *this); m_VertexBuilder.AttachBeginModify(pMesh, nFirstVertex, nVertexCount, *this); Reset(); } inline void CMeshBuilder::EndModify(bool bSpewData) { Assert(m_pMesh); if (bSpewData) { m_pMesh->Spew(m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this); } #ifdef _DEBUG m_pMesh->ValidateData(m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this); #endif m_pMesh->ModifyEnd(*this); m_pMesh = 0; m_IndexBuilder.AttachEndModify(); m_VertexBuilder.AttachEndModify(); #ifdef _DEBUG memset((MeshDesc_t*)this, 0, sizeof(MeshDesc_t)); #endif } inline void CMeshBuilder::Reset() { m_IndexBuilder.Reset(); m_VertexBuilder.Reset(); } FORCEINLINE void CMeshBuilder::SelectVertex(int nIndex) { m_VertexBuilder.SelectVertex(nIndex); } inline void CMeshBuilder::SelectVertexFromIndex(int idx) { int vertIdx = idx - m_nFirstVertex; SelectVertex(vertIdx); } FORCEINLINE void CMeshBuilder::SelectIndex(int idx) { m_IndexBuilder.SelectIndex(idx); } template FORCEINLINE void CMeshBuilder::AdvanceVertexF() { m_VertexBuilder.AdvanceVertexF(); } FORCEINLINE void CMeshBuilder::AdvanceVertex() { m_VertexBuilder.AdvanceVertex(); } FORCEINLINE void CMeshBuilder::AdvanceVertices(int nVertexCount) { m_VertexBuilder.AdvanceVertices(nVertexCount); } FORCEINLINE void CMeshBuilder::AdvanceIndex() { m_IndexBuilder.AdvanceIndex(); } FORCEINLINE void CMeshBuilder::AdvanceIndices(int nIndices) { m_IndexBuilder.AdvanceIndices(nIndices); } FORCEINLINE int CMeshBuilder::GetCurrentVertex() { return m_VertexBuilder.GetCurrentVertex(); } FORCEINLINE int CMeshBuilder::GetCurrentIndex() { return m_IndexBuilder.GetCurrentIndex(); } inline void CMeshBuilder::DrawQuad(IMesh* pMesh, const float* v1, const float* v2, const float* v3, const float* v4, unsigned char const* pColor, bool wireframe) { if (!wireframe) { Begin(pMesh, MATERIAL_TRIANGLE_STRIP, 2); Position3fv(v1); Color4ubv(pColor); AdvanceVertexF(); Position3fv(v2); Color4ubv(pColor); AdvanceVertexF(); Position3fv(v4); Color4ubv(pColor); AdvanceVertexF(); Position3fv(v3); Color4ubv(pColor); AdvanceVertexF(); } else { Begin(pMesh, MATERIAL_LINE_LOOP, 4); Position3fv(v1); Color4ubv(pColor); AdvanceVertexF(); Position3fv(v2); Color4ubv(pColor); AdvanceVertexF(); Position3fv(v3); Color4ubv(pColor); AdvanceVertexF(); Position3fv(v4); Color4ubv(pColor); AdvanceVertexF(); } End(); pMesh->Draw(); } FORCEINLINE int CMeshBuilder::VertexCount() const { return m_VertexBuilder.VertexCount(); } FORCEINLINE int CMeshBuilder::IndexCount() const { return m_IndexBuilder.IndexCount(); } FORCEINLINE void* CMeshBuilder::BaseVertexData() { return m_VertexBuilder.BaseVertexData(); } FORCEINLINE const float* CMeshBuilder::Position() const { return m_VertexBuilder.Position(); } FORCEINLINE const float* CMeshBuilder::Normal() const { return m_VertexBuilder.Normal(); } FORCEINLINE unsigned int CMeshBuilder::Color() const { return m_VertexBuilder.Color(); } FORCEINLINE unsigned char* CMeshBuilder::Specular() const { return m_VertexBuilder.Specular(); } FORCEINLINE const float* CMeshBuilder::TexCoord(int nStage) const { return m_VertexBuilder.TexCoord(nStage); } FORCEINLINE const float* CMeshBuilder::TangentS() const { return m_VertexBuilder.TangentS(); } FORCEINLINE const float* CMeshBuilder::TangentT() const { return m_VertexBuilder.TangentT(); } FORCEINLINE float CMeshBuilder::Wrinkle() const { return m_VertexBuilder.Wrinkle(); } FORCEINLINE const float* CMeshBuilder::BoneWeight() const { return m_VertexBuilder.BoneWeight(); } FORCEINLINE int CMeshBuilder::NumBoneWeights() const { return m_VertexBuilder.NumBoneWeights(); } FORCEINLINE unsigned short const* CMeshBuilder::Index() const { return m_IndexBuilder.Index(); } FORCEINLINE void CMeshBuilder::Index(unsigned short idx) { m_IndexBuilder.Index(idx); } FORCEINLINE void CMeshBuilder::FastIndex(unsigned short idx) { m_IndexBuilder.FastIndex(idx); } FORCEINLINE void CMeshBuilder::FastIndex2(unsigned short nIndex1, unsigned short nIndex2) { m_IndexBuilder.FastIndex2(nIndex1, nIndex2); } FORCEINLINE void CMeshBuilder::FastQuad(int nIndex) { m_IndexBuilder.FastQuad(nIndex); } FORCEINLINE void CMeshBuilder::FastAdvanceNVertices(int nVertexCount) { m_VertexBuilder.FastAdvanceNVertices(nVertexCount); } FORCEINLINE void CMeshBuilder::FastVertex(const ModelVertexDX8_t& vertex) { m_VertexBuilder.FastVertex(vertex); } FORCEINLINE void CMeshBuilder::FastVertexSSE(const ModelVertexDX8_t& vertex) { m_VertexBuilder.FastVertexSSE(vertex); } FORCEINLINE void CMeshBuilder::FastQuadVertexSSE(const QuadTessVertex_t& vertex) { m_VertexBuilder.FastQuadVertexSSE(vertex); } #if defined( _X360 ) inline void CMeshBuilder::VertexDX8ToX360(const ModelVertexDX8_t& vertex) { m_VertexBuilder.VertexDX8ToX360(vertex); } #endif FORCEINLINE void CMeshBuilder::Position3f(float x, float y, float z) { m_VertexBuilder.Position3f(x, y, z); } FORCEINLINE void CMeshBuilder::Position3fv(const float* v) { m_VertexBuilder.Position3fv(v); } FORCEINLINE void CMeshBuilder::Normal3f(float nx, float ny, float nz) { m_VertexBuilder.Normal3f(nx, ny, nz); } FORCEINLINE void CMeshBuilder::Normal3fv(const float* n) { m_VertexBuilder.Normal3fv(n); } FORCEINLINE void CMeshBuilder::NormalDelta3f(float nx, float ny, float nz) { m_VertexBuilder.NormalDelta3f(nx, ny, nz); } FORCEINLINE void CMeshBuilder::NormalDelta3fv(const float* n) { m_VertexBuilder.NormalDelta3fv(n); } FORCEINLINE void CMeshBuilder::Color3f(float r, float g, float b) { m_VertexBuilder.Color3f(r, g, b); } FORCEINLINE void CMeshBuilder::Color3fv(const float* rgb) { m_VertexBuilder.Color3fv(rgb); } FORCEINLINE void CMeshBuilder::Color4f(float r, float g, float b, float a) { m_VertexBuilder.Color4f(r, g, b, a); } FORCEINLINE void CMeshBuilder::Color4fv(const float* rgba) { m_VertexBuilder.Color4fv(rgba); } FORCEINLINE void CMeshBuilder::Color3ub(unsigned char r, unsigned char g, unsigned char b) { m_VertexBuilder.Color3ub(r, g, b); } FORCEINLINE void CMeshBuilder::Color3ubv(unsigned char const* rgb) { m_VertexBuilder.Color3ubv(rgb); } FORCEINLINE void CMeshBuilder::Color4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { m_VertexBuilder.Color4ub(r, g, b, a); } FORCEINLINE void CMeshBuilder::Color4ubv(unsigned char const* rgba) { m_VertexBuilder.Color4ubv(rgba); } FORCEINLINE void CMeshBuilder::Color4Packed(int packedColor) { m_VertexBuilder.Color4Packed(packedColor); } FORCEINLINE int CMeshBuilder::PackColor4(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { return m_VertexBuilder.PackColor4(r, g, b, a); } FORCEINLINE void CMeshBuilder::Specular3f(float r, float g, float b) { m_VertexBuilder.Specular3f(r, g, b); } FORCEINLINE void CMeshBuilder::Specular3fv(const float* rgb) { m_VertexBuilder.Specular3fv(rgb); } FORCEINLINE void CMeshBuilder::Specular4f(float r, float g, float b, float a) { m_VertexBuilder.Specular4f(r, g, b, a); } FORCEINLINE void CMeshBuilder::Specular4fv(const float* rgba) { m_VertexBuilder.Specular4fv(rgba); } FORCEINLINE void CMeshBuilder::Specular3ub(unsigned char r, unsigned char g, unsigned char b) { m_VertexBuilder.Specular3ub(r, g, b); } FORCEINLINE void CMeshBuilder::Specular3ubv(unsigned char const* c) { m_VertexBuilder.Specular3ubv(c); } FORCEINLINE void CMeshBuilder::Specular4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { m_VertexBuilder.Specular4ub(r, g, b, a); } FORCEINLINE void CMeshBuilder::Specular4ubv(unsigned char const* c) { m_VertexBuilder.Specular4ubv(c); } FORCEINLINE void CMeshBuilder::TexCoord1f(int nStage, float s) { m_VertexBuilder.TexCoord1f(nStage, s); } FORCEINLINE void CMeshBuilder::TexCoord2f(int nStage, float s, float t) { m_VertexBuilder.TexCoord2f(nStage, s, t); } FORCEINLINE void CMeshBuilder::TexCoord2fv(int nStage, const float* st) { m_VertexBuilder.TexCoord2fv(nStage, st); } FORCEINLINE void CMeshBuilder::TexCoord3f(int nStage, float s, float t, float u) { m_VertexBuilder.TexCoord3f(nStage, s, t, u); } FORCEINLINE void CMeshBuilder::TexCoord3fv(int nStage, const float* stu) { m_VertexBuilder.TexCoord3fv(nStage, stu); } FORCEINLINE void CMeshBuilder::TexCoord4f(int nStage, float s, float t, float u, float v) { m_VertexBuilder.TexCoord4f(nStage, s, t, u, v); } FORCEINLINE void CMeshBuilder::TexCoord4fv(int nStage, const float* stuv) { m_VertexBuilder.TexCoord4fv(nStage, stuv); } FORCEINLINE void CMeshBuilder::TexCoordSubRect2f(int nStage, float s, float t, float offsetS, float offsetT, float scaleS, float scaleT) { m_VertexBuilder.TexCoordSubRect2f(nStage, s, t, offsetS, offsetT, scaleS, scaleT); } FORCEINLINE void CMeshBuilder::TexCoordSubRect2fv(int nStage, const float* st, const float* offset, const float* scale) { m_VertexBuilder.TexCoordSubRect2fv(nStage, st, offset, scale); } FORCEINLINE void CMeshBuilder::TangentS3f(float sx, float sy, float sz) { m_VertexBuilder.TangentS3f(sx, sy, sz); } FORCEINLINE void CMeshBuilder::TangentS3fv(const float* s) { m_VertexBuilder.TangentS3fv(s); } FORCEINLINE void CMeshBuilder::TangentT3f(float tx, float ty, float tz) { m_VertexBuilder.TangentT3f(tx, ty, tz); } FORCEINLINE void CMeshBuilder::TangentT3fv(const float* t) { m_VertexBuilder.TangentT3fv(t); } FORCEINLINE void CMeshBuilder::Wrinkle1f(float flWrinkle) { m_VertexBuilder.Wrinkle1f(flWrinkle); } FORCEINLINE void CMeshBuilder::BoneWeight(int nIndex, float flWeight) { m_VertexBuilder.BoneWeight(nIndex, flWeight); } FORCEINLINE void CMeshBuilder::BoneWeights2(float weight1, float weight2) { m_VertexBuilder.BoneWeights2(weight1, weight2); } template FORCEINLINE void CMeshBuilder::CompressedBoneWeight3fv(const float* pWeights) { m_VertexBuilder.CompressedBoneWeight3fv(pWeights); } FORCEINLINE void CMeshBuilder::BoneMatrix(int nIndex, int nMatrixIdx) { m_VertexBuilder.BoneMatrix(nIndex, nMatrixIdx); } FORCEINLINE void CMeshBuilder::BoneMatrices4(int matrixIdx0, int matrixIdx1, int matrixIdx2, int matrixIdx3) { m_VertexBuilder.BoneMatrices4(matrixIdx0, matrixIdx1, matrixIdx2, matrixIdx3); } FORCEINLINE void CMeshBuilder::UserData(const float* pData) { m_VertexBuilder.UserData(pData); } template FORCEINLINE void CMeshBuilder::CompressedUserData(const float* pData) { m_VertexBuilder.CompressedUserData(pData); } template FORCEINLINE void CMeshBuilder::CompressedNormal3f(float nx, float ny, float nz) { m_VertexBuilder.CompressedNormal3f(nx, ny, nz); } template FORCEINLINE void CMeshBuilder::CompressedNormal3fv(const float* n) { m_VertexBuilder.CompressedNormal3fv(n); } #endif