2020-04-22 16:56:21 +00:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//===========================================================================//
# ifndef IMESH_H
# define IMESH_H
# ifdef _WIN32
# pragma once
# endif
# include "tier1/interface.h"
# include "materialsystem/imaterial.h"
# include <float.h>
# include <string.h>
# include "tier0/dbg.h"
# include "tier2/meshutils.h"
# include "mathlib/mathlib.h"
# if defined( DX_TO_GL_ABSTRACTION )
// Swap these so that we do color swapping on 10.6.2, which doesn't have EXT_vertex_array_bgra
# define OPENGL_SWAP_COLORS
# endif
//-----------------------------------------------------------------------------
// forward declarations
//-----------------------------------------------------------------------------
class IMaterial ;
class CMeshBuilder ;
class IMaterialVar ;
typedef uint64 VertexFormat_t ;
//-----------------------------------------------------------------------------
// Define this to find write-combine problems
//-----------------------------------------------------------------------------
# ifdef _DEBUG
//#ifndef DEBUG_WRITE_COMBINE
//#define DEBUG_WRITE_COMBINE 1
//#endif
# endif
//-----------------------------------------------------------------------------
// The Vertex Buffer interface
//-----------------------------------------------------------------------------
enum
{
VERTEX_MAX_TEXTURE_COORDINATES = 8 ,
BONE_MATRIX_INDEX_INVALID = 255
} ;
// Internal maximums for sizes. Don't use directly, use IMaterialSystem::GetMaxToRender()
enum
{
INDEX_BUFFER_SIZE = 32768 ,
DYNAMIC_VERTEX_BUFFER_MEMORY = ( 1024 + 512 ) * 1024 ,
DYNAMIC_VERTEX_BUFFER_MEMORY_SMALL = 384 * 1024 , // Only allocate this much during map transitions
} ;
// Vertex fields must be written in well-defined order to achieve write combining,
// which is a perf booster
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
{
// These can be set to zero if there are pointers to dummy buffers, when the
// actual buffer format doesn't contain the data but it needs to be safe to
// use all the CMeshBuilder functions.
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 ; // Size of the vertices.. Some of the m_VertexSize_ elements above
// are set to this value and some are set to zero depending on which
// fields exist in a buffer's vertex format.
// The type of compression applied to this vertex data
VertexCompressionType_t m_CompressionType ;
// Number of bone weights per vertex...
int m_NumBoneWeights ;
// Pointers to our current vertex data
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 ] ;
// Tangent space *associated with one particular set of texcoords*
float * m_pTangentS ;
float * m_pTangentT ;
float * m_pWrinkle ;
// user data
float * m_pUserData ;
// The first vertex index (used for buffered vertex buffers, or cards that don't support stream offset)
int m_nFirstVertex ;
// The offset in bytes of the memory we're writing into
// from the start of the D3D buffer (will be 0 for static meshes)
unsigned int m_nOffset ;
# ifdef DEBUG_WRITE_COMBINE
int m_nLastWrittenField ;
unsigned char * m_pLastWrittenAddress ;
# endif
} ;
struct IndexDesc_t
{
// Pointers to the index data
unsigned short * m_pIndices ;
// The offset in bytes of the memory we're writing into
// from the start of the D3D buffer (will be 0 for static meshes)
unsigned int m_nOffset ;
// The first index (used for buffered index buffers, or cards that don't support stream offset)
unsigned int m_nFirstIndex ;
// 1 if the device is active, 0 if the device isn't active.
// Faster than doing if checks for null m_pIndices if someone is
// trying to write the m_pIndices while the device is inactive.
unsigned char m_nIndexSize ;
} ;
//-----------------------------------------------------------------------------
// The Mesh memory descriptor
//-----------------------------------------------------------------------------
struct MeshDesc_t : public VertexDesc_t , public IndexDesc_t
{
} ;
//-----------------------------------------------------------------------------
// Standard vertex formats for models
//-----------------------------------------------------------------------------
struct ModelVertexDX7_t
{
Vector m_vecPosition ;
Vector2D m_flBoneWeights ;
unsigned int m_nBoneIndices ;
Vector m_vecNormal ;
unsigned int m_nColor ; // ARGB
Vector2D m_vecTexCoord ;
} ;
struct ModelVertexDX8_t : public ModelVertexDX7_t
{
Vector4D m_vecUserData ;
} ;
//-----------------------------------------------------------------------------
// Utility methods for buffer builders
//-----------------------------------------------------------------------------
inline float * OffsetFloatPointer ( float * pBufferPointer , int nVertexCount , int vertexSize )
{
return reinterpret_cast < float * > (
reinterpret_cast < unsigned char * > ( pBufferPointer ) +
nVertexCount * vertexSize ) ;
}
inline const float * OffsetFloatPointer ( const float * pBufferPointer , int nVertexCount , int vertexSize )
{
return reinterpret_cast < const float * > (
reinterpret_cast < unsigned char const * > ( pBufferPointer ) +
nVertexCount * vertexSize ) ;
}
inline void IncrementFloatPointer ( float * & pBufferPointer , int vertexSize )
{
pBufferPointer = reinterpret_cast < float * > ( reinterpret_cast < unsigned char * > ( pBufferPointer ) + vertexSize ) ;
}
//-----------------------------------------------------------------------------
// Used in lists of indexed primitives.
//-----------------------------------------------------------------------------
class CPrimList
{
public :
2022-11-05 11:22:27 +00:00
CPrimList ( ) = default ;
2020-04-22 16:56:21 +00:00
CPrimList ( int nFirstIndex , int nIndexCount ) ;
int m_FirstIndex ;
int m_NumIndices ;
} ;
inline CPrimList : : CPrimList ( int nFirstIndex , int nIndexCount )
{
m_FirstIndex = nFirstIndex ;
m_NumIndices = nIndexCount ;
}
abstract_class IVertexBuffer
{
public :
// Add a virtual destructor to silence the clang warning.
// This is harmless but not important since the only derived class
// doesn't have a destructor.
virtual ~ IVertexBuffer ( ) { }
// NOTE: The following two methods are only valid for static vertex buffers
// Returns the number of vertices and the format of the vertex buffer
virtual int VertexCount ( ) const = 0 ;
virtual VertexFormat_t GetVertexFormat ( ) const = 0 ;
// Is this vertex buffer dynamic?
virtual bool IsDynamic ( ) const = 0 ;
// NOTE: For dynamic vertex buffers only!
// Casts the memory of the dynamic vertex buffer to the appropriate type
virtual void BeginCastBuffer ( VertexFormat_t format ) = 0 ;
virtual void EndCastBuffer ( ) = 0 ;
// Returns the number of vertices that can still be written into the buffer
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 ;
// Spews the mesh data
virtual void Spew ( int nVertexCount , const VertexDesc_t & desc ) = 0 ;
// Call this in debug mode to make sure our data is good.
virtual void ValidateData ( int nVertexCount , const VertexDesc_t & desc ) = 0 ;
} ;
abstract_class IIndexBuffer
{
public :
// Add a virtual destructor to silence the clang warning.
// This is harmless but not important since the only derived class
// doesn't have a destructor.
virtual ~ IIndexBuffer ( ) { }
// NOTE: The following two methods are only valid for static index buffers
// Returns the number of indices and the format of the index buffer
virtual int IndexCount ( ) const = 0 ;
virtual MaterialIndexFormat_t IndexFormat ( ) const = 0 ;
// Is this index buffer dynamic?
virtual bool IsDynamic ( ) const = 0 ;
// NOTE: For dynamic index buffers only!
// Casts the memory of the dynamic index buffer to the appropriate type
virtual void BeginCastBuffer ( MaterialIndexFormat_t format ) = 0 ;
virtual void EndCastBuffer ( ) = 0 ;
// Returns the number of indices that can still be written into the buffer
virtual int GetRoomRemaining ( ) const = 0 ;
// Locks, unlocks the index buffer
virtual bool Lock ( int nMaxIndexCount , bool bAppend , IndexDesc_t & desc ) = 0 ;
virtual void Unlock ( int nWrittenIndexCount , IndexDesc_t & desc ) = 0 ;
// FIXME: Remove this!!
// Locks, unlocks the index buffer for modify
virtual void ModifyBegin ( bool bReadOnly , int nFirstIndex , int nIndexCount , IndexDesc_t & desc ) = 0 ;
virtual void ModifyEnd ( IndexDesc_t & desc ) = 0 ;
// Spews the mesh data
virtual void Spew ( int nIndexCount , const IndexDesc_t & desc ) = 0 ;
// Ensures the data in the index buffer is valid
virtual void ValidateData ( int nIndexCount , const IndexDesc_t & desc ) = 0 ;
} ;
//-----------------------------------------------------------------------------
// Interface to the mesh - needs to contain an IVertexBuffer and an IIndexBuffer to emulate old mesh behavior
//-----------------------------------------------------------------------------
abstract_class IMesh : public IVertexBuffer , public IIndexBuffer
{
public :
// -----------------------------------
// Sets/gets the primitive type
virtual void SetPrimitiveType ( MaterialPrimitiveType_t type ) = 0 ;
// Draws the mesh
virtual void Draw ( int nFirstIndex = - 1 , int nIndexCount = 0 ) = 0 ;
virtual void SetColorMesh ( IMesh * pColorMesh , int nVertexOffset ) = 0 ;
// Draw a list of (lists of) primitives. Batching your lists together that use
// the same lightmap, material, vertex and index buffers with multipass shaders
// can drastically reduce state-switching overhead.
// NOTE: this only works with STATIC meshes.
virtual void Draw ( CPrimList * pLists , int nLists ) = 0 ;
// Copy verts and/or indices to a mesh builder. This only works for temp meshes!
virtual void CopyToMeshBuilder (
int iStartVert , // Which vertices to copy.
int nVerts ,
int iStartIndex , // Which indices to copy.
int nIndices ,
int indexOffset , // This is added to each index.
CMeshBuilder & builder ) = 0 ;
// Spews the mesh data
virtual void Spew ( int nVertexCount , int nIndexCount , const MeshDesc_t & desc ) = 0 ;
// Call this in debug mode to make sure our data is good.
virtual void ValidateData ( int nVertexCount , int nIndexCount , const MeshDesc_t & desc ) = 0 ;
// New version
// Locks/unlocks the mesh, providing space for nVertexCount and nIndexCount.
// nIndexCount of -1 means don't lock the index buffer...
virtual void LockMesh ( int nVertexCount , int nIndexCount , MeshDesc_t & desc ) = 0 ;
virtual void ModifyBegin ( int nFirstVertex , int nVertexCount , int nFirstIndex , int nIndexCount , MeshDesc_t & desc ) = 0 ;
virtual void ModifyEnd ( MeshDesc_t & desc ) = 0 ;
virtual void UnlockMesh ( int nVertexCount , int nIndexCount , MeshDesc_t & desc ) = 0 ;
virtual void ModifyBeginEx ( bool bReadOnly , int nFirstVertex , int nVertexCount , int nFirstIndex , int nIndexCount , MeshDesc_t & desc ) = 0 ;
virtual void SetFlexMesh ( IMesh * pMesh , int nVertexOffset ) = 0 ;
virtual void DisableFlexMesh ( ) = 0 ;
virtual void MarkAsDrawn ( ) = 0 ;
virtual unsigned ComputeMemoryUsed ( ) = 0 ;
} ;
# include "meshreader.h"
# define INVALID_BUFFER_OFFSET 0xFFFFFFFFUL
// flags for advancevertex optimization
# define VTX_HAVEPOS 1
# define VTX_HAVENORMAL 2
# define VTX_HAVECOLOR 4
# define VTX_HAVEALL ( VTX_HAVEPOS | VTX_HAVENORMAL | VTX_HAVECOLOR )
//-----------------------------------------------------------------------------
//
// Helper class used to define vertex buffers
//
//-----------------------------------------------------------------------------
class CVertexBuilder : private VertexDesc_t
{
public :
CVertexBuilder ( ) ;
CVertexBuilder ( IVertexBuffer * pVertexBuffer , VertexFormat_t fmt = 0 ) ;
~ CVertexBuilder ( ) ;
// Begins, ends modification of the index buffer (returns true if the lock succeeded)
// A lock may not succeed if append is set to true and there isn't enough room
// NOTE: Append is only used with dynamic index buffers; it's ignored for static buffers
bool Lock ( int nMaxIndexCount , bool bAppend = false ) ;
void Unlock ( ) ;
// Spews the current data
// NOTE: Can only be called during a lock/unlock block
void SpewData ( ) ;
// Returns the number of indices we can fit into the buffer without needing to discard
int GetRoomRemaining ( ) const ;
// Binds this vertex buffer
void Bind ( IMatRenderContext * pContext , int nStreamID , VertexFormat_t usage = 0 ) ;
// Returns the byte offset
int Offset ( ) const ;
// This must be called before Begin, if a vertex buffer with a compressed format is to be used
void SetCompressionType ( VertexCompressionType_t compressionType ) ;
void ValidateCompressionType ( ) ;
void Begin ( IVertexBuffer * pVertexBuffer , int nVertexCount , int * nFirstVertex ) ;
void Begin ( IVertexBuffer * pVertexBuffer , int nVertexCount ) ;
// Use this when you're done writing
// Set bDraw to true to call m_pMesh->Draw automatically.
void End ( bool bSpewData = false ) ;
// Locks the vertex buffer to modify existing data
// Passing nVertexCount == -1 says to lock all the vertices for modification.
void BeginModify ( IVertexBuffer * pVertexBuffer , int nFirstVertex = 0 , int nVertexCount = - 1 ) ;
void EndModify ( bool bSpewData = false ) ;
// returns the number of vertices
int VertexCount ( ) const ;
// Returns the total number of vertices across all Locks()
int TotalVertexCount ( ) const ;
// Resets the mesh builder so it points to the start of everything again
void Reset ( ) ;
// Returns the size of the vertex
int VertexSize ( ) { return m_ActualVertexSize ; }
// returns the data size of a given texture coordinate
int TextureCoordinateSize ( int nTexCoordNumber ) { return m_VertexSize_TexCoord [ nTexCoordNumber ] ; }
// Returns the base vertex memory pointer
void * BaseVertexData ( ) ;
// Selects the nth Vertex and Index
void SelectVertex ( int idx ) ;
// Advances the current vertex and index by one
void AdvanceVertex ( void ) ;
template < int nFlags , int nNumTexCoords > void AdvanceVertexF ( void ) ;
void AdvanceVertices ( int nVerts ) ;
int GetCurrentVertex ( ) const ;
int GetFirstVertex ( ) const ;
// Data retrieval...
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
// position setting
void Position3f ( float x , float y , float z ) ;
void Position3fv ( const float * v ) ;
// normal setting
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 ) ;
// normal setting (templatized for code which needs to support compressed vertices)
template < VertexCompressionType_t T > void CompressedNormal3f ( float nx , float ny , float nz ) ;
template < VertexCompressionType_t T > void CompressedNormal3fv ( const float * n ) ;
// color setting
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 ) ;
// Faster versions of color
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 ) ;
// specular color setting
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 ) ;
// Faster version of specular
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 ) ;
// texture coordinate setting
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 ) ;
// tangent space
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 ) ;
// Wrinkle
void Wrinkle1f ( float flWrinkle ) ;
// bone weights
void BoneWeight ( int idx , float weight ) ;
// bone weights (templatized for code which needs to support compressed vertices)
template < VertexCompressionType_t T > void CompressedBoneWeight3fv ( const float * pWeights ) ;
// bone matrix index
void BoneMatrix ( int idx , int matrixIndex ) ;
// Generic per-vertex data
void UserData ( const float * pData ) ;
// Generic per-vertex data (templatized for code which needs to support compressed vertices)
template < VertexCompressionType_t T > void CompressedUserData ( const float * pData ) ;
// Fast Vertex! No need to call advance vertex, and no random access allowed.
// WARNING - these are low level functions that are intended only for use
// in the software vertex skinner.
void FastVertex ( const ModelVertexDX7_t & vertex ) ;
void FastVertexSSE ( const ModelVertexDX7_t & vertex ) ;
// store 4 dx7 vertices fast. for special sse dx7 pipeline
void Fast4VerticesSSE (
ModelVertexDX7_t const * vtx_a ,
ModelVertexDX7_t const * vtx_b ,
ModelVertexDX7_t const * vtx_c ,
ModelVertexDX7_t const * vtx_d ) ;
void FastVertex ( const ModelVertexDX8_t & vertex ) ;
void FastVertexSSE ( const ModelVertexDX8_t & vertex ) ;
// Add number of verts and current vert since FastVertex routines do not update.
void FastAdvanceNVertices ( int n ) ;
# if defined( _X360 )
void VertexDX8ToX360 ( const ModelVertexDX8_t & vertex ) ;
# endif
// FIXME: Remove! Backward compat so we can use this from a CMeshBuilder.
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 :
// The vertex buffer we're modifying
IVertexBuffer * m_pVertexBuffer ;
// Used to make sure Begin/End calls and BeginModify/EndModify calls match.
bool m_bModify ;
// Max number of indices and vertices
int m_nMaxVertexCount ;
// Number of indices and vertices
int m_nVertexCount ;
// The current vertex and index
mutable int m_nCurrentVertex ;
// Optimization: Pointer to the current pos, norm, texcoord, and color
mutable float * m_pCurrPosition ;
mutable float * m_pCurrNormal ;
mutable float * m_pCurrTexCoord [ VERTEX_MAX_TEXTURE_COORDINATES ] ;
mutable unsigned char * m_pCurrColor ;
// Total number of vertices appended
int m_nTotalVertexCount ;
// First vertex buffer offset + index
unsigned int m_nBufferOffset ;
unsigned int m_nBufferFirstVertex ;
# if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 )
// Debug checks to make sure we write userdata4/tangents AFTER normals
bool m_bWrittenNormal : 1 ;
bool m_bWrittenUserData : 1 ;
# endif
friend class CMeshBuilder ;
} ;
//-----------------------------------------------------------------------------
//
// Inline methods of CVertexBuilder
//
//-----------------------------------------------------------------------------
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 ( ) ;
}
}
//-----------------------------------------------------------------------------
// Begins, ends modification of the index buffer
//-----------------------------------------------------------------------------
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 ;
}
// Lock the vertex buffer
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
// Null out our data...
m_pCurrPosition = NULL ;
m_pCurrNormal = NULL ;
m_pCurrColor = NULL ;
memset ( m_pCurrTexCoord , 0 , sizeof ( m_pCurrTexCoord ) ) ;
memset ( static_cast < VertexDesc_t * > ( this ) , 0 , sizeof ( VertexDesc_t ) ) ;
# endif
}
inline void CVertexBuilder : : SpewData ( )
{
m_pVertexBuffer - > Spew ( m_nVertexCount , * this ) ;
}
//-----------------------------------------------------------------------------
// Binds this vertex buffer
//-----------------------------------------------------------------------------
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 ) ;
}
}
//-----------------------------------------------------------------------------
// Returns the byte offset
//-----------------------------------------------------------------------------
inline int CVertexBuilder : : Offset ( ) const
{
return m_nBufferOffset ;
}
inline int CVertexBuilder : : GetFirstVertex ( ) const
{
return m_nBufferFirstVertex ;
}
//-----------------------------------------------------------------------------
// Specify the type of vertex compression that this CMeshBuilder will perform
//-----------------------------------------------------------------------------
inline void CVertexBuilder : : SetCompressionType ( VertexCompressionType_t compressionType )
{
// The real purpose of this method is to allow us to emit a Warning in Begin()
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 " ) ;
}
// Never use vertex compression for dynamic VBs (the conversions can really hurt perf)
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 ;
// Make sure SetCompressionType was called correctly, if this VB is compressed
ValidateCompressionType ( ) ;
// Lock the vertex and index buffer
m_pVertexBuffer - > Lock ( m_nMaxVertexCount , false , * this ) ;
// Point to the start of the buffers..
Reset ( ) ;
}
//-----------------------------------------------------------------------------
// Use this when you're done modifying the mesh
//-----------------------------------------------------------------------------
inline void CVertexBuilder : : End ( bool bSpewData )
{
// Make sure they called Begin()
Assert ( ! m_bModify ) ;
if ( bSpewData )
{
m_pVertexBuffer - > Spew ( m_nVertexCount , * this ) ;
}
# ifdef _DEBUG
m_pVertexBuffer - > ValidateData ( m_nVertexCount , * this ) ;
# endif
// Unlock our buffers
m_pVertexBuffer - > Unlock ( m_nVertexCount , * this ) ;
m_pVertexBuffer = 0 ;
m_nMaxVertexCount = 0 ;
m_CompressionType = VERTEX_COMPRESSION_INVALID ;
# ifdef _DEBUG
// Null out our pointers...
m_pCurrPosition = NULL ;
m_pCurrNormal = NULL ;
m_pCurrColor = NULL ;
memset ( m_pCurrTexCoord , 0 , sizeof ( m_pCurrTexCoord ) ) ;
memset ( static_cast < VertexDesc_t * > ( this ) , 0 , sizeof ( VertexDesc_t ) ) ;
# endif
}
//-----------------------------------------------------------------------------
// FIXME: Remove! Backward compat so we can use this from a CMeshBuilder.
//-----------------------------------------------------------------------------
inline void CVertexBuilder : : AttachBegin ( IMesh * pMesh , int nMaxVertexCount , const MeshDesc_t & desc )
{
VertexCompressionType_t compressionType = m_CompressionType ;
m_pVertexBuffer = pMesh ;
memcpy ( static_cast < VertexDesc_t * > ( this ) , static_cast < const VertexDesc_t * > ( & desc ) , sizeof ( VertexDesc_t ) ) ;
m_nMaxVertexCount = nMaxVertexCount ;
m_NumBoneWeights = m_NumBoneWeights = = 0 ? 0 : 2 ; // Two weights if any
m_nVertexCount = 0 ;
m_bModify = false ;
if ( compressionType ! = VERTEX_COMPRESSION_INVALID )
m_CompressionType = compressionType ;
// Make sure SetCompressionType was called correctly, if this VB is compressed
ValidateCompressionType ( ) ;
if ( m_nBufferOffset = = INVALID_BUFFER_OFFSET )
{
m_nTotalVertexCount = 0 ;
m_nBufferOffset = static_cast < const VertexDesc_t * > ( & desc ) - > m_nOffset ;
m_nBufferFirstVertex = desc . m_nFirstVertex ;
}
}
inline void CVertexBuilder : : AttachEnd ( )
{
// Make sure they called Begin()
Assert ( ! m_bModify ) ;
m_nMaxVertexCount = 0 ;
m_pVertexBuffer = NULL ;
m_CompressionType = VERTEX_COMPRESSION_INVALID ;
# ifdef _DEBUG
// Null out our pointers...
m_pCurrPosition = NULL ;
m_pCurrNormal = NULL ;
m_pCurrColor = NULL ;
memset ( m_pCurrTexCoord , 0 , sizeof ( m_pCurrTexCoord ) ) ;
memset ( static_cast < VertexDesc_t * > ( 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 < VertexDesc_t * > ( this ) , static_cast < const VertexDesc_t * > ( & desc ) , sizeof ( VertexDesc_t ) ) ;
m_nMaxVertexCount = m_nVertexCount = nVertexCount ;
m_NumBoneWeights = m_NumBoneWeights = = 0 ? 0 : 2 ; // Two weights if any
m_bModify = true ;
// Make sure SetCompressionType was called correctly, if this VB is compressed
ValidateCompressionType ( ) ;
}
inline void CVertexBuilder : : AttachEndModify ( )
{
Assert ( m_pVertexBuffer ) ;
Assert ( m_bModify ) ; // Make sure they called BeginModify.
m_pVertexBuffer = 0 ;
m_nMaxVertexCount = 0 ;
m_CompressionType = VERTEX_COMPRESSION_INVALID ;
# ifdef _DEBUG
// Null out our pointers...
m_pCurrPosition = NULL ;
m_pCurrNormal = NULL ;
m_pCurrColor = NULL ;
memset ( m_pCurrTexCoord , 0 , sizeof ( m_pCurrTexCoord ) ) ;
memset ( static_cast < VertexDesc_t * > ( this ) , 0 , sizeof ( VertexDesc_t ) ) ;
# endif
}
//-----------------------------------------------------------------------------
// Computes the first min non-null address
//-----------------------------------------------------------------------------
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 ;
}
//-----------------------------------------------------------------------------
// Resets the vertex buffer builder so it points to the start of everything again
//-----------------------------------------------------------------------------
inline void CVertexBuilder : : Reset ( )
{
m_nCurrentVertex = 0 ;
m_pCurrPosition = m_pPosition ;
m_pCurrNormal = m_pNormal ;
for ( int 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
// Logic for m_pLastWrittenAddress is tricky. It really wants the min of the
// non-null address pointers.
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
}
//-----------------------------------------------------------------------------
// returns the number of vertices
//-----------------------------------------------------------------------------
inline int CVertexBuilder : : VertexCount ( ) const
{
return m_nVertexCount ;
}
//-----------------------------------------------------------------------------
// Returns the total number of vertices across all Locks()
//-----------------------------------------------------------------------------
inline int CVertexBuilder : : TotalVertexCount ( ) const
{
return m_nTotalVertexCount ;
}
//-----------------------------------------------------------------------------
// Returns the base vertex memory pointer
//-----------------------------------------------------------------------------
inline void * CVertexBuilder : : BaseVertexData ( )
{
// FIXME: If there's no position specified, we need to find
// the base address
Assert ( m_pPosition ) ;
return m_pPosition ;
}
//-----------------------------------------------------------------------------
// Selects the current vertex
//-----------------------------------------------------------------------------
inline void CVertexBuilder : : SelectVertex ( int nIndex )
{
// NOTE: This index is expected to be relative
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
}
//-----------------------------------------------------------------------------
// Advances vertex after you're done writing to it.
//-----------------------------------------------------------------------------
template < int nFlags , int nNumTexCoords > 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 < VTX_HAVEALL , 8 > ( ) ;
}
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
}
//-----------------------------------------------------------------------------
// For use with the FastVertex methods, advances the current vertex by N
//-----------------------------------------------------------------------------
inline void CVertexBuilder : : FastAdvanceNVertices ( int n )
{
m_nCurrentVertex + = n ;
m_nVertexCount = m_nCurrentVertex ;
}
2022-07-28 11:27:56 +00:00
// #ifndef COMPILER_MSVC64
2020-04-22 16:56:21 +00:00
// Implement for 64-bit Windows if needed.
//-----------------------------------------------------------------------------
// Fast Vertex! No need to call advance vertex, and no random access allowed
//-----------------------------------------------------------------------------
inline void CVertexBuilder : : FastVertex ( const ModelVertexDX7_t & vertex )
{
2022-07-28 11:27:56 +00:00
# if defined(__arm__) || defined(__aarch64__) || defined(PLATFORM_WINDOWS_PC64)
2021-04-25 20:36:09 +00:00
FastVertexSSE ( vertex ) ;
# else
2020-04-22 16:56:21 +00:00
Assert ( m_CompressionType = = VERTEX_COMPRESSION_NONE ) ; // FIXME: support compressed verts if needed
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 "
" 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 "
" emms \n "
: : " r " ( pRead ) , " r " ( pCurrPos ) : " memory " ) ;
# else
Error ( " Implement CMeshBuilder::FastVertex(dx7) " ) ;
# endif
IncrementFloatPointer ( m_pCurrPosition , m_VertexSize_Position ) ;
//m_nVertexCount = ++m_nCurrentVertex;
# if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) )
m_bWrittenNormal = false ;
m_bWrittenUserData = false ;
# endif
2021-04-25 20:36:09 +00:00
# endif
2020-04-22 16:56:21 +00:00
}
inline void CVertexBuilder : : FastVertexSSE ( const ModelVertexDX7_t & vertex )
{
Assert ( m_CompressionType = = VERTEX_COMPRESSION_NONE ) ; // FIXME: support compressed verts if needed
Assert ( m_nCurrentVertex < m_nMaxVertexCount ) ;
2022-07-28 11:27:56 +00:00
# if defined( _WIN32 ) && !defined( _X360 ) && !defined( PLATFORM_64BITS )
2020-04-22 16:56:21 +00:00
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
}
2022-07-28 11:27:56 +00:00
# elif defined(GNUC) || defined(PLATFORM_WINDOWS_PC64)
2020-04-22 16:56:21 +00:00
const char * pRead = ( char * ) & vertex ;
char * pCurrPos = ( char * ) m_pCurrPosition ;
__m128 m1 = _mm_load_ps ( ( float * ) pRead ) ;
2022-02-23 11:50:30 +00:00
__m128 m2 = _mm_load_ps ( ( float * ) ( ( intp ) pRead + 16 ) ) ;
__m128 m3 = _mm_load_ps ( ( float * ) ( ( intp ) pRead + 32 ) ) ;
2020-04-22 16:56:21 +00:00
_mm_stream_ps ( ( float * ) pCurrPos , m1 ) ;
2022-02-23 11:50:30 +00:00
_mm_stream_ps ( ( float * ) ( ( intp ) pCurrPos + 16 ) , m2 ) ;
_mm_stream_ps ( ( float * ) ( ( intp ) pCurrPos + 32 ) , m3 ) ;
2020-04-22 16:56:21 +00:00
# else
Error ( " Implement CMeshBuilder::FastVertexSSE(dx7) " ) ;
# endif
IncrementFloatPointer ( m_pCurrPosition , m_VertexSize_Position ) ;
//m_nVertexCount = ++m_nCurrentVertex;
# if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) )
m_bWrittenNormal = false ;
m_bWrittenUserData = false ;
# endif
}
inline void CVertexBuilder : : Fast4VerticesSSE (
ModelVertexDX7_t const * vtx_a ,
ModelVertexDX7_t const * vtx_b ,
ModelVertexDX7_t const * vtx_c ,
ModelVertexDX7_t const * vtx_d )
{
Assert ( m_CompressionType = = VERTEX_COMPRESSION_NONE ) ; // FIXME: support compressed verts if needed
Assert ( m_nCurrentVertex < m_nMaxVertexCount - 3 ) ;
2022-07-28 11:27:56 +00:00
# if defined( _WIN32 ) && !defined( _X360 ) && !defined( PLATFORM_64BITS )
2020-04-22 16:56:21 +00:00
void * pCurrPos = m_pCurrPosition ;
__asm
{
mov esi , vtx_a
mov ecx , vtx_b
mov edi , pCurrPos
nop
movaps xmm0 , [ esi + 0 ]
movaps xmm1 , [ esi + 16 ]
movaps xmm2 , [ esi + 32 ]
movaps xmm3 , [ ecx + 0 ]
movaps xmm4 , [ ecx + 16 ]
movaps xmm5 , [ ecx + 32 ]
mov esi , vtx_c
mov ecx , vtx_d
movntps [ edi + 0 ] , xmm0
movntps [ edi + 16 ] , xmm1
movntps [ edi + 32 ] , xmm2
movntps [ edi + 48 ] , xmm3
movntps [ edi + 64 ] , xmm4
movntps [ edi + 80 ] , xmm5
movaps xmm0 , [ esi + 0 ]
movaps xmm1 , [ esi + 16 ]
movaps xmm2 , [ esi + 32 ]
movaps xmm3 , [ ecx + 0 ]
movaps xmm4 , [ ecx + 16 ]
movaps xmm5 , [ ecx + 32 ]
movntps [ edi + 0 + 96 ] , xmm0
movntps [ edi + 16 + 96 ] , xmm1
movntps [ edi + 32 + 96 ] , xmm2
movntps [ edi + 48 + 96 ] , xmm3
movntps [ edi + 64 + 96 ] , xmm4
movntps [ edi + 80 + 96 ] , xmm5
}
2022-07-28 11:27:56 +00:00
# elif defined(__arm__) || defined(PLATFORM_WINDOWS_PC64)
const void * pReadA = & vtx_a ;
const void * pReadB = & vtx_b ;
const void * pReadC = & vtx_c ;
const void * pReadD = & vtx_d ;
void * pCurrPos = m_pCurrPosition ;
__m128 m1 = _mm_load_ps ( ( float * ) pReadA ) ;
__m128 m2 = _mm_load_ps ( ( float * ) ( ( intp ) pReadA + 16 ) ) ;
__m128 m3 = _mm_load_ps ( ( float * ) ( ( intp ) pReadA + 32 ) ) ;
__m128 m4 = _mm_load_ps ( ( float * ) pReadB ) ;
__m128 m5 = _mm_load_ps ( ( float * ) ( ( intp ) pReadB + 16 ) ) ;
__m128 m6 = _mm_load_ps ( ( float * ) ( ( intp ) pReadB + 32 ) ) ;
_mm_stream_ps ( ( float * ) pCurrPos , m1 ) ;
_mm_stream_ps ( ( float * ) ( ( intp ) pCurrPos + 16 ) , m2 ) ;
_mm_stream_ps ( ( float * ) ( ( intp ) pCurrPos + 32 ) , m3 ) ;
_mm_stream_ps ( ( float * ) ( ( intp ) pCurrPos + 48 ) , m4 ) ;
_mm_stream_ps ( ( float * ) ( ( intp ) pCurrPos + 64 ) , m5 ) ;
_mm_stream_ps ( ( float * ) ( ( intp ) pCurrPos + 80 ) , m6 ) ;
m1 = _mm_load_ps ( ( float * ) pReadC ) ;
m2 = _mm_load_ps ( ( float * ) ( ( intp ) pReadC + 16 ) ) ;
m3 = _mm_load_ps ( ( float * ) ( ( intp ) pReadC + 32 ) ) ;
m4 = _mm_load_ps ( ( float * ) pReadD ) ;
m5 = _mm_load_ps ( ( float * ) ( ( intp ) pReadD + 16 ) ) ;
m6 = _mm_load_ps ( ( float * ) ( ( intp ) pReadD + 32 ) ) ;
_mm_stream_ps ( ( float * ) ( ( intp ) pCurrPos + 0 + 96 ) , m1 ) ;
_mm_stream_ps ( ( float * ) ( ( intp ) pCurrPos + 16 + 96 ) , m2 ) ;
_mm_stream_ps ( ( float * ) ( ( intp ) pCurrPos + 32 + 96 ) , m3 ) ;
_mm_stream_ps ( ( float * ) ( ( intp ) pCurrPos + 48 + 96 ) , m4 ) ;
_mm_stream_ps ( ( float * ) ( ( intp ) pCurrPos + 64 + 96 ) , m5 ) ;
_mm_stream_ps ( ( float * ) ( ( intp ) pCurrPos + 80 + 96 ) , m6 ) ;
2020-04-22 16:56:21 +00:00
# else
Error ( " Implement CMeshBuilder::Fast4VerticesSSE \n " ) ;
# endif
IncrementFloatPointer ( m_pCurrPosition , 4 * m_VertexSize_Position ) ;
# if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) )
m_bWrittenNormal = false ;
m_bWrittenUserData = false ;
# endif
}
inline void CVertexBuilder : : FastVertex ( const ModelVertexDX8_t & vertex )
{
2022-07-28 11:27:56 +00:00
# if defined(__arm__) || defined(__aarch64__) || defined(PLATFORM_WINDOWS_PC64)
2021-04-25 20:36:09 +00:00
FastVertexSSE ( vertex ) ;
# else
2020-04-22 16:56:21 +00:00
Assert ( m_CompressionType = = VERTEX_COMPRESSION_NONE ) ; // FIXME: support compressed verts if needed
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 ]
movq mm6 , [ esi + 48 ]
movq mm7 , [ esi + 56 ]
movntq [ edi + 0 ] , mm0
movntq [ edi + 8 ] , mm1
movntq [ edi + 16 ] , mm2
movntq [ edi + 24 ] , mm3
movntq [ edi + 32 ] , mm4
movntq [ edi + 40 ] , mm5
movntq [ edi + 48 ] , mm6
movntq [ edi + 56 ] , mm7
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 ) ;
// m_nVertexCount = ++m_nCurrentVertex;
# if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) )
m_bWrittenNormal = false ;
m_bWrittenUserData = false ;
# endif
2021-04-25 20:36:09 +00:00
# endif
2020-04-22 16:56:21 +00:00
}
2021-04-25 20:36:09 +00:00
2020-04-22 16:56:21 +00:00
inline void CVertexBuilder : : FastVertexSSE ( const ModelVertexDX8_t & vertex )
{
Assert ( m_CompressionType = = VERTEX_COMPRESSION_NONE ) ; // FIXME: support compressed verts if needed
Assert ( m_nCurrentVertex < m_nMaxVertexCount ) ;
2022-07-28 11:27:56 +00:00
# if defined( _WIN32 ) && !defined( _X360 ) && !defined( PLATFORM_64BITS )
2020-04-22 16:56:21 +00:00
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 ]
movaps xmm3 , [ esi + 48 ]
movntps [ edi + 0 ] , xmm0
movntps [ edi + 16 ] , xmm1
movntps [ edi + 32 ] , xmm2
movntps [ edi + 48 ] , xmm3
}
2022-07-28 11:27:56 +00:00
# elif defined(GNUC) || defined(PLATFORM_WINDOWS_PC64)
2020-04-22 16:56:21 +00:00
const void * pRead = & vertex ;
void * pCurrPos = m_pCurrPosition ;
2021-04-25 20:36:09 +00:00
/* __asm__ __volatile__ (
2020-04-22 16:56:21 +00:00
" 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 "
2021-04-25 20:36:09 +00:00
" movntps %%xmm3, 48(%1) \n "
: : " r " ( pRead ) , " r " ( pCurrPos ) : " memory " ) ; */
__m128 m1 = _mm_load_ps ( ( float * ) pRead ) ;
2022-02-23 11:50:30 +00:00
__m128 m2 = _mm_load_ps ( ( float * ) ( ( intp ) pRead + 16 ) ) ;
__m128 m3 = _mm_load_ps ( ( float * ) ( ( intp ) pRead + 32 ) ) ;
__m128 m4 = _mm_load_ps ( ( float * ) ( ( intp ) pRead + 48 ) ) ;
2021-04-25 20:36:09 +00:00
_mm_stream_ps ( ( float * ) pCurrPos , m1 ) ;
2022-02-23 11:50:30 +00:00
_mm_stream_ps ( ( float * ) ( ( intp ) pCurrPos + 16 ) , m2 ) ;
_mm_stream_ps ( ( float * ) ( ( intp ) pCurrPos + 32 ) , m3 ) ;
_mm_stream_ps ( ( float * ) ( ( intp ) pCurrPos + 48 ) , m4 ) ;
2020-04-22 16:56:21 +00:00
# else
Error ( " Implement CMeshBuilder::FastVertexSSE((dx8) " ) ;
# endif
IncrementFloatPointer ( m_pCurrPosition , m_VertexSize_Position ) ;
// m_nVertexCount = ++m_nCurrentVertex;
# if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) )
m_bWrittenNormal = false ;
m_bWrittenUserData = false ;
# endif
}
2022-07-28 11:27:56 +00:00
// #endif // COMPILER_MSVC64
2020-04-22 16:56:21 +00:00
//-----------------------------------------------------------------------------
// Returns the current vertex
//-----------------------------------------------------------------------------
inline int CVertexBuilder : : GetCurrentVertex ( ) const
{
return m_nCurrentVertex ;
}
//-----------------------------------------------------------------------------
// Copies a vertex into the x360 format
//-----------------------------------------------------------------------------
# if defined( _X360 )
inline void CVertexBuilder : : VertexDX8ToX360 ( const ModelVertexDX8_t & vertex )
{
Assert ( m_CompressionType = = VERTEX_COMPRESSION_NONE ) ; // FIXME: support compressed verts if needed
Assert ( m_nCurrentVertex < m_nMaxVertexCount ) ;
// get the start of the data
unsigned char * pDst = ( unsigned char * ) m_pCurrPosition ;
Assert ( m_VertexSize_Position > 0 ) ; // Assume position is always present
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_BoneWeight )
{
Assert ( vertex . m_flBoneWeights [ 0 ] > = 0 & & vertex . m_flBoneWeights [ 0 ] < = 1.0f ) ;
Assert ( vertex . m_flBoneWeights [ 1 ] > = 0 & & vertex . m_flBoneWeights [ 1 ] < = 1.0f ) ;
Assert ( GetVertexElementSize ( VERTEX_ELEMENT_BONEWEIGHTS2 , VERTEX_COMPRESSION_NONE ) = = sizeof ( vertex . m_flBoneWeights ) ) ;
memcpy ( pDst , vertex . m_flBoneWeights . Base ( ) , sizeof ( vertex . m_flBoneWeights ) ) ;
pDst + = sizeof ( vertex . m_flBoneWeights ) ;
if ( m_VertexSize_BoneMatrixIndex )
{
Assert ( GetVertexElementSize ( VERTEX_ELEMENT_BONEINDEX , VERTEX_COMPRESSION_NONE ) = = sizeof ( vertex . m_nBoneIndices ) ) ;
* ( unsigned int * ) pDst = vertex . m_nBoneIndices ;
pDst + = sizeof ( vertex . m_nBoneIndices ) ;
}
}
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_Color )
{
Assert ( GetVertexElementSize ( VERTEX_ELEMENT_COLOR , VERTEX_COMPRESSION_NONE ) = = sizeof ( vertex . m_nColor ) ) ;
* ( unsigned int * ) pDst = vertex . m_nColor ;
pDst + = sizeof ( vertex . m_nColor ) ;
}
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 ) ;
}
// ensure code is synced with the mesh builder that established the offsets
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
//-----------------------------------------------------------------------------
// Data retrieval...
//-----------------------------------------------------------------------------
inline const float * CVertexBuilder : : Position ( ) const
{
// FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately)
// for code that needs to access compressed data (and/or a return-by-value templatized accessor)
Assert ( m_CompressionType = = VERTEX_COMPRESSION_NONE ) ;
Assert ( m_nCurrentVertex < m_nMaxVertexCount ) ;
return m_pCurrPosition ;
}
inline const float * CVertexBuilder : : Normal ( ) const
{
// FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately)
// for code that needs to access compressed data (and/or a return-by-value templatized accessor)
Assert ( m_CompressionType = = VERTEX_COMPRESSION_NONE ) ;
Assert ( m_nCurrentVertex < m_nMaxVertexCount ) ;
return m_pCurrNormal ;
}
inline unsigned int CVertexBuilder : : Color ( ) const
{
// FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately)
// for code that needs to access compressed data (and/or a return-by-value templatized accessor)
Assert ( m_CompressionType = = VERTEX_COMPRESSION_NONE ) ;
// Swizzle it so it returns the same format as accepted by Color4ubv - rgba
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
{
// in memory as argb, back to rgba
color = ( m_pCurrColor [ 1 ] < < 24 ) | ( m_pCurrColor [ 2 ] < < 16 ) | ( m_pCurrColor [ 3 ] < < 8 ) | ( m_pCurrColor [ 0 ] ) ;
}
return color ;
}
inline unsigned char * CVertexBuilder : : Specular ( ) const
{
// FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately)
// for code that needs to access compressed data (and/or a return-by-value templatized accessor)
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
{
// FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately)
// for code that needs to access compressed data (and/or a return-by-value templatized accessor)
Assert ( m_CompressionType = = VERTEX_COMPRESSION_NONE ) ;
Assert ( m_nCurrentVertex < m_nMaxVertexCount ) ;
return m_pCurrTexCoord [ stage ] ;
}
inline const float * CVertexBuilder : : TangentS ( ) const
{
// FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately)
// for code that needs to access compressed data (and/or a return-by-value templatized accessor)
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
{
// FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately)
// for code that needs to access compressed data (and/or a return-by-value templatized accessor)
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
{
// FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately)
// for code that needs to access compressed data (and/or a return-by-value templatized accessor)
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
{
// FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately)
// for code that needs to access compressed data (and/or a return-by-value templatized accessor)
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
{
// FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately)
// for code that needs to access compressed data (and/or a return-by-value templatized accessor)
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
{
// FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately)
// for code that needs to access compressed data (and/or a return-by-value templatized accessor)
Assert ( m_CompressionType = = VERTEX_COMPRESSION_NONE ) ;
Assert ( m_nCurrentVertex < m_nMaxVertexCount ) ;
return m_pBoneMatrixIndex + m_nCurrentVertex * m_VertexSize_BoneMatrixIndex ;
}
# endif
//-----------------------------------------------------------------------------
// Position setting methods
//-----------------------------------------------------------------------------
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 ;
}
//-----------------------------------------------------------------------------
// Normal setting methods
//-----------------------------------------------------------------------------
inline void CVertexBuilder : : Normal3f ( float nx , float ny , float nz )
{
Assert ( m_CompressionType = = VERTEX_COMPRESSION_NONE ) ; // Use the templatized version if you want to support compression
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 ) ; // Use the templatized version if you want to support compression
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 ) ; // Use the templatized version if you want to support compression
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 ) ; // Use the templatized version if you want to support compression
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 ;
}
//-----------------------------------------------------------------------------
// Templatized normal setting methods which support compressed vertices
//-----------------------------------------------------------------------------
template < VertexCompressionType_t T > 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 ) ;
// FIXME: studiorender is passing in non-unit normals
//float lengthSqd = nx*nx + ny*ny + nz*nz;
//Assert( lengthSqd >= 0.95f && lengthSqd <= 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 //( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 )
// NOTE: write the normal into the lower 16 bits of a word, clearing the top 16 bits - a userdata4
// tangent must be written into the upper 16 bits by CompressedUserData() *AFTER* this.
# 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 < VertexCompressionType_t T > inline void CVertexBuilder : : CompressedNormal3fv ( const float * n )
{
Assert ( n ) ;
CompressedNormal3f < T > ( n [ 0 ] , n [ 1 ] , n [ 2 ] ) ;
}
//-----------------------------------------------------------------------------
// Color setting methods
//-----------------------------------------------------------------------------
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 ) ) ;
# ifdef OPENGL_SWAP_COLORS
int col = ( FastFToC ( r ) ) | ( FastFToC ( g ) < < 8 ) | ( FastFToC ( b ) < < 16 ) | 0xFF000000 ;
# else
int col = ( FastFToC ( b ) ) | ( FastFToC ( g ) < < 8 ) | ( FastFToC ( r ) < < 16 ) | 0xFF000000 ;
# endif
* ( 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 ) ) ;
# ifdef OPENGL_SWAP_COLORS
int col = ( FastFToC ( rgb [ 0 ] ) ) | ( FastFToC ( rgb [ 1 ] ) < < 8 ) | ( FastFToC ( rgb [ 2 ] ) < < 16 ) | 0xFF000000 ;
# else
int col = ( FastFToC ( rgb [ 2 ] ) ) | ( FastFToC ( rgb [ 1 ] ) < < 8 ) | ( FastFToC ( rgb [ 0 ] ) < < 16 ) | 0xFF000000 ;
# endif
* ( 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 ) ) ;
# ifdef OPENGL_SWAP_COLORS
int col = ( FastFToC ( r ) ) | ( FastFToC ( g ) < < 8 ) | ( FastFToC ( b ) < < 16 ) | ( FastFToC ( a ) < < 24 ) ;
# else
int col = ( FastFToC ( b ) ) | ( FastFToC ( g ) < < 8 ) | ( FastFToC ( r ) < < 16 ) | ( FastFToC ( a ) < < 24 ) ;
# endif
* ( 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 ) ) ;
# ifdef OPENGL_SWAP_COLORS
int col = ( FastFToC ( rgba [ 0 ] ) ) | ( FastFToC ( rgba [ 1 ] ) < < 8 ) | ( FastFToC ( rgba [ 2 ] ) < < 16 ) | ( FastFToC ( rgba [ 3 ] ) < < 24 ) ;
# else
int col = ( FastFToC ( rgba [ 2 ] ) ) | ( FastFToC ( rgba [ 1 ] ) < < 8 ) | ( FastFToC ( rgba [ 0 ] ) < < 16 ) | ( FastFToC ( rgba [ 3 ] ) < < 24 ) ;
# endif
* ( int * ) m_pCurrColor = col ;
}
//-----------------------------------------------------------------------------
// Faster versions of color
//-----------------------------------------------------------------------------
// note that on the OSX target (OpenGL) whenever there is vertex data being written as bytes - they need to be written in R,G,B,A memory order
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 ; // r, g, b, a in memory
# 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 ; // r, g, b, a in memory
# 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 ) ; // r, g, b, a in memory
# 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 ) ; // r, g, b, a in memory
# else
int col = rgba [ 2 ] | ( rgba [ 1 ] < < 8 ) | ( rgba [ 0 ] < < 16 ) | ( rgba [ 3 ] < < 24 ) ;
# endif
* ( int * ) m_pCurrColor = col ;
}
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 ] ;
# ifdef OPENGL_SWAP_COLORS
int col = ( FastFToC ( r ) ) | ( FastFToC ( g ) < < 8 ) | ( FastFToC ( b ) < < 16 ) | 0xFF000000 ;
# else
int col = ( FastFToC ( b ) ) | ( FastFToC ( g ) < < 8 ) | ( FastFToC ( r ) < < 16 ) | 0xFF000000 ;
# endif
* ( 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 ] ;
# ifdef OPENGL_SWAP_COLORS
int col = ( FastFToC ( rgb [ 0 ] ) ) | ( FastFToC ( rgb [ 1 ] ) < < 8 ) | ( FastFToC ( rgb [ 2 ] ) < < 16 ) | 0xFF000000 ;
# else
int col = ( FastFToC ( rgb [ 2 ] ) ) | ( FastFToC ( rgb [ 1 ] ) < < 8 ) | ( FastFToC ( rgb [ 0 ] ) < < 16 ) | 0xFF000000 ;
# endif
* ( 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 ] ;
# ifdef OPENGL_SWAP_COLORS
int col = ( FastFToC ( r ) ) | ( FastFToC ( g ) < < 8 ) | ( FastFToC ( b ) < < 16 ) | ( FastFToC ( a ) < < 24 ) ;
# else
int col = ( FastFToC ( b ) ) | ( FastFToC ( g ) < < 8 ) | ( FastFToC ( r ) < < 16 ) | ( FastFToC ( a ) < < 24 ) ;
# endif
* ( 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 ] ;
# ifdef OPENGL_SWAP_COLORS
int col = ( FastFToC ( rgb [ 0 ] ) ) | ( FastFToC ( rgb [ 1 ] ) < < 8 ) | ( FastFToC ( rgb [ 2 ] ) < < 16 ) | ( FastFToC ( rgb [ 3 ] ) < < 24 ) ;
# else
int col = ( FastFToC ( rgb [ 2 ] ) ) | ( FastFToC ( rgb [ 1 ] ) < < 8 ) | ( FastFToC ( rgb [ 0 ] ) < < 16 ) | ( FastFToC ( rgb [ 3 ] ) < < 24 ) ;
# endif
* ( 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 ; // r, g, b, a in memory
# 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 ; // r, g, b, a in memory
# 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 ) ; // r, g, b, a in memory
# 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 ;
}
//-----------------------------------------------------------------------------
// Texture coordinate setting methods
//-----------------------------------------------------------------------------
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 )
{
// Tried to add too much!
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 )
{
// Tried to add too much!
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 ;
}
//-----------------------------------------------------------------------------
// Tangent space setting methods
//-----------------------------------------------------------------------------
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 ;
}
//-----------------------------------------------------------------------------
// Wrinkle setting methods
//-----------------------------------------------------------------------------
inline void CVertexBuilder : : Wrinkle1f ( float flWrinkle )
{
Assert ( m_pWrinkle ) ;
Assert ( IsFinite ( flWrinkle ) ) ;
float * pWrinkle = OffsetFloatPointer ( m_pWrinkle , m_nCurrentVertex , m_VertexSize_Wrinkle ) ;
* pWrinkle = flWrinkle ;
}
//-----------------------------------------------------------------------------
// Bone weight setting methods
//-----------------------------------------------------------------------------
inline void CVertexBuilder : : BoneWeight ( int idx , float weight )
{
Assert ( m_pBoneWeight ) ;
Assert ( IsFinite ( weight ) ) ;
Assert ( idx > = 0 ) ;
AssertOnce ( m_NumBoneWeights = = 2 ) ;
// This test is here because we store N-1 bone weights (the Nth is computed in
// the vertex shader as "1 - C", where C is the sum of the (N-1) other weights)
if ( idx < m_NumBoneWeights )
{
float * pBoneWeight = OffsetFloatPointer ( m_pBoneWeight , m_nCurrentVertex , m_VertexSize_BoneWeight ) ;
pBoneWeight [ idx ] = weight ;
}
}
static int sg_IndexSwap [ 4 ] = { 2 , 1 , 0 , 3 } ;
inline void CVertexBuilder : : BoneMatrix ( int idx , int matrixIdx )
{
Assert ( m_pBoneMatrixIndex ) ;
Assert ( idx > = 0 ) ;
Assert ( idx < 4 ) ;
// garymcthack
if ( matrixIdx = = BONE_MATRIX_INDEX_INVALID )
{
matrixIdx = 0 ;
}
Assert ( ( matrixIdx > = 0 ) & & ( matrixIdx < 53 ) ) ;
# ifdef OPENGL_SWAP_COLORS
idx = sg_IndexSwap [ idx ] ;
# endif
# ifndef NEW_SKINNING
unsigned char * pBoneMatrix = & m_pBoneMatrixIndex [ m_nCurrentVertex * m_VertexSize_BoneMatrixIndex ] ;
if ( IsX360 ( ) )
{
// store sequentially as wzyx order, gpu delivers as xyzw
idx = 3 - idx ;
}
pBoneMatrix [ idx ] = ( unsigned char ) matrixIdx ;
# else
float * pBoneMatrix = & m_pBoneMatrixIndex [ m_nCurrentVertex * m_VertexSize_BoneMatrixIndex ] ;
pBoneMatrix [ idx ] = matrixIdx ;
# endif
}
//-----------------------------------------------------------------------------
// Templatized bone weight setting methods which support compressed vertices
//-----------------------------------------------------------------------------
template < VertexCompressionType_t T > 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 )
{
// Quantize to 15 bits per weight (we use D3DDECLTYPE_SHORT2)
// NOTE: we perform careful normalization (weights sum to 1.0f in the vertex shader), so
// as to avoid cracking at boundaries between meshes with different numbers of weights
// per vertex. For example, (1) needs to yield the same normalized weights as (1,0),
// and (0.5,0.49) needs to normalize the same normalized weights as (0.5,0.49,0).
// The key is that values which are *computed* in the shader (e.g. the second weight
// in a 2-weight mesh) must exactly equal values which are *read* from the vertex
// stream (e.g. the second weight in a 3-weight mesh).
// Only 1 or 2 weights (SHORT2N) supported for compressed verts so far
Assert ( m_NumBoneWeights < = 2 ) ;
const int WEIGHT0_SHIFT = IsX360 ( ) ? 16 : 0 ;
const int WEIGHT1_SHIFT = IsX360 ( ) ? 0 : 16 ;
unsigned int * weights = ( unsigned int * ) pDestWeights ;
// We scale our weights so that they sum to 32768, then subtract 1 (which gets added
// back in the shader), because dividing by 32767 introduces nasty rounding issues.
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 )
{
// Double-check the validity of the values that were passed in
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 )
{
// This path for 3 weights per vert (2 are stored and the 3rd is computed
// in the shader - we do post-quantization normalization here in such a
// way as to avoid mesh-boundary cracking)
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 ; // Normalize
* weights | = ( 0x0000FFFF & ( weight1 - 1 ) ) < < WEIGHT1_SHIFT ;
}
}
else // Uncompressed path
{
pDestWeights [ 0 ] = pWeights [ 0 ] ;
pDestWeights [ 1 ] = pWeights [ 1 ] ;
}
}
//-----------------------------------------------------------------------------
// Generic per-vertex data setting method
//-----------------------------------------------------------------------------
inline void CVertexBuilder : : UserData ( const float * pData )
{
Assert ( m_CompressionType = = VERTEX_COMPRESSION_NONE ) ; // Use the templatized version if you want to support compression
Assert ( pData ) ;
int userDataSize = 4 ; // garymcthack
float * pUserData = OffsetFloatPointer ( m_pUserData , m_nCurrentVertex , m_VertexSize_UserData ) ;
memcpy ( pUserData , pData , sizeof ( float ) * userDataSize ) ;
}
//-----------------------------------------------------------------------------
// Templatized generic per-vertex data setting method which supports compressed vertices
//-----------------------------------------------------------------------------
template < VertexCompressionType_t T > inline void CVertexBuilder : : CompressedUserData ( const float * pData )
{
Assert ( T = = m_CompressionType ) ;
Assert ( pData ) ;
// This is always in fact a tangent vector, not generic 'userdata'
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 ) ;
// FIXME: studiorender is passing in non-unit normals
//float lengthSqd = pData[0]*pData[0] + pData[1]*pData[1] + pData[2]*pData[2];
//Assert( lengthSqd >= 0.95f && lengthSqd <= 1.05f );
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 //( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 )
// FIXME: add a combined CompressedNormalAndTangent() accessor, to avoid reading back from write-combined memory here
// The normal should have already been written into the lower 16
// bits - here, we OR in the tangent into the upper 16 bits
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 ; // garymcthack
float * pUserData = OffsetFloatPointer ( m_pUserData , m_nCurrentVertex , m_VertexSize_UserData ) ;
memcpy ( pUserData , pData , sizeof ( float ) * userDataSize ) ;
}
}
//-----------------------------------------------------------------------------
//
// Helper class used to define index buffers
//
//-----------------------------------------------------------------------------
class CIndexBuilder : private IndexDesc_t
{
public :
CIndexBuilder ( ) ;
CIndexBuilder ( IIndexBuffer * pIndexBuffer , MaterialIndexFormat_t fmt = MATERIAL_INDEX_FORMAT_UNKNOWN ) ;
~ CIndexBuilder ( ) ;
// Begins, ends modification of the index buffer (returns true if the lock succeeded)
// A lock may not succeed if append is set to true and there isn't enough room
// NOTE: Append is only used with dynamic index buffers; it's ignored for static buffers
bool Lock ( int nMaxIndexCount , int nIndexOffset , bool bAppend = false ) ;
void Unlock ( ) ;
// Spews the current data
// NOTE: Can only be called during a lock/unlock block
void SpewData ( ) ;
// Returns the number of indices we can fit into the buffer without needing to discard
int GetRoomRemaining ( ) const ;
// Binds this index buffer
void Bind ( IMatRenderContext * pContext ) ;
// Returns the byte offset
int Offset ( ) const ;
// Begins, ends modification of the index buffer
// NOTE: IndexOffset is the number to add to all indices written into the buffer;
// useful when using dynamic vertex buffers.
void Begin ( IIndexBuffer * pIndexBuffer , int nMaxIndexCount , int nIndexOffset = 0 ) ;
void End ( bool bSpewData = false ) ;
// Locks the index buffer to modify existing data
// Passing nVertexCount == -1 says to lock all the vertices for modification.
// Pass 0 for nIndexCount to not lock the index buffer.
void BeginModify ( IIndexBuffer * pIndexBuffer , int nFirstIndex = 0 , int nIndexCount = 0 , int nIndexOffset = 0 ) ;
void EndModify ( bool bSpewData = false ) ;
// returns the number of indices
int IndexCount ( ) const ;
// Returns the total number of indices across all Locks()
int TotalIndexCount ( ) const ;
// Resets the mesh builder so it points to the start of everything again
void Reset ( ) ;
// Selects the nth Index
void SelectIndex ( int nBufferIndex ) ;
// Advances the current index by one
void AdvanceIndex ( ) ;
void AdvanceIndices ( int nIndexCount ) ;
int GetCurrentIndex ( ) ;
int GetFirstIndex ( ) const ;
unsigned short const * Index ( ) const ;
// Used to define the indices (only used if you aren't using primitives)
void Index ( unsigned short nIndex ) ;
// Fast Index! No need to call advance index, and no random access allowed
void FastIndex ( unsigned short nIndex ) ;
// NOTE: This version is the one you really want to achieve write-combining;
// Write combining only works if you write in 4 bytes chunks.
void FastIndex2 ( unsigned short nIndex1 , unsigned short nIndex2 ) ;
// Generates indices for a particular primitive type
void GenerateIndices ( MaterialPrimitiveType_t primitiveType , int nIndexCount ) ;
// FIXME: Remove! Backward compat so we can use this from a CMeshBuilder.
void AttachBegin ( IMesh * pMesh , int nMaxIndexCount , const MeshDesc_t & desc ) ;
void AttachEnd ( ) ;
void AttachBeginModify ( IMesh * pMesh , int nFirstIndex , int nIndexCount , 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 :
// The mesh we're modifying
IIndexBuffer * m_pIndexBuffer ;
// Max number of indices
int m_nMaxIndexCount ;
// Number of indices
int m_nIndexCount ;
// Offset to add to each index as it's written into the buffer
int m_nIndexOffset ;
// The current index
mutable int m_nCurrentIndex ;
// Total number of indices appended
int m_nTotalIndexCount ;
// First index buffer offset + first index
unsigned int m_nBufferOffset ;
unsigned int m_nBufferFirstIndex ;
// Used to make sure Begin/End calls and BeginModify/EndModify calls match.
bool m_bModify ;
} ;
//-----------------------------------------------------------------------------
//
// Inline methods related to CIndexBuilder
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
inline CIndexBuilder : : CIndexBuilder ( ) : m_pIndexBuffer ( 0 ) , m_nIndexCount ( 0 ) ,
m_nCurrentIndex ( 0 ) , m_nMaxIndexCount ( 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 ( ) ;
}
}
//-----------------------------------------------------------------------------
// Begins, ends modification of the index buffer
//-----------------------------------------------------------------------------
inline bool CIndexBuilder : : Lock ( int nMaxIndexCount , int nIndexOffset , bool bAppend )
{
Assert ( m_pIndexBuffer ) ;
m_bModify = false ;
m_nIndexOffset = nIndexOffset ;
m_nMaxIndexCount = nMaxIndexCount ;
bool bFirstLock = ( m_nBufferOffset = = INVALID_BUFFER_OFFSET ) ;
if ( bFirstLock )
{
bAppend = false ;
}
if ( ! bAppend )
{
m_nTotalIndexCount = 0 ;
}
Reset ( ) ;
// Lock the index buffer
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
// Null out our data...
memset ( ( IndexDesc_t * ) this , 0 , sizeof ( IndexDesc_t ) ) ;
# endif
}
inline void CIndexBuilder : : SpewData ( )
{
m_pIndexBuffer - > Spew ( m_nIndexCount , * this ) ;
}
//-----------------------------------------------------------------------------
// Binds this index buffer
//-----------------------------------------------------------------------------
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 ) ;
}
}
//-----------------------------------------------------------------------------
// Returns the byte offset
//-----------------------------------------------------------------------------
inline int CIndexBuilder : : Offset ( ) const
{
return m_nBufferOffset ;
}
inline int CIndexBuilder : : GetFirstIndex ( ) const
{
return m_nBufferFirstIndex ;
}
//-----------------------------------------------------------------------------
// Begins, ends modification of the index buffer
//-----------------------------------------------------------------------------
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 ;
// Lock the index buffer
m_pIndexBuffer - > Lock ( m_nMaxIndexCount , false , * this ) ;
// Point to the start of the buffers..
Reset ( ) ;
}
inline void CIndexBuilder : : End ( bool bSpewData )
{
// Make sure they called Begin()
Assert ( ! m_bModify ) ;
if ( bSpewData )
{
m_pIndexBuffer - > Spew ( m_nIndexCount , * this ) ;
}
// Unlock our buffers
m_pIndexBuffer - > Unlock ( m_nIndexCount , * this ) ;
m_pIndexBuffer = 0 ;
m_nMaxIndexCount = 0 ;
# ifdef _DEBUG
// Null out our data...
memset ( ( IndexDesc_t * ) this , 0 , sizeof ( IndexDesc_t ) ) ;
# endif
}
//-----------------------------------------------------------------------------
// Begins, ends modification of an existing index buffer which has already been filled out
//-----------------------------------------------------------------------------
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 ;
// Lock the vertex and index buffer
m_pIndexBuffer - > ModifyBegin ( false , nFirstIndex , nIndexCount , * this ) ;
// Point to the start of the buffers..
Reset ( ) ;
}
inline void CIndexBuilder : : EndModify ( bool bSpewData )
{
Assert ( m_pIndexBuffer ) ;
Assert ( m_bModify ) ; // Make sure they called BeginModify.
if ( bSpewData )
{
m_pIndexBuffer - > Spew ( m_nIndexCount , * this ) ;
}
// Unlock our buffers
m_pIndexBuffer - > ModifyEnd ( * this ) ;
m_pIndexBuffer = 0 ;
m_nMaxIndexCount = 0 ;
# ifdef _DEBUG
// Null out our data...
memset ( ( IndexDesc_t * ) this , 0 , sizeof ( IndexDesc_t ) ) ;
# endif
}
//-----------------------------------------------------------------------------
// FIXME: Remove! Backward compat so we can use this from a CMeshBuilder.
//-----------------------------------------------------------------------------
inline void CIndexBuilder : : AttachBegin ( IMesh * pMesh , int nMaxIndexCount , const MeshDesc_t & desc )
{
m_pIndexBuffer = pMesh ;
m_nIndexCount = 0 ;
m_nMaxIndexCount = nMaxIndexCount ;
m_bModify = false ;
// Copy relevant data from the mesh desc
m_nIndexOffset = desc . m_nFirstVertex ;
m_pIndices = desc . m_pIndices ;
m_nIndexSize = desc . m_nIndexSize ;
// Point to the start of the buffers..
Reset ( ) ;
}
inline void CIndexBuilder : : AttachEnd ( )
{
Assert ( m_pIndexBuffer ) ;
Assert ( ! m_bModify ) ; // Make sure they called AttachBegin.
m_pIndexBuffer = 0 ;
m_nMaxIndexCount = 0 ;
# ifdef _DEBUG
// Null out our data...
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 ;
// Copy relevant data from the mesh desc
m_nIndexOffset = desc . m_nFirstVertex ;
m_pIndices = desc . m_pIndices ;
m_nIndexSize = desc . m_nIndexSize ;
// Point to the start of the buffers..
Reset ( ) ;
}
inline void CIndexBuilder : : AttachEndModify ( )
{
Assert ( m_pIndexBuffer ) ;
Assert ( m_bModify ) ; // Make sure they called AttachBeginModify.
m_pIndexBuffer = 0 ;
m_nMaxIndexCount = 0 ;
# ifdef _DEBUG
// Null out our data...
memset ( ( IndexDesc_t * ) this , 0 , sizeof ( IndexDesc_t ) ) ;
# endif
}
//-----------------------------------------------------------------------------
// Resets the index buffer builder so it points to the start of everything again
//-----------------------------------------------------------------------------
inline void CIndexBuilder : : Reset ( )
{
m_nCurrentIndex = 0 ;
}
//-----------------------------------------------------------------------------
// returns the number of indices
//-----------------------------------------------------------------------------
inline int CIndexBuilder : : IndexCount ( ) const
{
return m_nIndexCount ;
}
//-----------------------------------------------------------------------------
// Returns the total number of indices across all Locks()
//-----------------------------------------------------------------------------
inline int CIndexBuilder : : TotalIndexCount ( ) const
{
return m_nTotalIndexCount ;
}
//-----------------------------------------------------------------------------
// Advances the current index
//-----------------------------------------------------------------------------
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 ;
}
}
//-----------------------------------------------------------------------------
// Returns the current index
//-----------------------------------------------------------------------------
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 ;
}
//-----------------------------------------------------------------------------
// Used to write data into the index buffer
//-----------------------------------------------------------------------------
inline void CIndexBuilder : : Index ( unsigned short nIndex )
{
Assert ( m_pIndices ) ;
Assert ( m_nCurrentIndex < m_nMaxIndexCount ) ;
m_pIndices [ m_nCurrentIndex ] = ( unsigned short ) ( m_nIndexOffset + nIndex ) ;
}
// Fast Index! No need to call advance index
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 ;
}
inline void CIndexBuilder : : FastTriangle ( int startVert )
{
startVert + = m_nIndexOffset ;
m_pIndices [ m_nCurrentIndex + 0 ] = startVert ;
m_pIndices [ m_nCurrentIndex + 1 ] = startVert + 1 ;
m_pIndices [ m_nCurrentIndex + 2 ] = startVert + 2 ;
AdvanceIndices ( 3 ) ;
}
inline void CIndexBuilder : : FastQuad ( int startVert )
{
startVert + = m_nIndexOffset ;
m_pIndices [ m_nCurrentIndex + 0 ] = startVert ;
m_pIndices [ m_nCurrentIndex + 1 ] = startVert + 1 ;
m_pIndices [ m_nCurrentIndex + 2 ] = startVert + 2 ;
m_pIndices [ m_nCurrentIndex + 3 ] = startVert ;
m_pIndices [ m_nCurrentIndex + 4 ] = startVert + 2 ;
m_pIndices [ m_nCurrentIndex + 5 ] = startVert + 3 ;
AdvanceIndices ( 6 ) ;
}
inline void CIndexBuilder : : FastPolygon ( int startVert , int triangleCount )
{
unsigned short * pIndex = & m_pIndices [ m_nCurrentIndex ] ;
startVert + = m_nIndexOffset ;
if ( ! IsX360 ( ) )
{
// NOTE: IndexSize is 1 or 0 (0 for alt-tab)
// This prevents us from writing into bogus memory
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 ( ) )
{
// NOTE: IndexSize is 1 or 0 (0 for alt-tab)
// This prevents us from writing into bogus memory
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 ( ) )
{
// NOTE: IndexSize is 1 or 0 (0 for alt-tab)
// This prevents us from writing into bogus memory
Assert ( m_nIndexSize = = 0 | | m_nIndexSize = = 1 ) ;
indexCount * = m_nIndexSize ;
}
for ( int i = 0 ; i < indexCount ; + + i )
{
pIndexOut [ i ] = startVert + pIndexList [ i ] ;
}
AdvanceIndices ( indexCount ) ;
}
//-----------------------------------------------------------------------------
// NOTE: This version is the one you really want to achieve write-combining;
// Write combining only works if you write in 4 bytes chunks.
//-----------------------------------------------------------------------------
inline void CIndexBuilder : : FastIndex2 ( unsigned short nIndex1 , unsigned short nIndex2 )
{
Assert ( m_pIndices ) ;
Assert ( m_nCurrentIndex < m_nMaxIndexCount - 1 ) ;
// Assert( ( (int)( &m_pIndices[m_nCurrentIndex] ) & 0x3 ) == 0 );
# 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 ;
}
//-----------------------------------------------------------------------------
// Generates indices for a particular primitive type
//-----------------------------------------------------------------------------
inline void CIndexBuilder : : GenerateIndices ( MaterialPrimitiveType_t primitiveType , int nIndexCount )
{
// FIXME: How to make this work with short vs int sized indices?
// Don't generate indices if we've got an empty buffer
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 ) ; // Shouldn't get here (this primtype is unindexed)
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 ) ; // Shouldn't get here (this primtype is unindexed)
break ;
default :
GenerateSequentialIndexBuffer ( pIndices , nIndexCount , m_nIndexOffset ) ;
break ;
}
AdvanceIndices ( nIndexCount ) ;
}
//-----------------------------------------------------------------------------
//
// Helper class used to define meshes
//
//-----------------------------------------------------------------------------
//class CMeshBuilder : private MeshDesc_t
// hack fixme
class CMeshBuilder : public MeshDesc_t
{
public :
CMeshBuilder ( ) ;
~ CMeshBuilder ( ) { Assert ( ! m_pMesh ) ; } // if this fires you did a Begin() without an End()
operator CIndexBuilder & ( ) { return m_IndexBuilder ; }
// This must be called before Begin, if a vertex buffer with a compressed format is to be used
void SetCompressionType ( VertexCompressionType_t compressionType ) ;
// Locks the vertex buffer
// (*cannot* use the Index() call below)
void Begin ( IMesh * pMesh , MaterialPrimitiveType_t type , int numPrimitives ) ;
// Locks the vertex buffer, can specify arbitrary index lists
// (must use the Index() call below)
void Begin ( IMesh * pMesh , MaterialPrimitiveType_t type , int nVertexCount , int nIndexCount , int * nFirstVertex ) ;
void Begin ( IMesh * pMesh , MaterialPrimitiveType_t type , int nVertexCount , int nIndexCount ) ;
// forward compat
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 ) ;
// Use this when you're done writing
// Set bDraw to true to call m_pMesh->Draw automatically.
void End ( bool bSpewData = false , bool bDraw = false ) ;
// Locks the vertex buffer to modify existing data
// Passing nVertexCount == -1 says to lock all the vertices for modification.
// Pass 0 for nIndexCount to not lock the index buffer.
void BeginModify ( IMesh * pMesh , int nFirstVertex = 0 , int nVertexCount = - 1 , int nFirstIndex = 0 , int nIndexCount = 0 ) ;
void EndModify ( bool bSpewData = false ) ;
// A helper method since this seems to be done a whole bunch.
void DrawQuad ( IMesh * pMesh , const float * v1 , const float * v2 ,
const float * v3 , const float * v4 , unsigned char const * pColor , bool wireframe = false ) ;
// returns the number of indices and vertices
int VertexCount ( ) const ;
int IndexCount ( ) const ;
// Resets the mesh builder so it points to the start of everything again
void Reset ( ) ;
// Returns the size of the vertex
int VertexSize ( ) { return m_ActualVertexSize ; }
// returns the data size of a given texture coordinate
int TextureCoordinateSize ( int nTexCoordNumber ) { return m_VertexSize_TexCoord [ nTexCoordNumber ] ; }
// Returns the base vertex memory pointer
void * BaseVertexData ( ) ;
// Selects the nth Vertex and Index
void SelectVertex ( int idx ) ;
void SelectIndex ( int idx ) ;
// Given an index, point to the associated vertex
void SelectVertexFromIndex ( int idx ) ;
// Advances the current vertex and index by one
void AdvanceVertex ( ) ;
template < int nFlags , int nNumTexCoords > void AdvanceVertexF ( ) ;
void AdvanceVertices ( int nVerts ) ;
void AdvanceIndex ( ) ;
void AdvanceIndices ( int nIndices ) ;
int GetCurrentVertex ( ) ;
int GetCurrentIndex ( ) ;
// Data retrieval...
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 ;
// position setting
void Position3f ( float x , float y , float z ) ;
void Position3fv ( const float * v ) ;
// normal setting
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 ) ;
// normal setting (templatized for code which needs to support compressed vertices)
template < VertexCompressionType_t T > void CompressedNormal3f ( float nx , float ny , float nz ) ;
template < VertexCompressionType_t T > void CompressedNormal3fv ( const float * n ) ;
// color setting
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 ) ;
// Faster versions of color
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 ) ;
// specular color setting
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 ) ;
// Faster version of specular
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 ) ;
// texture coordinate setting
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 ) ;
// tangent space
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 ) ;
// Wrinkle
void Wrinkle1f ( float flWrinkle ) ;
// bone weights
void BoneWeight ( int idx , float weight ) ;
// bone weights (templatized for code which needs to support compressed vertices)
template < VertexCompressionType_t T > void CompressedBoneWeight3fv ( const float * pWeights ) ;
// bone matrix index
void BoneMatrix ( int idx , int matrixIndex ) ;
// Generic per-vertex data
void UserData ( const float * pData ) ;
// Generic per-vertex data (templatized for code which needs to support compressed vertices)
template < VertexCompressionType_t T > void CompressedUserData ( const float * pData ) ;
// Used to define the indices (only used if you aren't using primitives)
void Index ( unsigned short index ) ;
// NOTE: Use this one to get write combining! Much faster than the other version of FastIndex
// Fast Index! No need to call advance index, and no random access allowed
void FastIndex2 ( unsigned short nIndex1 , unsigned short nIndex2 ) ;
// Fast Index! No need to call advance index, and no random access allowed
void FastIndex ( unsigned short index ) ;
// Fast Vertex! No need to call advance vertex, and no random access allowed.
// WARNING - these are low level functions that are intended only for use
// in the software vertex skinner.
void FastVertex ( const ModelVertexDX7_t & vertex ) ;
void FastVertexSSE ( const ModelVertexDX7_t & vertex ) ;
// store 4 dx7 vertices fast. for special sse dx7 pipeline
void Fast4VerticesSSE (
ModelVertexDX7_t const * vtx_a ,
ModelVertexDX7_t const * vtx_b ,
ModelVertexDX7_t const * vtx_c ,
ModelVertexDX7_t const * vtx_d ) ;
void FastVertex ( const ModelVertexDX8_t & vertex ) ;
void FastVertexSSE ( const ModelVertexDX8_t & vertex ) ;
// Add number of verts and current vert since FastVertexxx routines do not update.
void FastAdvanceNVertices ( int n ) ;
# if defined( _X360 )
void VertexDX8ToX360 ( const ModelVertexDX8_t & vertex ) ;
# endif
private :
// Computes number of verts and indices
void ComputeNumVertsAndIndices ( int * pMaxVertices , int * pMaxIndices ,
MaterialPrimitiveType_t type , int nPrimitiveCount ) ;
int IndicesFromVertices ( MaterialPrimitiveType_t type , int nVertexCount ) ;
// The mesh we're modifying
IMesh * m_pMesh ;
MaterialPrimitiveType_t m_Type ;
// Generate indices?
bool m_bGenerateIndices ;
CIndexBuilder m_IndexBuilder ;
CVertexBuilder m_VertexBuilder ;
} ;
//-----------------------------------------------------------------------------
// Forward compat
//-----------------------------------------------------------------------------
inline void CMeshBuilder : : Begin ( IVertexBuffer * pVertexBuffer , MaterialPrimitiveType_t type , int numPrimitives )
{
Assert ( 0 ) ;
// Begin( pVertexBuffer->GetMesh(), type, numPrimitives );
}
inline void CMeshBuilder : : Begin ( IVertexBuffer * pVertexBuffer , IIndexBuffer * pIndexBuffer , MaterialPrimitiveType_t type , int nVertexCount , int nIndexCount , int * nFirstVertex )
{
Assert ( 0 ) ;
// Begin( pVertexBuffer->GetMesh(), type, nVertexCount, nIndexCount, nFirstVertex );
}
inline void CMeshBuilder : : Begin ( IVertexBuffer * pVertexBuffer , IIndexBuffer * pIndexBuffer , MaterialPrimitiveType_t type , int nVertexCount , int nIndexCount )
{
Assert ( 0 ) ;
// Begin( pVertexBuffer->GetMesh(), type, nVertexCount, nIndexCount );
}
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
inline CMeshBuilder : : CMeshBuilder ( ) : m_pMesh ( 0 ) , m_bGenerateIndices ( false )
{
}
//-----------------------------------------------------------------------------
// Computes the number of verts and indices based on primitive type and count
//-----------------------------------------------------------------------------
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 ; // This primtype is unindexed
break ;
case MATERIAL_POLYGON :
* pMaxVertices = nPrimitiveCount ;
* pMaxIndices = ( nPrimitiveCount - 2 ) * 3 ;
break ;
default :
* pMaxVertices = 0 ;
* pMaxIndices = 0 ;
Assert ( 0 ) ;
}
// FIXME: need to get this from meshdx8.cpp, or move it to somewhere common
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 :
// This primtype is unindexed
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 ;
}
}
//-----------------------------------------------------------------------------
// Specify the type of vertex compression that this CMeshBuilder will perform
//-----------------------------------------------------------------------------
inline void CMeshBuilder : : SetCompressionType ( VertexCompressionType_t vertexCompressionType )
{
m_VertexBuilder . SetCompressionType ( vertexCompressionType ) ;
}
//-----------------------------------------------------------------------------
// Begins modifying the mesh
//-----------------------------------------------------------------------------
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 ) ;
}
// Lock the mesh
m_pMesh - > LockMesh ( nMaxVertexCount , nMaxIndexCount , * this ) ;
m_IndexBuilder . AttachBegin ( pMesh , nMaxIndexCount , * this ) ;
m_VertexBuilder . AttachBegin ( pMesh , nMaxVertexCount , * this ) ;
// Point to the start of the index and vertex buffers
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 ) ) ;
// NOTE: We can't specify the indices when we use quads, polygons, or
// linestrips; they aren't actually directly supported by
// the material system
Assert ( ( type ! = MATERIAL_QUADS ) & & ( type ! = MATERIAL_INSTANCED_QUADS ) & & ( type ! = MATERIAL_POLYGON ) & &
( type ! = MATERIAL_LINE_STRIP ) & & ( type ! = MATERIAL_LINE_LOOP ) ) ;
// Dx8 doesn't support indexed points...
Assert ( type ! = MATERIAL_POINTS ) ;
m_pMesh = pMesh ;
m_bGenerateIndices = false ;
m_Type = type ;
// Set the primitive type
m_pMesh - > SetPrimitiveType ( type ) ;
// Lock the vertex and index buffer
m_pMesh - > LockMesh ( nVertexCount , nIndexCount , * this ) ;
m_IndexBuilder . AttachBegin ( pMesh , nIndexCount , * this ) ;
m_VertexBuilder . AttachBegin ( pMesh , nVertexCount , * this ) ;
// Point to the start of the buffers..
Reset ( ) ;
}
//-----------------------------------------------------------------------------
// Use this when you're done modifying the mesh
//-----------------------------------------------------------------------------
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
// Unlock our buffers
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
}
//-----------------------------------------------------------------------------
// Locks the vertex buffer to modify existing data
//-----------------------------------------------------------------------------
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 ;
// Locks mesh for modifying
pMesh - > ModifyBeginEx ( false , nFirstVertex , nVertexCount , nFirstIndex , nIndexCount , * this ) ;
m_IndexBuilder . AttachBeginModify ( pMesh , nFirstIndex , nIndexCount , * this ) ;
m_VertexBuilder . AttachBeginModify ( pMesh , nFirstVertex , nVertexCount , * this ) ;
// Point to the start of the buffers..
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
// Unlocks mesh
m_pMesh - > ModifyEnd ( * this ) ;
m_pMesh = 0 ;
m_IndexBuilder . AttachEndModify ( ) ;
m_VertexBuilder . AttachEndModify ( ) ;
# ifdef _DEBUG
// Null out our pointers...
memset ( ( MeshDesc_t * ) this , 0 , sizeof ( MeshDesc_t ) ) ;
# endif
}
//-----------------------------------------------------------------------------
// Resets the mesh builder so it points to the start of everything again
//-----------------------------------------------------------------------------
inline void CMeshBuilder : : Reset ( )
{
m_IndexBuilder . Reset ( ) ;
m_VertexBuilder . Reset ( ) ;
}
//-----------------------------------------------------------------------------
// Selects the current Vertex and Index
//-----------------------------------------------------------------------------
FORCEINLINE void CMeshBuilder : : SelectVertex ( int nIndex )
{
m_VertexBuilder . SelectVertex ( nIndex ) ;
}
inline void CMeshBuilder : : SelectVertexFromIndex ( int idx )
{
// NOTE: This index is expected to be relative
int vertIdx = idx - m_nFirstVertex ;
SelectVertex ( vertIdx ) ;
}
FORCEINLINE void CMeshBuilder : : SelectIndex ( int idx )
{
m_IndexBuilder . SelectIndex ( idx ) ;
}
//-----------------------------------------------------------------------------
// Advances the current vertex and index by one
//-----------------------------------------------------------------------------
template < int nFlags , int nNumTexCoords > FORCEINLINE void CMeshBuilder : : AdvanceVertexF ( )
{
m_VertexBuilder . AdvanceVertexF < nFlags , nNumTexCoords > ( ) ;
}
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 ( ) ;
}
//-----------------------------------------------------------------------------
// A helper method since this seems to be done a whole bunch.
//-----------------------------------------------------------------------------
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 < VTX_HAVEPOS | VTX_HAVECOLOR , 0 > ( ) ;
Position3fv ( v2 ) ;
Color4ubv ( pColor ) ;
AdvanceVertexF < VTX_HAVEPOS | VTX_HAVECOLOR , 0 > ( ) ;
Position3fv ( v4 ) ;
Color4ubv ( pColor ) ;
AdvanceVertexF < VTX_HAVEPOS | VTX_HAVECOLOR , 0 > ( ) ;
Position3fv ( v3 ) ;
Color4ubv ( pColor ) ;
AdvanceVertexF < VTX_HAVEPOS | VTX_HAVECOLOR , 0 > ( ) ;
}
else
{
Begin ( pMesh , MATERIAL_LINE_LOOP , 4 ) ;
Position3fv ( v1 ) ;
Color4ubv ( pColor ) ;
AdvanceVertexF < VTX_HAVEPOS | VTX_HAVECOLOR , 0 > ( ) ;
Position3fv ( v2 ) ;
Color4ubv ( pColor ) ;
AdvanceVertexF < VTX_HAVEPOS | VTX_HAVECOLOR , 0 > ( ) ;
Position3fv ( v3 ) ;
Color4ubv ( pColor ) ;
AdvanceVertexF < VTX_HAVEPOS | VTX_HAVECOLOR , 0 > ( ) ;
Position3fv ( v4 ) ;
Color4ubv ( pColor ) ;
AdvanceVertexF < VTX_HAVEPOS | VTX_HAVECOLOR , 0 > ( ) ;
}
End ( ) ;
pMesh - > Draw ( ) ;
}
//-----------------------------------------------------------------------------
// returns the number of indices and vertices
//-----------------------------------------------------------------------------
FORCEINLINE int CMeshBuilder : : VertexCount ( ) const
{
return m_VertexBuilder . VertexCount ( ) ;
}
FORCEINLINE int CMeshBuilder : : IndexCount ( ) const
{
return m_IndexBuilder . IndexCount ( ) ;
}
//-----------------------------------------------------------------------------
// Returns the base vertex memory pointer
//-----------------------------------------------------------------------------
FORCEINLINE void * CMeshBuilder : : BaseVertexData ( )
{
return m_VertexBuilder . BaseVertexData ( ) ;
}
//-----------------------------------------------------------------------------
// Data retrieval...
//-----------------------------------------------------------------------------
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 ( ) ;
}
//-----------------------------------------------------------------------------
// Index
//-----------------------------------------------------------------------------
FORCEINLINE void CMeshBuilder : : Index ( unsigned short idx )
{
m_IndexBuilder . Index ( idx ) ;
}
//-----------------------------------------------------------------------------
// Fast Index! No need to call advance index
//-----------------------------------------------------------------------------
FORCEINLINE void CMeshBuilder : : FastIndex ( unsigned short idx )
{
m_IndexBuilder . FastIndex ( idx ) ;
}
// NOTE: Use this one to get write combining! Much faster than the other version of FastIndex
// Fast Index! No need to call advance index, and no random access allowed
FORCEINLINE void CMeshBuilder : : FastIndex2 ( unsigned short nIndex1 , unsigned short nIndex2 )
{
m_IndexBuilder . FastIndex2 ( nIndex1 , nIndex2 ) ;
}
//-----------------------------------------------------------------------------
// For use with the FastVertex methods, advances the current vertex by N
//-----------------------------------------------------------------------------
FORCEINLINE void CMeshBuilder : : FastAdvanceNVertices ( int nVertexCount )
{
m_VertexBuilder . FastAdvanceNVertices ( nVertexCount ) ;
}
//-----------------------------------------------------------------------------
// Fast Vertex! No need to call advance vertex, and no random access allowed
//-----------------------------------------------------------------------------
FORCEINLINE void CMeshBuilder : : FastVertex ( const ModelVertexDX7_t & vertex )
{
m_VertexBuilder . FastVertex ( vertex ) ;
}
FORCEINLINE void CMeshBuilder : : FastVertexSSE ( const ModelVertexDX7_t & vertex )
{
m_VertexBuilder . FastVertexSSE ( vertex ) ;
}
FORCEINLINE void CMeshBuilder : : Fast4VerticesSSE (
const ModelVertexDX7_t * vtx_a , const ModelVertexDX7_t * vtx_b ,
const ModelVertexDX7_t * vtx_c , const ModelVertexDX7_t * vtx_d )
{
m_VertexBuilder . Fast4VerticesSSE ( vtx_a , vtx_b , vtx_c , vtx_d ) ;
}
FORCEINLINE void CMeshBuilder : : FastVertex ( const ModelVertexDX8_t & vertex )
{
m_VertexBuilder . FastVertex ( vertex ) ;
}
FORCEINLINE void CMeshBuilder : : FastVertexSSE ( const ModelVertexDX8_t & vertex )
{
m_VertexBuilder . FastVertexSSE ( vertex ) ;
}
//-----------------------------------------------------------------------------
// Copies a vertex into the x360 format
//-----------------------------------------------------------------------------
# if defined( _X360 )
inline void CMeshBuilder : : VertexDX8ToX360 ( const ModelVertexDX8_t & vertex )
{
m_VertexBuilder . VertexDX8ToX360 ( vertex ) ;
}
# endif
//-----------------------------------------------------------------------------
// Vertex field setting methods
//-----------------------------------------------------------------------------
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 : : 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 ) ;
}
template < VertexCompressionType_t T > FORCEINLINE void CMeshBuilder : : CompressedBoneWeight3fv ( const float * pWeights )
{
m_VertexBuilder . CompressedBoneWeight3fv < T > ( pWeights ) ;
}
FORCEINLINE void CMeshBuilder : : BoneMatrix ( int nIndex , int nMatrixIdx )
{
m_VertexBuilder . BoneMatrix ( nIndex , nMatrixIdx ) ;
}
FORCEINLINE void CMeshBuilder : : UserData ( const float * pData )
{
m_VertexBuilder . UserData ( pData ) ;
}
template < VertexCompressionType_t T > FORCEINLINE void CMeshBuilder : : CompressedUserData ( const float * pData )
{
m_VertexBuilder . CompressedUserData < T > ( pData ) ;
}
//-----------------------------------------------------------------------------
// Templatized vertex field setting methods which support compression
//-----------------------------------------------------------------------------
template < VertexCompressionType_t T > FORCEINLINE void CMeshBuilder : : CompressedNormal3f ( float nx , float ny , float nz )
{
m_VertexBuilder . CompressedNormal3f < T > ( nx , ny , nz ) ;
}
template < VertexCompressionType_t T > FORCEINLINE void CMeshBuilder : : CompressedNormal3fv ( const float * n )
{
m_VertexBuilder . CompressedNormal3fv < T > ( n ) ;
}
# endif // IMESH_H