2020-04-22 18:56:21 +02:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//===========================================================================//
# define DISABLE_PROTECTED_THINGS
# include "locald3dtypes.h"
# include "imeshdx8.h"
# include "shaderapidx8_global.h"
# include "materialsystem/IShader.h"
# include "tier0/vprof.h"
# include "studio.h"
# include "tier1/fmtstr.h"
# include "tier0/platform.h"
# include "tier0/systeminformation.h"
// fixme - stick this in a header file.
# if defined( _DEBUG ) && !defined( _X360 )
// define this if you want to range check all indices when drawing
# define CHECK_INDICES
# endif
# ifdef CHECK_INDICES
# define CHECK_INDICES_MAX_NUM_STREAMS 2
# endif
# include "dynamicib.h"
# include "dynamicvb.h"
# include "utlvector.h"
# include "shaderapi/ishaderapi.h"
# include "imaterialinternal.h"
# include "imaterialsysteminternal.h"
# include "shaderapidx8.h"
# include "shaderapi/ishaderutil.h"
# include "materialsystem/imaterialsystemhardwareconfig.h"
# include "materialsystem/materialsystem_config.h"
# include "materialsystem/ivballoctracker.h"
# include "tier1/strtools.h"
# include "convar.h"
# include "shaderdevicedx8.h"
// memdbgon must be the last include file in a .cpp file!!!
# include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Uncomment this to test buffered state
//-----------------------------------------------------------------------------
//#define DEBUG_BUFFERED_MESHES 1
# define MAX_DX8_STREAMS 16
# define VERTEX_FORMAT_INVALID 0xFFFFFFFFFFFFFFFFull
// this is hooked into the engines convar
extern ConVar mat_debugalttab ;
//#define DRAW_SELECTION 1
static bool g_bDrawSelection = true ; // only used in DRAW_SELECTION
2024-08-29 08:59:44 +02:00
alignas ( 16 ) static unsigned short g_nScratchIndexBuffer [ 6 ] ; // large enough for a fast quad; used when device is not active
2020-04-22 18:56:21 +02:00
# ifdef _DEBUG
int CVertexBuffer : : s_BufferCount = 0 ;
int CIndexBuffer : : s_BufferCount = 0 ;
# endif
//-----------------------------------------------------------------------------
// Important enumerations
//-----------------------------------------------------------------------------
enum
{
VERTEX_BUFFER_SIZE = 32768 ,
MAX_QUAD_INDICES = 16384 ,
} ;
//-----------------------------------------------------------------------------
//
// Code related to vertex buffers start here
//
//-----------------------------------------------------------------------------
class CVertexBufferDx8 : public CVertexBufferBase
{
typedef CVertexBufferBase BaseClass ;
// Methods of IVertexBuffer
public :
virtual int VertexCount ( ) const ;
virtual VertexFormat_t GetVertexFormat ( ) const ;
virtual bool IsDynamic ( ) const ;
virtual void BeginCastBuffer ( VertexFormat_t format ) ;
virtual void EndCastBuffer ( ) ;
virtual int GetRoomRemaining ( ) const ;
virtual bool Lock ( int nVertexCount , bool bAppend , VertexDesc_t & desc ) ;
virtual void Unlock ( int nVertexCount , VertexDesc_t & desc ) ;
public :
// constructor
CVertexBufferDx8 ( ShaderBufferType_t type , VertexFormat_t fmt , int nVertexCount , const char * pBudgetGroupName ) ;
virtual ~ CVertexBufferDx8 ( ) ;
// Allocates, deallocates the index buffer
bool Allocate ( ) ;
void Free ( ) ;
// Returns the vertex size
int VertexSize ( ) const ;
// Only used by dynamic buffers, indicates the next lock should perform a discard.
void Flush ( ) ;
// Returns the D3D buffer
IDirect3DVertexBuffer9 * GetDx9Buffer ( ) ;
// Used to measure how much static buffer memory is touched each frame
void HandlePerFrameTextureStats ( int nFrame ) ;
protected :
IDirect3DVertexBuffer9 * m_pVertexBuffer ;
VertexFormat_t m_VertexFormat ;
int m_nVertexCount ;
int m_nBufferSize ;
int m_nFirstUnwrittenOffset ; // Used only for dynamic buffers, indicates where it's safe to write (nooverwrite)
// Is it locked?
bool m_bIsLocked : 1 ;
bool m_bIsDynamic : 1 ;
bool m_bFlush : 1 ; // Used only for dynamic buffers, indicates to discard the next time
# ifdef VPROF_ENABLED
int m_nVProfFrame ;
int * m_pFrameCounter ;
int * m_pGlobalCounter ;
# endif
# ifdef _DEBUG
static int s_nBufferCount ;
# endif
} ;
//-----------------------------------------------------------------------------
//
// Code related to index buffers start here
//
//-----------------------------------------------------------------------------
class CIndexBufferDx8 : public CIndexBufferBase
{
typedef CIndexBufferBase BaseClass ;
// Methods of IIndexBuffer
public :
virtual int IndexCount ( ) const ;
virtual MaterialIndexFormat_t IndexFormat ( ) const ;
virtual int GetRoomRemaining ( ) const ;
virtual bool Lock ( int nIndexCount , bool bAppend , IndexDesc_t & desc ) ;
virtual void Unlock ( int nIndexCount , IndexDesc_t & desc ) ;
virtual void BeginCastBuffer ( MaterialIndexFormat_t format ) ;
virtual void EndCastBuffer ( ) ;
virtual bool IsDynamic ( ) const ;
virtual void ModifyBegin ( bool bReadOnly , int nFirstIndex , int nIndexCount , IndexDesc_t & desc ) { Assert ( 0 ) ; }
virtual void ModifyEnd ( IndexDesc_t & desc ) { Assert ( 0 ) ; }
public :
// constructor
CIndexBufferDx8 ( ShaderBufferType_t bufferType , MaterialIndexFormat_t fmt , int nIndexCount , const char * pBudgetGroupName ) ;
virtual ~ CIndexBufferDx8 ( ) ;
// Allocates, deallocates the index buffer
bool Allocate ( ) ;
void Free ( ) ;
// Returns the index size
int IndexSize ( ) const ;
// Only used by dynamic buffers, indicates the next lock should perform a discard.
void Flush ( ) ;
// Returns the D3D buffer
IDirect3DIndexBuffer9 * GetDx9Buffer ( ) ;
// Used to measure how much static buffer memory is touched each frame
void HandlePerFrameTextureStats ( int nFrame ) ;
# ifdef CHECK_INDICES
unsigned short GetShadowIndex ( int i ) const ;
# endif
private :
IDirect3DIndexBuffer9 * m_pIndexBuffer ;
MaterialIndexFormat_t m_IndexFormat ;
int m_nIndexCount ;
int m_nBufferSize ;
int m_nFirstUnwrittenOffset ; // Used only for dynamic buffers, indicates where it's safe to write (nooverwrite)
// Is it locked?
bool m_bIsLocked : 1 ;
bool m_bIsDynamic : 1 ;
bool m_bFlush : 1 ; // Used only for dynamic buffers, indicates to discard the next time
# ifdef CHECK_INDICES
unsigned char * m_pShadowIndices ;
void * m_pLockIndexBuffer ;
int m_nLockIndexBufferSize ;
int m_nLockIndexOffset ;
# endif
# ifdef VPROF_ENABLED
int m_nVProfFrame ;
# endif
# ifdef _DEBUG
static int s_nBufferCount ;
# endif
} ;
//-----------------------------------------------------------------------------
//
// Backward compat mesh code; will go away soon
//
//-----------------------------------------------------------------------------
abstract_class CBaseMeshDX8 : public CMeshBase
{
public :
// constructor, destructor
CBaseMeshDX8 ( ) ;
virtual ~ CBaseMeshDX8 ( ) ;
// FIXME: Make this work! Unsupported methods of IIndexBuffer + IVertexBuffer
virtual bool Lock ( int nMaxIndexCount , bool bAppend , IndexDesc_t & desc ) { Assert ( 0 ) ; return false ; }
virtual void Unlock ( int nWrittenIndexCount , IndexDesc_t & desc ) { Assert ( 0 ) ; }
virtual void ModifyBegin ( bool bReadOnly , int nFirstIndex , int nIndexCount , IndexDesc_t & desc ) { Assert ( 0 ) ; }
virtual void ModifyEnd ( IndexDesc_t & desc ) { Assert ( 0 ) ; }
virtual void Spew ( int nIndexCount , const IndexDesc_t & desc ) { Assert ( 0 ) ; }
virtual void ValidateData ( int nIndexCount , const IndexDesc_t & desc ) { Assert ( 0 ) ; }
virtual bool Lock ( int nVertexCount , bool bAppend , VertexDesc_t & desc ) { Assert ( 0 ) ; return false ; }
virtual void Unlock ( int nVertexCount , VertexDesc_t & desc ) { Assert ( 0 ) ; }
virtual void Spew ( int nVertexCount , const VertexDesc_t & desc ) { Assert ( 0 ) ; }
virtual void ValidateData ( int nVertexCount , const VertexDesc_t & desc ) { Assert ( 0 ) ; }
// Locks mesh for modifying
void ModifyBeginEx ( bool bReadOnly , int nFirstVertex , int nVertexCount , int nFirstIndex , int nIndexCount , MeshDesc_t & desc ) ;
void ModifyBegin ( int nFirstVertex , int nVertexCount , int nFirstIndex , int nIndexCount , MeshDesc_t & desc ) ;
void ModifyEnd ( MeshDesc_t & desc ) ;
// Sets/gets the vertex format
virtual void SetVertexFormat ( VertexFormat_t format ) ;
virtual VertexFormat_t GetVertexFormat ( ) const ;
// Sets/gets the morph format
virtual void SetMorphFormat ( MorphFormat_t format ) ;
virtual MorphFormat_t GetMorphFormat ( ) const ;
// Am I using morph data?
virtual bool IsUsingMorphData ( ) const ;
bool IsUsingVertexID ( ) const
{
return ShaderAPI ( ) - > GetBoundMaterial ( ) - > IsUsingVertexID ( ) ;
}
// Sets the material
virtual void SetMaterial ( IMaterial * pMaterial ) ;
// returns the # of vertices (static meshes only)
int VertexCount ( ) const { return 0 ; }
void SetColorMesh ( IMesh * pColorMesh , int nVertexOffsetInBytes )
{
Assert ( 0 ) ;
}
void SetFlexMesh ( IMesh * pMesh , int nVertexOffsetInBytes )
{
Assert ( pMesh = = NULL & & nVertexOffsetInBytes = = 0 ) ;
}
void DisableFlexMesh ( )
{
Assert ( 0 ) ;
}
void MarkAsDrawn ( ) { }
bool HasColorMesh ( ) const { return false ; }
bool HasFlexMesh ( ) const { return false ; }
// Draws the mesh
void DrawMesh ( ) ;
// Begins a pass
void BeginPass ( ) ;
// Spews the mesh data
virtual void Spew ( int nVertexCount , int nIndexCount , const MeshDesc_t & desc ) ;
// Call this in debug mode to make sure our data is good.
virtual void ValidateData ( int nVertexCount , int nIndexCount , const MeshDesc_t & desc ) ;
virtual void HandleLateCreation ( ) = 0 ;
void Draw ( CPrimList * pLists , int nLists ) ;
// 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 ) ;
// returns the primitive type
virtual MaterialPrimitiveType_t GetPrimitiveType ( ) const = 0 ;
// Returns the number of indices in a mesh..
virtual int IndexCount ( ) const = 0 ;
// FIXME: Make this work!
virtual MaterialIndexFormat_t IndexFormat ( ) const { return MATERIAL_INDEX_FORMAT_16BIT ; }
// NOTE: For dynamic index buffers only!
// Casts the memory of the dynamic index buffer to the appropriate type
virtual void BeginCastBuffer ( MaterialIndexFormat_t format ) { Assert ( 0 ) ; }
virtual void BeginCastBuffer ( VertexFormat_t format ) { Assert ( 0 ) ; }
virtual void EndCastBuffer ( ) { Assert ( 0 ) ; }
virtual int GetRoomRemaining ( ) const { Assert ( 0 ) ; return 0 ; }
// returns a static vertex buffer...
virtual CVertexBuffer * GetVertexBuffer ( ) { return 0 ; }
virtual CIndexBuffer * GetIndexBuffer ( ) { return 0 ; }
// Do I need to reset the vertex format?
virtual bool NeedsVertexFormatReset ( VertexFormat_t fmt ) const ;
// Do I have enough room?
virtual bool HasEnoughRoom ( int nVertexCount , int nIndexCount ) const ;
// Operation to do pre-lock
virtual void PreLock ( ) { }
virtual unsigned ComputeMemoryUsed ( ) ;
bool m_bMeshLocked ;
protected :
bool DebugTrace ( ) const ;
// The vertex format we're using...
VertexFormat_t m_VertexFormat ;
// The morph format we're using
MorphFormat_t m_MorphFormat ;
# ifdef DBGFLAG_ASSERT
IMaterialInternal * m_pMaterial ;
bool m_IsDrawing ;
# endif
} ;
//-----------------------------------------------------------------------------
// Implementation of the mesh
//-----------------------------------------------------------------------------
class CMeshDX8 : public CBaseMeshDX8
{
public :
// constructor
CMeshDX8 ( const char * pTextureGroupName ) ;
virtual ~ CMeshDX8 ( ) ;
// Locks/unlocks the mesh
void LockMesh ( int nVertexCount , int nIndexCount , MeshDesc_t & desc ) ;
void UnlockMesh ( int nVertexCount , int nIndexCount , MeshDesc_t & desc ) ;
// Locks mesh for modifying
void ModifyBeginEx ( bool bReadOnly , int nFirstVertex , int nVertexCount , int nFirstIndex , int nIndexCount , MeshDesc_t & desc ) ;
void ModifyBegin ( int nFirstVertex , int nVertexCount , int nFirstIndex , int nIndexCount , MeshDesc_t & desc ) ;
void ModifyEnd ( MeshDesc_t & desc ) ;
// returns the # of vertices (static meshes only)
int VertexCount ( ) const ;
// returns the # of indices
virtual int IndexCount ( ) const ;
// Sets up the vertex and index buffers
void UseIndexBuffer ( CIndexBuffer * pBuffer ) ;
void UseVertexBuffer ( CVertexBuffer * pBuffer ) ;
// returns a static vertex buffer...
CVertexBuffer * GetVertexBuffer ( ) { return m_pVertexBuffer ; }
CIndexBuffer * GetIndexBuffer ( ) { return m_pIndexBuffer ; }
void SetColorMesh ( IMesh * pColorMesh , int nVertexOffsetInBytes ) ;
void SetFlexMesh ( IMesh * pMesh , int nVertexOffsetInBytes ) ;
void DisableFlexMesh ( ) ;
virtual void HandleLateCreation ( ) ;
bool HasColorMesh ( ) const ;
bool HasFlexMesh ( ) const ;
// Draws the mesh
void Draw ( int nFirstIndex , int nIndexCount ) ;
void Draw ( CPrimList * pLists , int nLists ) ;
void DrawInternal ( CPrimList * pLists , int nLists ) ;
// Draws a single pass
void RenderPass ( ) ;
// Sets the primitive type
void SetPrimitiveType ( MaterialPrimitiveType_t type ) ;
MaterialPrimitiveType_t GetPrimitiveType ( ) const ;
bool IsDynamic ( ) const { return false ; }
protected :
// Sets the render state.
bool SetRenderState ( int nVertexOffsetInBytes , int nFirstVertexIdx , VertexFormat_t vertexFormat = VERTEX_FORMAT_INVALID ) ;
// Is the vertex format valid?
bool IsValidVertexFormat ( VertexFormat_t vertexFormat = VERTEX_FORMAT_INVALID ) ;
// Locks/ unlocks the vertex buffer
bool Lock ( int nVertexCount , bool bAppend , VertexDesc_t & desc ) ;
void Unlock ( int nVertexCount , VertexDesc_t & desc ) ;
// Locks/unlocks the index buffer
// Pass in nFirstIndex=-1 to lock wherever the index buffer is. Pass in a value
// >= 0 to specify where to lock.
int Lock ( bool bReadOnly , int nFirstIndex , int nIndexCount , IndexDesc_t & pIndices ) ;
void Unlock ( int nIndexCount , IndexDesc_t & desc ) ;
// computes how many primitives we've got
int NumPrimitives ( int nVertexCount , int nIndexCount ) const ;
// Debugging output...
void SpewMaterialVerts ( ) ;
// Stream source setting methods
void SetVertexIDStreamState ( ) ;
void SetColorStreamState ( ) ;
void SetVertexStreamState ( int nVertOffsetInBytes ) ;
void SetIndexStreamState ( int firstVertexIdx ) ;
void CheckIndices ( CPrimList * pPrim , int numPrimitives ) ;
// The vertex and index buffers
CVertexBuffer * m_pVertexBuffer ;
CIndexBuffer * m_pIndexBuffer ;
// The current color mesh (to be bound to stream 1)
// The vertex offset allows use of a global, shared color mesh VB
CMeshDX8 * m_pColorMesh ;
int m_nColorMeshVertOffsetInBytes ;
CVertexBuffer * m_pFlexVertexBuffer ;
bool m_bHasFlexVerts ;
int m_nFlexVertOffsetInBytes ;
int m_flexVertCount ;
// Primitive type
MaterialPrimitiveType_t m_Type ;
// Primitive mode
D3DPRIMITIVETYPE m_Mode ;
// Number of primitives
unsigned int m_NumIndices ;
unsigned short m_NumVertices ;
// Is it locked?
bool m_IsVBLocked ;
bool m_IsIBLocked ;
// Used in rendering sub-parts of the mesh
static CPrimList * s_pPrims ;
static int s_nPrims ;
static unsigned int s_FirstVertex ; // Gets reset during CMeshDX8::DrawInternal
static unsigned int s_NumVertices ;
int m_FirstIndex ;
# ifdef RECORDING
int m_LockVertexBufferSize ;
void * m_LockVertexBuffer ;
# endif
# if defined( RECORDING ) || defined( CHECK_INDICES )
void * m_LockIndexBuffer ;
int m_LockIndexBufferSize ;
# endif
const char * m_pTextureGroupName ;
friend class CMeshMgr ; // MESHFIXME
} ;
//-----------------------------------------------------------------------------
// A little extra stuff for the dynamic version
//-----------------------------------------------------------------------------
class CDynamicMeshDX8 : public CMeshDX8
{
public :
// constructor, destructor
CDynamicMeshDX8 ( ) ;
virtual ~ CDynamicMeshDX8 ( ) ;
// Initializes the dynamic mesh
void Init ( int nBufferId ) ;
// Sets the vertex format
virtual void SetVertexFormat ( VertexFormat_t format ) ;
// Resets the state in case of a task switch
void Reset ( ) ;
// Do I have enough room in the buffer?
bool HasEnoughRoom ( int nVertexCount , int nIndexCount ) const ;
// returns the # of indices
int IndexCount ( ) const ;
// Locks the mesh
void LockMesh ( int nVertexCount , int nIndexCount , MeshDesc_t & desc ) ;
// Unlocks the mesh
void UnlockMesh ( int nVertexCount , int nIndexCount , MeshDesc_t & desc ) ;
// Override vertex + index buffer
void OverrideVertexBuffer ( CVertexBuffer * pStaticVertexBuffer ) ;
void OverrideIndexBuffer ( CIndexBuffer * pStaticIndexBuffer ) ;
// Do I need to reset the vertex format?
bool NeedsVertexFormatReset ( VertexFormat_t fmt ) const ;
// Draws it
void Draw ( int nFirstIndex , int nIndexCount ) ;
void MarkAsDrawn ( ) { m_HasDrawn = true ; }
// Simply draws what's been buffered up immediately, without state change
void DrawSinglePassImmediately ( ) ;
// Operation to do pre-lock
void PreLock ( ) ;
bool IsDynamic ( ) const { return true ; }
private :
// Resets buffering state
void ResetVertexAndIndexCounts ( ) ;
// Buffer Id
int m_nBufferId ;
// total queued vertices
int m_TotalVertices ;
int m_TotalIndices ;
// the first vertex and index since the last draw
int m_nFirstVertex ;
int m_FirstIndex ;
// Have we drawn since the last lock?
bool m_HasDrawn ;
// Any overrides?
bool m_VertexOverride ;
bool m_IndexOverride ;
} ;
//-----------------------------------------------------------------------------
// A mesh that stores temporary vertex data in the correct format (for modification)
//-----------------------------------------------------------------------------
class CTempMeshDX8 : public CBaseMeshDX8
{
public :
// constructor, destructor
CTempMeshDX8 ( bool isDynamic ) ;
virtual ~ CTempMeshDX8 ( ) ;
// Sets the material
virtual void SetVertexFormat ( VertexFormat_t format ) ;
// Locks/unlocks the mesh
void LockMesh ( int nVertexCount , int nIndexCount , MeshDesc_t & desc ) ;
void UnlockMesh ( int nVertexCount , int nIndexCount , MeshDesc_t & desc ) ;
// Locks mesh for modifying
virtual void ModifyBeginEx ( bool bReadOnly , int nFirstVertex , int nVertexCount , int nFirstIndex , int nIndexCount , MeshDesc_t & desc ) ;
virtual void ModifyBegin ( int nFirstVertex , int nVertexCount , int nFirstIndex , int nIndexCount , MeshDesc_t & desc ) ;
virtual void ModifyEnd ( MeshDesc_t & desc ) ;
// Number of indices + vertices
int VertexCount ( ) const ;
virtual int IndexCount ( ) const ;
virtual bool IsDynamic ( ) const ;
// Sets the primitive type
void SetPrimitiveType ( MaterialPrimitiveType_t type ) ;
MaterialPrimitiveType_t GetPrimitiveType ( ) const ;
// Begins a pass
void BeginPass ( ) ;
// Draws a single pass
void RenderPass ( ) ;
virtual void HandleLateCreation ( )
{
Assert ( ! " TBD - CTempMeshDX8::HandleLateCreation() " ) ;
}
// Draws the entire beast
void Draw ( int nFirstIndex , int nIndexCount ) ;
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 ) ;
private :
// Selection mode
void TestSelection ( ) ;
void ClipTriangle ( D3DXVECTOR3 * * ppVert , float zNear , D3DXMATRIX & proj ) ;
CDynamicMeshDX8 * GetDynamicMesh ( ) ;
CUtlVector < unsigned char , CUtlMemoryAligned < unsigned char , 32 > > m_VertexData ;
2024-08-29 08:59:44 +02:00
CUtlVector < unsigned short , CUtlMemoryAligned < unsigned short , 16 > > m_IndexData ;
2020-04-22 18:56:21 +02:00
unsigned short m_VertexSize ;
MaterialPrimitiveType_t m_Type ;
int m_LockedVerts ;
int m_LockedIndices ;
bool m_IsDynamic ;
// Used in rendering sub-parts of the mesh
static unsigned int s_NumIndices ;
static unsigned int s_FirstIndex ;
# ifdef DBGFLAG_ASSERT
bool m_Locked ;
bool m_InPass ;
# endif
} ;
#if 0
//-----------------------------------------------------------------------------
// A mesh that stores temporary vertex data in the correct format (for modification)
//-----------------------------------------------------------------------------
class CTempIndexBufferDX8 : public CIndexBufferBase
{
public :
// constructor, destructor
CTempIndexBufferDX8 ( bool isDynamic ) ;
virtual ~ CTempIndexBufferDX8 ( ) ;
// Locks/unlocks the mesh
void LockIndexBuffer ( int nIndexCount ) ;
void UnlockMesh ( int nIndexCount ) ;
// Locks mesh for modifying
virtual void ModifyBeginEx ( bool bReadOnly , int nFirstIndex , int nIndexCount ) ;
virtual void ModifyEnd ( ) ;
// Number of indices
virtual int IndexCount ( ) const ;
virtual bool IsDynamic ( ) const ;
virtual void CopyToIndexBuilder (
int iStartIndex , // Which indices to copy.
int nIndices ,
int indexOffset , // This is added to each index.
CIndexBuilder & builder ) ;
private :
// Selection mode
void TestSelection ( ) ;
CDynamicMeshDX8 * GetDynamicMesh ( ) ;
CUtlVector < unsigned short > m_IndexData ;
MaterialPrimitiveType_t m_Type ;
int m_LockedIndices ;
bool m_IsDynamic ;
// Used in rendering sub-parts of the mesh
static unsigned int s_NumIndices ;
static unsigned int s_FirstIndex ;
# ifdef DBGFLAG_ASSERT
bool m_Locked ;
bool m_InPass ;
# endif
} ;
# endif
//-----------------------------------------------------------------------------
// This is a version that buffers up vertex data so we can blast through it later
//-----------------------------------------------------------------------------
class CBufferedMeshDX8 : public CBaseMeshDX8
{
public :
// constructor, destructor
CBufferedMeshDX8 ( ) ;
virtual ~ CBufferedMeshDX8 ( ) ;
// checks to see if it was rendered..
void ResetRendered ( ) ;
bool WasNotRendered ( ) const ;
// Sets the mesh we're really going to draw into
void SetMesh ( CBaseMeshDX8 * pMesh ) ;
const CBaseMeshDX8 * GetMesh ( ) const { return m_pMesh ; }
// Spews the mesh data
virtual void Spew ( int nVertexCount , int nIndexCount , const MeshDesc_t & spewDesc ) ;
// Sets the vertex format
virtual void SetVertexFormat ( VertexFormat_t format ) ;
virtual VertexFormat_t GetVertexFormat ( ) const ;
// Sets the morph format
virtual void SetMorphFormat ( MorphFormat_t format ) ;
// Sets the material
void SetMaterial ( IMaterial * pMaterial ) ;
// returns the number of indices (should never be called!)
virtual int IndexCount ( ) const { Assert ( 0 ) ; return 0 ; }
virtual MaterialIndexFormat_t IndexFormat ( ) const { Assert ( 0 ) ; return MATERIAL_INDEX_FORMAT_16BIT ; }
virtual bool IsDynamic ( ) const { Assert ( 0 ) ; return true ; }
virtual void BeginCastBuffer ( MaterialIndexFormat_t format ) { Assert ( 0 ) ; }
virtual void EndCastBuffer ( ) { Assert ( 0 ) ; }
virtual int GetRoomRemaining ( ) const { Assert ( 0 ) ; return 0 ; }
// Locks the mesh
void LockMesh ( int nVertexCount , int nIndexCount , MeshDesc_t & desc ) ;
void UnlockMesh ( int nVertexCount , int nIndexCount , MeshDesc_t & desc ) ;
// Sets the primitive type
void SetPrimitiveType ( MaterialPrimitiveType_t type ) ;
MaterialPrimitiveType_t GetPrimitiveType ( ) const ;
void ValidateData ( int nVertexCount , int nIndexCount , const MeshDesc_t & spewDesc ) ;
virtual void HandleLateCreation ( )
{
if ( m_pMesh )
{
m_pMesh - > HandleLateCreation ( ) ;
}
}
// Draws it
void Draw ( int nFirstIndex , int nIndexCount ) ;
// Renders a pass
void RenderPass ( ) ;
// Flushes queued data
void Flush ( ) ;
void SetFlexMesh ( IMesh * pMesh , int nVertexOffsetInBytes ) ;
private :
// The actual mesh we need to render....
CBaseMeshDX8 * m_pMesh ;
// The index of the last vertex (for tristrip fixup)
unsigned short m_LastIndex ;
// Extra padding indices for tristrips
unsigned short m_ExtraIndices ;
// Am I currently flushing?
bool m_IsFlushing ;
// has the dynamic mesh been rendered?
bool m_WasRendered ;
// Do I need to flush?
bool m_FlushNeeded ;
# ifdef DEBUG_BUFFERED_MESHES
// for debugging only
bool m_BufferedStateSet ;
BufferedState_t m_BufferedState ;
# endif
} ;
//-----------------------------------------------------------------------------
// Implementation of the mesh manager
//-----------------------------------------------------------------------------
class CMeshMgr : public IMeshMgr
{
public :
// constructor, destructor
CMeshMgr ( ) ;
virtual ~ CMeshMgr ( ) ;
// Initialize, shutdown
void Init ( ) ;
void Shutdown ( ) ;
// Task switch...
void ReleaseBuffers ( ) ;
void RestoreBuffers ( ) ;
// Releases all dynamic vertex buffers
void DestroyVertexBuffers ( ) ;
// Flushes the dynamic mesh
void Flush ( ) ;
// Flushes the vertex buffers
void DiscardVertexBuffers ( ) ;
// Creates, destroys static meshes
IMesh * CreateStaticMesh ( VertexFormat_t vertexFormat , const char * pTextureBudgetGroup , IMaterial * pMaterial = NULL ) ;
void DestroyStaticMesh ( IMesh * pMesh ) ;
// Gets at the dynamic mesh (spoofs it though)
IMesh * GetDynamicMesh ( IMaterial * pMaterial , VertexFormat_t vertexFormat , int nHWSkinBoneCount , bool buffered ,
IMesh * pVertexOverride , IMesh * pIndexOverride ) ;
// -----------------------------------------------------------
// ------------ New Vertex/Index Buffer interface ----------------------------
// Do we need support for bForceTempMesh and bSoftwareVertexShader?
// I don't think we use bSoftwareVertexShader anymore. .need to look into bForceTempMesh.
IVertexBuffer * CreateVertexBuffer ( ShaderBufferType_t type , VertexFormat_t fmt , int nVertexCount , const char * pBudgetGroup ) ;
IIndexBuffer * CreateIndexBuffer ( ShaderBufferType_t bufferType , MaterialIndexFormat_t fmt , int nIndexCount , const char * pBudgetGroup ) ;
void DestroyVertexBuffer ( IVertexBuffer * ) ;
void DestroyIndexBuffer ( IIndexBuffer * ) ;
// Do we need to specify the stream here in the case of locking multiple dynamic VBs on different streams?
IVertexBuffer * GetDynamicVertexBuffer ( int streamID , VertexFormat_t vertexFormat , bool bBuffered = true ) ;
IIndexBuffer * GetDynamicIndexBuffer ( MaterialIndexFormat_t fmt , bool bBuffered = true ) ;
void BindVertexBuffer ( int streamID , IVertexBuffer * pVertexBuffer , int nOffsetInBytes , int nFirstVertex , int nVertexCount , VertexFormat_t fmt , int nRepetitions = 1 ) ;
void BindIndexBuffer ( IIndexBuffer * pIndexBuffer , int nOffsetInBytes ) ;
void Draw ( MaterialPrimitiveType_t primitiveType , int nFirstIndex , int nIndexCount ) ;
// ------------ End ----------------------------
void RenderPassWithVertexAndIndexBuffers ( void ) ;
VertexFormat_t GetCurrentVertexFormat ( void ) const { return m_CurrentVertexFormat ; }
// Gets at the *actual* dynamic mesh
IMesh * GetActualDynamicMesh ( VertexFormat_t vertexFormat ) ;
IMesh * GetFlexMesh ( ) ;
// Computes vertex format from a list of ingredients
VertexFormat_t ComputeVertexFormat ( unsigned int flags ,
int numTexCoords , int * pTexCoordDimensions , int numBoneWeights ,
int userDataSize ) const ;
// Use fat vertices (for tools)
virtual void UseFatVertices ( bool bUseFat ) ;
// Returns the number of vertices we can render using the dynamic mesh
virtual void GetMaxToRender ( IMesh * pMesh , bool bMaxUntilFlush , int * pMaxVerts , int * pMaxIndices ) ;
virtual int GetMaxVerticesToRender ( IMaterial * pMaterial ) ;
virtual int GetMaxIndicesToRender ( ) ;
// Returns a vertex buffer appropriate for the flags
CVertexBuffer * FindOrCreateVertexBuffer ( int nDynamicBufferId , VertexFormat_t fmt ) ;
CIndexBuffer * GetDynamicIndexBuffer ( ) ;
// Is the mesh dynamic?
bool IsDynamicMesh ( IMesh * pMesh ) const ;
bool IsBufferedDynamicMesh ( IMesh * pMesh ) const ;
// Is the vertex buffer dynamic?
bool IsDynamicVertexBuffer ( IVertexBuffer * pVertexBuffer ) const ;
// Is the index buffer dynamic?
bool IsDynamicIndexBuffer ( IIndexBuffer * pIndexBuffer ) const ;
// Returns the vertex size
int VertexFormatSize ( VertexFormat_t vertexFormat ) const
{
return CVertexBufferBase : : VertexFormatSize ( vertexFormat ) ;
}
// Computes the vertex buffer pointers
void ComputeVertexDescription ( unsigned char * pBuffer ,
VertexFormat_t vertexFormat , MeshDesc_t & desc ) const ;
// Returns the number of buffers...
int BufferCount ( ) const
{
# ifdef _DEBUG
return CVertexBuffer : : BufferCount ( ) + CIndexBuffer : : BufferCount ( ) ;
# else
return 0 ;
# endif
}
CVertexBuffer * GetVertexIDBuffer ( ) ;
IVertexBuffer * GetDynamicVertexBuffer ( IMaterial * pMaterial , bool buffered = true ) ;
IIndexBuffer * GetDynamicIndexBuffer ( IMaterial * pMaterial , bool buffered = true ) ;
virtual void MarkUnusedVertexFields ( unsigned int nFlags , int nTexCoordCount , bool * pUnusedTexCoords ) ;
int UnusedVertexFields ( ) const { return m_nUnusedVertexFields ; }
int UnusedTextureCoords ( ) const { return m_nUnusedTextureCoords ; }
IDirect3DVertexBuffer9 * GetZeroVertexBuffer ( ) const { return m_pZeroVertexBuffer ; }
private :
void SetVertexIDStreamState ( ) ;
void SetColorStreamState ( ) ;
void SetVertexStreamState ( int nVertOffsetInBytes , int nVertexStride ) ;
void SetIndexStreamState ( int firstVertexIdx ) ;
bool SetRenderState ( int nVertexOffsetInBytes , int nFirstVertexIdx , VertexFormat_t vertexFormat , int nVertexStride ) ;
struct VertexBufferLookup_t
{
CVertexBuffer * m_pBuffer ;
int m_VertexSize ;
} ;
void CopyStaticMeshIndexBufferToTempMeshIndexBuffer ( CTempMeshDX8 * pDstIndexMesh , CMeshDX8 * pSrcIndexMesh ) ;
// Cleans up the class
void CleanUp ( ) ;
// Creates, destroys the dynamic index
void CreateDynamicIndexBuffer ( ) ;
void DestroyDynamicIndexBuffer ( ) ;
// Creates, destroys the vertexID buffer
void CreateVertexIDBuffer ( ) ;
void DestroyVertexIDBuffer ( ) ;
void CreateZeroVertexBuffer ( ) ;
void DestroyZeroVertexBuffer ( ) ;
// Fills a vertexID buffer
void FillVertexIDBuffer ( CVertexBuffer * pVertexIDBuffer , int nCount ) ;
// The dynamic index buffer
CIndexBuffer * m_pDynamicIndexBuffer ;
// A static vertexID buffer
CVertexBuffer * m_pVertexIDBuffer ;
// The dynamic vertex buffers
CUtlVector < VertexBufferLookup_t > m_DynamicVertexBuffers ;
// The buffered mesh
CBufferedMeshDX8 m_BufferedMesh ;
// The current dynamic mesh
CDynamicMeshDX8 m_DynamicMesh ;
CDynamicMeshDX8 m_DynamicFlexMesh ;
// The current dynamic vertex buffer
CVertexBufferDx8 m_DynamicVertexBuffer ;
// The current dynamic index buffer
CIndexBufferDx8 m_DynamicIndexBuffer ;
// The dynamic mesh temp version (for shaders that modify vertex data)
CTempMeshDX8 m_DynamicTempMesh ;
// Am I buffering or not?
bool m_BufferedMode ;
// Using fat vertices?
bool m_bUseFatVertices ;
CVertexBufferDx8 * m_pCurrentVertexBuffer ;
VertexFormat_t m_CurrentVertexFormat ;
int m_pVertexBufferOffset [ MAX_DX8_STREAMS ] ;
int m_pCurrentVertexStride [ MAX_DX8_STREAMS ] ;
int m_pFirstVertex [ MAX_DX8_STREAMS ] ;
int m_pVertexCount [ MAX_DX8_STREAMS ] ;
CIndexBufferBase * m_pCurrentIndexBuffer ;
int m_nIndexBufferOffset ;
MaterialPrimitiveType_t m_PrimitiveType ;
int m_nFirstIndex ;
int m_nNumIndices ;
unsigned int m_nUnusedVertexFields ;
unsigned int m_nUnusedTextureCoords ;
// 4096 byte static VB containing all-zeros
IDirect3DVertexBuffer9 * m_pZeroVertexBuffer ;
} ;
//-----------------------------------------------------------------------------
// Singleton...
//-----------------------------------------------------------------------------
static CMeshMgr g_MeshMgr ;
IMeshMgr * MeshMgr ( )
{
return & g_MeshMgr ;
}
//-----------------------------------------------------------------------------
// Tracks stream state and queued data
//-----------------------------------------------------------------------------
static CIndexBuffer * g_pLastIndex = NULL ;
static IDirect3DIndexBuffer9 * g_pLastIndexBuffer = NULL ;
static CVertexBuffer * g_pLastVertex = NULL ;
static IDirect3DVertexBuffer9 * g_pLastVertexBuffer = NULL ;
static int g_nLastVertOffsetInBytes = 0 ;
static int g_nLastVertStride = 0 ;
static int g_LastVertexIdx = - 1 ;
static CMeshDX8 * g_pLastColorMesh = NULL ;
static int g_nLastColorMeshVertOffsetInBytes = 0 ;
static bool g_bUsingVertexID = false ;
static bool g_bFlexMeshStreamSet = false ;
static VertexFormat_t g_LastVertexFormat = 0 ;
inline void D3DSetStreamSource ( unsigned int streamNumber , IDirect3DVertexBuffer9 * pStreamData ,
unsigned int nVertexOffsetInBytes , unsigned int stride )
{
Dx9Device ( ) - > SetStreamSource ( streamNumber , pStreamData , nVertexOffsetInBytes , stride ) ;
}
//-----------------------------------------------------------------------------
// Tracks stream state and queued data
//-----------------------------------------------------------------------------
void Unbind ( IDirect3DIndexBuffer9 * pIndexBuffer )
{
# ifdef _X360
IDirect3DIndexBuffer9 * pBoundBuffer ;
Dx9Device ( ) - > GetIndices ( & pBoundBuffer ) ;
if ( pBoundBuffer = = pIndexBuffer )
{
// xboxissue - cannot lock indexes set in a d3d device, clear possibly set indices
Dx9Device ( ) - > SetIndices ( NULL ) ;
g_pLastIndex = NULL ;
g_pLastIndexBuffer = NULL ;
}
if ( pBoundBuffer )
{
pBoundBuffer - > Release ( ) ;
}
# endif
}
void Unbind ( IDirect3DVertexBuffer9 * pVertexBuffer )
{
# ifdef _X360
UINT nOffset , nStride ;
IDirect3DVertexBuffer9 * pBoundBuffer ;
for ( int i = 0 ; i < MAX_DX8_STREAMS ; + + i )
{
Dx9Device ( ) - > GetStreamSource ( i , & pBoundBuffer , & nOffset , & nStride ) ;
if ( pBoundBuffer = = pVertexBuffer )
{
// xboxissue - cannot lock indexes set in a d3d device, clear possibly set indices
Dx9Device ( ) - > SetStreamSource ( i , 0 , 0 , 0 ) ;
switch ( i )
{
case 0 :
g_pLastVertex = NULL ;
g_pLastVertexBuffer = NULL ;
break ;
case 1 :
g_pLastColorMesh = NULL ;
g_nLastColorMeshVertOffsetInBytes = 0 ;
break ;
}
}
if ( pBoundBuffer )
{
pBoundBuffer - > Release ( ) ;
}
}
# endif
}
//-----------------------------------------------------------------------------
// Helpers to count texture coordinates
//-----------------------------------------------------------------------------
static int NumTextureCoordinates ( VertexFormat_t vertexFormat )
{
int nTexCoordCount = 0 ;
for ( int i = 0 ; i < VERTEX_MAX_TEXTURE_COORDINATES ; + + i )
{
if ( TexCoordSize ( i , vertexFormat ) = = 0 )
continue ;
+ + nTexCoordCount ;
}
return nTexCoordCount ;
}
//-----------------------------------------------------------------------------
// Makes sure that the render state is always set next time
//-----------------------------------------------------------------------------
static void ResetMeshRenderState ( )
{
SafeRelease ( & g_pLastIndex ) ;
g_pLastIndexBuffer = 0 ;
g_pLastVertex = 0 ;
g_nLastVertOffsetInBytes = 0 ;
g_pLastColorMesh = 0 ;
g_nLastColorMeshVertOffsetInBytes = 0 ;
g_LastVertexIdx = - 1 ;
g_bUsingVertexID = false ;
g_bFlexMeshStreamSet = false ;
g_LastVertexFormat = 0 ;
}
//-----------------------------------------------------------------------------
// Makes sure that the render state is always set next time
//-----------------------------------------------------------------------------
static void ResetIndexBufferRenderState ( )
{
SafeRelease ( & g_pLastIndex ) ;
g_pLastIndexBuffer = 0 ;
g_LastVertexIdx = - 1 ;
}
//-----------------------------------------------------------------------------
//
// Index Buffer implementations begin here
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Globals
//-----------------------------------------------------------------------------
# ifdef _DEBUG
int CIndexBufferDx8 : : s_nBufferCount = 0 ;
# endif
//-----------------------------------------------------------------------------
// Constructor, destructor
//-----------------------------------------------------------------------------
CIndexBufferDx8 : : CIndexBufferDx8 ( ShaderBufferType_t bufferType , MaterialIndexFormat_t fmt , int nIndexCount , const char * pBudgetGroupName ) :
BaseClass ( pBudgetGroupName )
{
// Debugger();
Assert ( nIndexCount ! = 0 ) ;
// NOTE: MATERIAL_INDEX_FORMAT_UNKNOWN can't be dealt with under dx9
// because format is bound at buffer creation time. What we'll do
// is just arbitrarily choose to use a 16-bit index buffer of the same size
if ( fmt = = MATERIAL_INDEX_FORMAT_UNKNOWN )
{
fmt = MATERIAL_INDEX_FORMAT_16BIT ;
nIndexCount / = 2 ;
}
m_pIndexBuffer = NULL ;
m_IndexFormat = fmt ;
m_nBufferSize = nIndexCount * IndexSize ( ) ;
m_nIndexCount = nIndexCount ;
m_nFirstUnwrittenOffset = 0 ;
m_bIsLocked = false ;
m_bIsDynamic = IsDynamicBufferType ( bufferType ) ;
m_bFlush = false ;
# ifdef CHECK_INDICES
m_pShadowIndices = NULL ;
# endif
# ifdef VPROF_ENABLED
m_nVProfFrame = - 1 ;
# endif
}
CIndexBufferDx8 : : ~ CIndexBufferDx8 ( )
{
Free ( ) ;
}
//-----------------------------------------------------------------------------
// Returns the index size
//-----------------------------------------------------------------------------
inline int CIndexBufferDx8 : : IndexSize ( ) const
{
Assert ( m_IndexFormat ! = MATERIAL_INDEX_FORMAT_UNKNOWN ) ;
return ( m_IndexFormat = = MATERIAL_INDEX_FORMAT_16BIT ) ? 2 : 4 ;
}
//-----------------------------------------------------------------------------
// Creates, destroys the index buffer
//-----------------------------------------------------------------------------
bool CIndexBufferDx8 : : Allocate ( )
{
# ifdef OSX
Debugger ( ) ;
# endif
Assert ( ! m_pIndexBuffer ) ;
m_nFirstUnwrittenOffset = 0 ;
// FIXME: This doesn't really work for dynamic buffers; dynamic buffers
// can't have mixed-type indices in them. Bleah.
D3DFORMAT format = ( m_IndexFormat = = MATERIAL_INDEX_FORMAT_32BIT ) ?
D3DFMT_INDEX32 : D3DFMT_INDEX16 ;
DWORD usage = D3DUSAGE_WRITEONLY ;
if ( m_bIsDynamic )
{
usage | = D3DUSAGE_DYNAMIC ;
}
HRESULT hr = Dx9Device ( ) - > CreateIndexBuffer (
m_nBufferSize , usage , format , D3DPOOL_DEFAULT , & m_pIndexBuffer , NULL ) ;
# if !defined( _X360 )
if ( ( hr = = D3DERR_OUTOFVIDEOMEMORY ) | | ( hr = = E_OUTOFMEMORY ) )
{
// Don't have the memory for this. Try flushing all managed resources
// out of vid mem and try again.
// FIXME: need to record this
Dx9Device ( ) - > EvictManagedResources ( ) ;
hr = Dx9Device ( ) - > CreateIndexBuffer (
m_nBufferSize , usage , format , D3DPOOL_DEFAULT , & m_pIndexBuffer , NULL ) ;
}
# endif // !X360
if ( FAILED ( hr ) | | ( m_pIndexBuffer = = NULL ) )
{
Warning ( " CIndexBufferDx8::Allocate: CreateIndexBuffer failed! \n " ) ;
return false ;
}
if ( ! m_bIsDynamic )
{
VPROF_INCREMENT_GROUP_COUNTER ( " TexGroup_global_ " TEXTURE_GROUP_STATIC_INDEX_BUFFER ,
COUNTER_GROUP_TEXTURE_GLOBAL , m_nBufferSize ) ;
}
else
{
VPROF_INCREMENT_GROUP_COUNTER ( " TexGroup_global_ " TEXTURE_GROUP_DYNAMIC_INDEX_BUFFER ,
COUNTER_GROUP_TEXTURE_GLOBAL , m_nBufferSize ) ;
}
# ifdef CHECK_INDICES
Assert ( ! m_pShadowIndices ) ;
m_pShadowIndices = new unsigned char [ m_nBufferSize ] ;
memset ( m_pShadowIndices , 0xFF , m_nBufferSize ) ;
# endif // CHECK_INDICES
# ifdef _DEBUG
+ + s_nBufferCount ;
# endif
return true ;
}
void CIndexBufferDx8 : : Free ( )
{
// FIXME: Unlock(0);
if ( m_pIndexBuffer )
{
# ifdef _DEBUG
- - s_nBufferCount ;
# endif
m_pIndexBuffer - > Release ( ) ;
m_pIndexBuffer = NULL ;
if ( ! m_bIsDynamic )
{
VPROF_INCREMENT_GROUP_COUNTER ( " TexGroup_global_ " TEXTURE_GROUP_STATIC_INDEX_BUFFER ,
COUNTER_GROUP_TEXTURE_GLOBAL , - m_nBufferSize ) ;
}
else
{
VPROF_INCREMENT_GROUP_COUNTER ( " TexGroup_global_ " TEXTURE_GROUP_DYNAMIC_INDEX_BUFFER ,
COUNTER_GROUP_TEXTURE_GLOBAL , - m_nBufferSize ) ;
}
}
# ifdef CHECK_INDICES
if ( m_pShadowIndices )
{
delete [ ] m_pShadowIndices ;
m_pShadowIndices = NULL ;
}
# endif // CHECK_INDICES
}
//-----------------------------------------------------------------------------
// Index buffer information
//-----------------------------------------------------------------------------
int CIndexBufferDx8 : : IndexCount ( ) const
{
Assert ( ! m_bIsDynamic ) ;
return m_nIndexCount ;
}
MaterialIndexFormat_t CIndexBufferDx8 : : IndexFormat ( ) const
{
Assert ( ! m_bIsDynamic ) ;
return m_IndexFormat ;
}
//-----------------------------------------------------------------------------
// Returns true if the buffer is dynamic
//-----------------------------------------------------------------------------
bool CIndexBufferDx8 : : IsDynamic ( ) const
{
return m_bIsDynamic ;
}
//-----------------------------------------------------------------------------
// Only used by dynamic buffers, indicates the next lock should perform a discard.
//-----------------------------------------------------------------------------
void CIndexBufferDx8 : : Flush ( )
{
// This strange-looking line makes a flush only occur if the buffer is dynamic.
m_bFlush = m_bIsDynamic ;
}
//-----------------------------------------------------------------------------
// Returns the D3D buffer
//-----------------------------------------------------------------------------
IDirect3DIndexBuffer9 * CIndexBufferDx8 : : GetDx9Buffer ( )
{
return m_pIndexBuffer ;
}
//-----------------------------------------------------------------------------
// Returns a shadowed index, for validation
//-----------------------------------------------------------------------------
# ifdef CHECK_INDICES
unsigned short CIndexBufferDx8 : : GetShadowIndex ( int i ) const
{
Assert ( i > = 0 & & i < m_nIndexCount ) ;
Assert ( m_IndexFormat = = MATERIAL_INDEX_FORMAT_16BIT ) ;
return * ( unsigned short * ) ( & m_pShadowIndices [ i * IndexSize ( ) ] ) ;
}
# endif // CHECK_INDICES
//-----------------------------------------------------------------------------
// Used to measure how much static buffer memory is touched each frame
//-----------------------------------------------------------------------------
void CIndexBufferDx8 : : HandlePerFrameTextureStats ( int nFrame )
{
# ifdef VPROF_ENABLED
if ( m_nVProfFrame ! = nFrame & & ! m_bIsDynamic )
{
m_nVProfFrame = nFrame ;
VPROF_INCREMENT_GROUP_COUNTER ( " TexGroup_frame_ " TEXTURE_GROUP_STATIC_INDEX_BUFFER ,
COUNTER_GROUP_TEXTURE_PER_FRAME , m_nBufferSize ) ;
}
# endif
}
//-----------------------------------------------------------------------------
// Casts a dynamic buffer to be a particular index type
//-----------------------------------------------------------------------------
void CIndexBufferDx8 : : BeginCastBuffer ( MaterialIndexFormat_t format )
{
// NOTE: This should have no effect under Dx9, since we can't recast index buffers.
Assert ( format ! = MATERIAL_INDEX_FORMAT_UNKNOWN ) ;
Assert ( m_bIsDynamic & & ( m_IndexFormat = = format ) ) ;
}
void CIndexBufferDx8 : : EndCastBuffer ( )
{
// NOTE: This should have no effect under Dx9, since we can't recast index buffers.
}
int CIndexBufferDx8 : : GetRoomRemaining ( ) const
{
return ( m_nBufferSize - m_nFirstUnwrittenOffset ) / IndexSize ( ) ;
}
//-----------------------------------------------------------------------------
// Locks/unlocks the index buffer
//-----------------------------------------------------------------------------
bool CIndexBufferDx8 : : Lock ( int nMaxIndexCount , bool bAppend , IndexDesc_t & desc )
{
Assert ( ! m_bIsLocked & & ( nMaxIndexCount ! = 0 ) & & ( nMaxIndexCount < = m_nIndexCount ) ) ;
Assert ( m_IndexFormat ! = MATERIAL_INDEX_FORMAT_UNKNOWN ) ;
// FIXME: Why do we need to sync matrices now?
ShaderUtil ( ) - > SyncMatrices ( ) ;
g_ShaderMutex . Lock ( ) ;
VPROF ( " CIndexBufferX8::Lock " ) ;
void * pLockedData = NULL ;
HRESULT hr ;
int nMemoryRequired ;
bool bHasEnoughMemory ;
UINT nLockFlags ;
// This can happen if the buffer was locked but a type wasn't bound
if ( m_IndexFormat = = MATERIAL_INDEX_FORMAT_UNKNOWN )
goto indexBufferLockFailed ;
// Just give the app crap buffers to fill up while we're suppressed...
if ( g_pShaderDeviceDx8 - > IsDeactivated ( ) | | ( nMaxIndexCount = = 0 ) )
goto indexBufferLockFailed ;
// Did we ask for something too large?
if ( nMaxIndexCount > m_nIndexCount )
{
Warning ( " Too many indices for index buffer. . tell a programmer (%d>%d) \n " , nMaxIndexCount , m_nIndexCount ) ;
goto indexBufferLockFailed ;
}
// We might not have a buffer owing to alt-tab type stuff
if ( ! m_pIndexBuffer )
{
if ( ! Allocate ( ) )
goto indexBufferLockFailed ;
}
// Check to see if we have enough memory
nMemoryRequired = nMaxIndexCount * IndexSize ( ) ;
bHasEnoughMemory = ( m_nFirstUnwrittenOffset + nMemoryRequired < = m_nBufferSize ) ;
nLockFlags = D3DLOCK_NOSYSLOCK ;
if ( bAppend )
{
// Can't have the first lock after a flush be an appending lock
Assert ( ! m_bFlush ) ;
// If we're appending and we don't have enough room, then puke!
if ( ! bHasEnoughMemory | | m_bFlush )
goto indexBufferLockFailed ;
nLockFlags | = ( m_nFirstUnwrittenOffset = = 0 ) ? D3DLOCK_DISCARD : D3DLOCK_NOOVERWRITE ;
}
else
{
// If we're not appending, no overwrite unless we don't have enough room
// If we're a static buffer, always discard if we're not appending
if ( ! m_bFlush & & bHasEnoughMemory & & m_bIsDynamic )
{
nLockFlags | = ( m_nFirstUnwrittenOffset = = 0 ) ? D3DLOCK_DISCARD : D3DLOCK_NOOVERWRITE ;
}
else
{
if ( m_bIsDynamic )
{
nLockFlags | = D3DLOCK_DISCARD ;
}
m_nFirstUnwrittenOffset = 0 ;
m_bFlush = false ;
}
}
# if !defined( _X360 )
hr = m_pIndexBuffer - > Lock ( m_nFirstUnwrittenOffset , nMemoryRequired , & pLockedData , nLockFlags ) ;
# else
hr = m_pIndexBuffer - > Lock ( 0 , 0 , & pLockedData , nLockFlags ) ;
pLockedData = ( ( unsigned char * ) pLockedData + m_nFirstUnwrittenOffset ) ;
# endif
if ( FAILED ( hr ) )
{
Warning ( " Failed to lock index buffer in CIndexBufferDx8::LockIndexBuffer \n " ) ;
goto indexBufferLockFailed ;
}
desc . m_pIndices = ( unsigned short * ) ( pLockedData ) ;
desc . m_nIndexSize = IndexSize ( ) > > 1 ;
if ( g_pHardwareConfig - > SupportsStreamOffset ( ) )
{
desc . m_nFirstIndex = 0 ;
desc . m_nOffset = m_nFirstUnwrittenOffset ;
}
else
{
desc . m_nFirstIndex = m_nFirstUnwrittenOffset / IndexSize ( ) ;
Assert ( ( int ) ( desc . m_nFirstIndex * IndexSize ( ) ) = = m_nFirstUnwrittenOffset ) ;
desc . m_nOffset = 0 ;
}
m_bIsLocked = true ;
# ifdef CHECK_INDICES
m_nLockIndexBufferSize = nMemoryRequired ;
m_pLockIndexBuffer = desc . m_pIndices ;
m_nLockIndexOffset = m_nFirstUnwrittenOffset ;
# endif // CHECK_INDICES
return true ;
indexBufferLockFailed :
g_ShaderMutex . Unlock ( ) ;
// Set up a bogus index descriptor
desc . m_pIndices = g_nScratchIndexBuffer ;
desc . m_nIndexSize = 0 ;
desc . m_nFirstIndex = 0 ;
desc . m_nOffset = 0 ;
return false ;
}
void CIndexBufferDx8 : : Unlock ( int nWrittenIndexCount , IndexDesc_t & desc )
{
Assert ( nWrittenIndexCount < = m_nIndexCount ) ;
// NOTE: This can happen if another application finishes
// initializing during the construction of a mesh
if ( ! m_bIsLocked )
return ;
# ifdef CHECK_INDICES
memcpy ( ( unsigned char * ) m_pShadowIndices + m_nLockIndexOffset , m_pLockIndexBuffer , nWrittenIndexCount * IndexSize ( ) ) ;
# endif // CHECK_INDICES
if ( m_pIndexBuffer )
{
m_pIndexBuffer - > Unlock ( ) ;
}
m_nFirstUnwrittenOffset + = nWrittenIndexCount * IndexSize ( ) ;
m_bIsLocked = false ;
g_ShaderMutex . Unlock ( ) ;
}
//-----------------------------------------------------------------------------
//
// Vertex Buffer implementations begin here
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// globals
//-----------------------------------------------------------------------------
# ifdef _DEBUG
int CVertexBufferDx8 : : s_nBufferCount = 0 ;
# endif
//-----------------------------------------------------------------------------
// constructor
//-----------------------------------------------------------------------------
CVertexBufferDx8 : : CVertexBufferDx8 ( ShaderBufferType_t type , VertexFormat_t fmt , int nVertexCount , const char * pBudgetGroupName ) :
BaseClass ( pBudgetGroupName )
{
// Debugger();
Assert ( nVertexCount ! = 0 ) ;
m_pVertexBuffer = NULL ;
m_VertexFormat = fmt ;
m_nVertexCount = ( fmt = = VERTEX_FORMAT_UNKNOWN ) ? 0 : nVertexCount ;
m_nBufferSize = ( fmt = = VERTEX_FORMAT_UNKNOWN ) ? nVertexCount : nVertexCount * VertexSize ( ) ;
m_nFirstUnwrittenOffset = 0 ;
m_bIsLocked = false ;
m_bIsDynamic = ( type = = SHADER_BUFFER_TYPE_DYNAMIC ) | | ( type = = SHADER_BUFFER_TYPE_DYNAMIC_TEMP ) ;
m_bFlush = false ;
# ifdef VPROF_ENABLED
if ( ! m_bIsDynamic )
{
char name [ 256 ] ;
V_strcpy_safe ( name , " TexGroup_global_ " ) ;
V_strcat_safe ( name , pBudgetGroupName , sizeof ( name ) ) ;
m_pGlobalCounter = g_VProfCurrentProfile . FindOrCreateCounter ( name , COUNTER_GROUP_TEXTURE_GLOBAL ) ;
V_strcpy_safe ( name , " TexGroup_frame_ " ) ;
V_strcat_safe ( name , pBudgetGroupName , sizeof ( name ) ) ;
m_pFrameCounter = g_VProfCurrentProfile . FindOrCreateCounter ( name , COUNTER_GROUP_TEXTURE_PER_FRAME ) ;
}
else
{
m_pGlobalCounter = g_VProfCurrentProfile . FindOrCreateCounter ( " TexGroup_global_ " TEXTURE_GROUP_DYNAMIC_VERTEX_BUFFER , COUNTER_GROUP_TEXTURE_GLOBAL ) ;
m_pFrameCounter = NULL ;
}
m_nVProfFrame = - 1 ;
# endif
}
CVertexBufferDx8 : : ~ CVertexBufferDx8 ( )
{
Free ( ) ;
}
//-----------------------------------------------------------------------------
// Returns the vertex size
//-----------------------------------------------------------------------------
inline int CVertexBufferDx8 : : VertexSize ( ) const
{
Assert ( m_VertexFormat ! = VERTEX_FORMAT_UNKNOWN ) ;
return VertexFormatSize ( m_VertexFormat ) ;
}
//-----------------------------------------------------------------------------
// Creates, destroys the vertex buffer
//-----------------------------------------------------------------------------
bool CVertexBufferDx8 : : Allocate ( )
{
Assert ( ! m_pVertexBuffer ) ;
m_nFirstUnwrittenOffset = 0 ;
D3DPOOL pool = D3DPOOL_MANAGED ;
# if defined(IS_WINDOWS_PC) && defined(SHADERAPIDX9)
extern bool g_ShaderDeviceUsingD3D9Ex ;
if ( g_ShaderDeviceUsingD3D9Ex )
{
pool = D3DPOOL_DEFAULT ;
}
# endif
DWORD usage = D3DUSAGE_WRITEONLY ;
if ( m_bIsDynamic )
{
usage | = D3DUSAGE_DYNAMIC ;
pool = D3DPOOL_DEFAULT ;
// Dynamic meshes should never be compressed (slows down writing to them)
Assert ( CompressionType ( GetVertexFormat ( ) ) = = VERTEX_COMPRESSION_NONE ) ;
}
HRESULT hr = Dx9Device ( ) - > CreateVertexBuffer (
m_nBufferSize , usage , 0 , pool , & m_pVertexBuffer , NULL ) ;
# if !defined( _X360 )
if ( ( hr = = D3DERR_OUTOFVIDEOMEMORY ) | | ( hr = = E_OUTOFMEMORY ) )
{
// Don't have the memory for this. Try flushing all managed resources
// out of vid mem and try again.
// FIXME: need to record this
Dx9Device ( ) - > EvictManagedResources ( ) ;
hr = Dx9Device ( ) - > CreateVertexBuffer (
m_nBufferSize , usage , 0 , pool , & m_pVertexBuffer , NULL ) ;
}
# endif // !X360
if ( FAILED ( hr ) | | ( m_pVertexBuffer = = NULL ) )
{
Warning ( " CVertexBufferDx8::Allocate: CreateVertexBuffer failed! \n " ) ;
return false ;
}
// Track VB allocations
g_VBAllocTracker - > CountVB ( m_pVertexBuffer , m_bIsDynamic , m_nBufferSize , VertexSize ( ) , GetVertexFormat ( ) ) ;
# ifdef VPROF_ENABLED
if ( IsX360 ( ) | | ! m_bIsDynamic )
{
Assert ( m_pGlobalCounter ) ;
* m_pGlobalCounter + = m_nBufferSize ;
}
# endif
# ifdef _DEBUG
+ + s_nBufferCount ;
# endif
return true ;
}
void CVertexBufferDx8 : : Free ( )
{
// FIXME: Unlock(0);
if ( m_pVertexBuffer )
{
# ifdef _DEBUG
- - s_nBufferCount ;
# endif
// Track VB allocations
g_VBAllocTracker - > UnCountVB ( m_pVertexBuffer ) ;
# ifdef VPROF_ENABLED
if ( IsX360 ( ) | | ! m_bIsDynamic )
{
Assert ( m_pGlobalCounter ) ;
* m_pGlobalCounter - = m_nBufferSize ;
}
# endif
m_pVertexBuffer - > Release ( ) ;
m_pVertexBuffer = NULL ;
}
}
//-----------------------------------------------------------------------------
// Vertex buffer information
//-----------------------------------------------------------------------------
int CVertexBufferDx8 : : VertexCount ( ) const
{
Assert ( ! m_bIsDynamic ) ;
return m_nVertexCount ;
}
VertexFormat_t CVertexBufferDx8 : : GetVertexFormat ( ) const
{
Assert ( ! m_bIsDynamic ) ;
return m_VertexFormat ;
}
//-----------------------------------------------------------------------------
// Returns true if the buffer is dynamic
//-----------------------------------------------------------------------------
bool CVertexBufferDx8 : : IsDynamic ( ) const
{
return m_bIsDynamic ;
}
//-----------------------------------------------------------------------------
// Only used by dynamic buffers, indicates the next lock should perform a discard.
//-----------------------------------------------------------------------------
void CVertexBufferDx8 : : Flush ( )
{
// This strange-looking line makes a flush only occur if the buffer is dynamic.
m_bFlush = m_bIsDynamic ;
}
//-----------------------------------------------------------------------------
// Returns the D3D buffer
//-----------------------------------------------------------------------------
IDirect3DVertexBuffer9 * CVertexBufferDx8 : : GetDx9Buffer ( )
{
return m_pVertexBuffer ;
}
//-----------------------------------------------------------------------------
// Casts a dynamic buffer to be a particular vertex type
//-----------------------------------------------------------------------------
void CVertexBufferDx8 : : BeginCastBuffer ( VertexFormat_t format )
{
Assert ( format ! = MATERIAL_INDEX_FORMAT_UNKNOWN ) ;
Assert ( m_bIsDynamic & & ( m_VertexFormat = = 0 | | m_VertexFormat = = format ) ) ;
if ( ! m_bIsDynamic )
return ;
m_VertexFormat = format ;
int nVertexSize = VertexSize ( ) ;
m_nVertexCount = m_nBufferSize / nVertexSize ;
// snap current position up to the next position based on expected size
// so append can safely guarantee nooverwrite regardless of a format growth or shrinkage
if ( ! g_pHardwareConfig - > SupportsStreamOffset ( ) )
{
m_nFirstUnwrittenOffset = ( m_nFirstUnwrittenOffset + nVertexSize - 1 ) / nVertexSize ;
m_nFirstUnwrittenOffset * = nVertexSize ;
if ( m_nFirstUnwrittenOffset > m_nBufferSize )
{
m_nFirstUnwrittenOffset = m_nBufferSize ;
}
}
}
void CVertexBufferDx8 : : EndCastBuffer ( )
{
Assert ( m_bIsDynamic & & m_VertexFormat ! = 0 ) ;
if ( ! m_bIsDynamic )
return ;
m_VertexFormat = 0 ;
m_nVertexCount = 0 ;
}
//-----------------------------------------------------------------------------
// Returns the number of vertices we can still write into the buffer
//-----------------------------------------------------------------------------
int CVertexBufferDx8 : : GetRoomRemaining ( ) const
{
return ( m_nBufferSize - m_nFirstUnwrittenOffset ) / VertexSize ( ) ;
}
//-----------------------------------------------------------------------------
// Locks/unlocks the vertex buffer mesh
//-----------------------------------------------------------------------------
bool CVertexBufferDx8 : : Lock ( int nMaxVertexCount , bool bAppend , VertexDesc_t & desc )
{
Assert ( ! m_bIsLocked & & ( nMaxVertexCount ! = 0 ) & & ( nMaxVertexCount < = m_nVertexCount ) ) ;
Assert ( m_VertexFormat ! = VERTEX_FORMAT_UNKNOWN ) ;
// FIXME: Why do we need to sync matrices now?
ShaderUtil ( ) - > SyncMatrices ( ) ;
g_ShaderMutex . Lock ( ) ;
VPROF ( " CVertexBufferDx8::Lock " ) ;
void * pLockedData = NULL ;
HRESULT hr ;
int nMemoryRequired ;
bool bHasEnoughMemory ;
UINT nLockFlags ;
// This can happen if the buffer was locked but a type wasn't bound
if ( m_VertexFormat = = VERTEX_FORMAT_UNKNOWN )
goto vertexBufferLockFailed ;
// Just give the app crap buffers to fill up while we're suppressed...
if ( g_pShaderDeviceDx8 - > IsDeactivated ( ) | | ( nMaxVertexCount = = 0 ) )
goto vertexBufferLockFailed ;
// Did we ask for something too large?
if ( nMaxVertexCount > m_nVertexCount )
{
Warning ( " Too many vertices for vertex buffer. . tell a programmer (%d>%d) \n " , nMaxVertexCount , m_nVertexCount ) ;
goto vertexBufferLockFailed ;
}
// We might not have a buffer owing to alt-tab type stuff
if ( ! m_pVertexBuffer )
{
if ( ! Allocate ( ) )
goto vertexBufferLockFailed ;
}
// Check to see if we have enough memory
nMemoryRequired = nMaxVertexCount * VertexSize ( ) ;
bHasEnoughMemory = ( m_nFirstUnwrittenOffset + nMemoryRequired < = m_nBufferSize ) ;
nLockFlags = D3DLOCK_NOSYSLOCK ;
if ( bAppend )
{
// Can't have the first lock after a flush be an appending lock
Assert ( ! m_bFlush ) ;
// If we're appending and we don't have enough room, then puke!
if ( ! bHasEnoughMemory | | m_bFlush )
goto vertexBufferLockFailed ;
nLockFlags | = ( m_nFirstUnwrittenOffset = = 0 ) ? D3DLOCK_DISCARD : D3DLOCK_NOOVERWRITE ;
}
else
{
// If we're not appending, no overwrite unless we don't have enough room
// If we're a static buffer, always discard if we're not appending
if ( ! m_bFlush & & bHasEnoughMemory & & m_bIsDynamic )
{
nLockFlags | = ( m_nFirstUnwrittenOffset = = 0 ) ? D3DLOCK_DISCARD : D3DLOCK_NOOVERWRITE ;
}
else
{
if ( m_bIsDynamic )
{
nLockFlags | = D3DLOCK_DISCARD ;
}
m_nFirstUnwrittenOffset = 0 ;
m_bFlush = false ;
}
}
# if !defined( _X360 )
hr = m_pVertexBuffer - > Lock ( m_nFirstUnwrittenOffset , nMemoryRequired , & pLockedData , nLockFlags ) ;
# else
hr = m_pVertexBuffer - > Lock ( 0 , 0 , & pLockedData , nLockFlags ) ;
pLockedData = ( unsigned char * ) pLockedData + m_nFirstUnwrittenOffset ;
# endif
if ( FAILED ( hr ) )
{
// Check if paged pool is in critical state ( < 5% free )
PAGED_POOL_INFO_t ppi ;
if ( ( SYSCALL_SUCCESS = = Plat_GetPagedPoolInfo ( & ppi ) ) & &
( ( ppi . numPagesFree * 20 ) < ( ppi . numPagesUsed + ppi . numPagesFree ) ) )
{
Error ( " Out of OS Paged Pool Memory! For more information, please see \n http://support.steampowered.com/cgi-bin/steampowered.cfg/php/enduser/std_adp.php?p_faqid=150 \n " ) ;
}
else
{
Warning ( " Failed to lock vertex buffer in CVertexBufferDx8::Lock \n " ) ;
}
goto vertexBufferLockFailed ;
}
ComputeVertexDescription ( ( unsigned char * ) pLockedData , m_VertexFormat , desc ) ;
if ( g_pHardwareConfig - > SupportsStreamOffset ( ) )
{
desc . m_nFirstVertex = 0 ;
desc . m_nOffset = m_nFirstUnwrittenOffset ;
}
else
{
desc . m_nFirstVertex = m_nFirstUnwrittenOffset / VertexSize ( ) ;
desc . m_nOffset = 0 ;
Assert ( m_nFirstUnwrittenOffset = = VertexSize ( ) * desc . m_nFirstVertex ) ;
}
m_bIsLocked = true ;
return true ;
vertexBufferLockFailed :
ComputeVertexDescription ( 0 , 0 , desc ) ;
desc . m_nFirstVertex = 0 ;
desc . m_nOffset = 0 ;
return false ;
}
void CVertexBufferDx8 : : Unlock ( int nWrittenVertexCount , VertexDesc_t & desc )
{
Assert ( nWrittenVertexCount < = m_nVertexCount ) ;
// NOTE: This can happen if another application finishes
// initializing during the construction of a mesh
if ( ! m_bIsLocked )
return ;
if ( m_pVertexBuffer )
{
m_pVertexBuffer - > Unlock ( ) ;
}
m_nFirstUnwrittenOffset + = nWrittenVertexCount * VertexSize ( ) ;
m_bIsLocked = false ;
g_ShaderMutex . Unlock ( ) ;
}
//-----------------------------------------------------------------------------
// Used to measure how much static buffer memory is touched each frame
//-----------------------------------------------------------------------------
void CVertexBufferDx8 : : HandlePerFrameTextureStats ( int nFrame )
{
# ifdef VPROF_ENABLED
if ( m_nVProfFrame ! = nFrame & & ! m_bIsDynamic )
{
m_nVProfFrame = nFrame ;
m_pFrameCounter + = m_nBufferSize ;
}
# endif
}
//-----------------------------------------------------------------------------
// Helpers with meshdescs...
//-----------------------------------------------------------------------------
// FIXME: add compression-agnostic read-accessors (which decompress and return by value, checking desc.m_CompressionType)
inline D3DXVECTOR3 & Position ( MeshDesc_t const & desc , int vert )
{
return * ( D3DXVECTOR3 * ) ( ( unsigned char * ) desc . m_pPosition + vert * desc . m_VertexSize_Position ) ;
}
inline float Wrinkle ( MeshDesc_t const & desc , int vert )
{
return * ( float * ) ( ( unsigned char * ) desc . m_pWrinkle + vert * desc . m_VertexSize_Wrinkle ) ;
}
inline D3DXVECTOR3 & BoneWeight ( MeshDesc_t const & desc , int vert )
{
Assert ( desc . m_CompressionType = = VERTEX_COMPRESSION_NONE ) ;
return * ( D3DXVECTOR3 * ) ( ( unsigned char * ) desc . m_pBoneWeight + vert * desc . m_VertexSize_BoneWeight ) ;
}
inline unsigned char * BoneIndex ( MeshDesc_t const & desc , int vert )
{
return desc . m_pBoneMatrixIndex + vert * desc . m_VertexSize_BoneMatrixIndex ;
}
inline D3DXVECTOR3 & Normal ( MeshDesc_t const & desc , int vert )
{
Assert ( desc . m_CompressionType = = VERTEX_COMPRESSION_NONE ) ;
return * ( D3DXVECTOR3 * ) ( ( unsigned char * ) desc . m_pNormal + vert * desc . m_VertexSize_Normal ) ;
}
inline unsigned char * Color ( MeshDesc_t const & desc , int vert )
{
return desc . m_pColor + vert * desc . m_VertexSize_Color ;
}
inline D3DXVECTOR2 & TexCoord ( MeshDesc_t const & desc , int vert , int stage )
{
return * ( D3DXVECTOR2 * ) ( ( unsigned char * ) desc . m_pTexCoord [ stage ] + vert * desc . m_VertexSize_TexCoord [ stage ] ) ;
}
inline D3DXVECTOR3 & TangentS ( MeshDesc_t const & desc , int vert )
{
return * ( D3DXVECTOR3 * ) ( ( unsigned char * ) desc . m_pTangentS + vert * desc . m_VertexSize_TangentS ) ;
}
inline D3DXVECTOR3 & TangentT ( MeshDesc_t const & desc , int vert )
{
return * ( D3DXVECTOR3 * ) ( ( unsigned char * ) desc . m_pTangentT + vert * desc . m_VertexSize_TangentT ) ;
}
//-----------------------------------------------------------------------------
//
// Base mesh
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
CBaseMeshDX8 : : CBaseMeshDX8 ( ) : m_VertexFormat ( 0 )
{
m_bMeshLocked = false ;
# ifdef DBGFLAG_ASSERT
m_IsDrawing = false ;
m_pMaterial = 0 ;
# endif
}
CBaseMeshDX8 : : ~ CBaseMeshDX8 ( )
{
}
//-----------------------------------------------------------------------------
// For debugging...
//-----------------------------------------------------------------------------
bool CBaseMeshDX8 : : DebugTrace ( ) const
{
# ifdef _DEBUG
if ( m_pMaterial )
return m_pMaterial - > PerformDebugTrace ( ) ;
# endif
return false ;
}
void CBaseMeshDX8 : : SetMaterial ( IMaterial * pMaterial )
{
# ifdef DBGFLAG_ASSERT
m_pMaterial = static_cast < IMaterialInternal * > ( pMaterial ) ;
# endif
}
//-----------------------------------------------------------------------------
// Sets, gets the vertex format
//-----------------------------------------------------------------------------
void CBaseMeshDX8 : : SetVertexFormat ( VertexFormat_t format )
{
m_VertexFormat = format ;
}
VertexFormat_t CBaseMeshDX8 : : GetVertexFormat ( ) const
{
return m_VertexFormat ;
}
//-----------------------------------------------------------------------------
// Sets/gets the morph format
//-----------------------------------------------------------------------------
void CBaseMeshDX8 : : SetMorphFormat ( MorphFormat_t format )
{
m_MorphFormat = format ;
}
MorphFormat_t CBaseMeshDX8 : : GetMorphFormat ( ) const
{
return m_MorphFormat ;
}
//-----------------------------------------------------------------------------
// Am I using morph data?
//-----------------------------------------------------------------------------
bool CBaseMeshDX8 : : IsUsingMorphData ( ) const
{
LOCK_SHADERAPI ( ) ;
// We're not using a morph unless the bound morph is a superset of what the rendermesh needs
MorphFormat_t morphFormat = GetMorphFormat ( ) ;
if ( ! morphFormat )
return false ;
return ( ( morphFormat & ShaderUtil ( ) - > GetBoundMorphFormat ( ) ) = = morphFormat ) ;
}
//-----------------------------------------------------------------------------
// Do I need to reset the vertex format?
//-----------------------------------------------------------------------------
bool CBaseMeshDX8 : : NeedsVertexFormatReset ( VertexFormat_t fmt ) const
{
return m_VertexFormat ! = fmt ;
}
//-----------------------------------------------------------------------------
// Do I have enough room?
//-----------------------------------------------------------------------------
bool CBaseMeshDX8 : : HasEnoughRoom ( int nVertexCount , int nIndexCount ) const
{
// by default, we do
return true ;
}
//-----------------------------------------------------------------------------
// Estimate the memory used
//-----------------------------------------------------------------------------
unsigned CBaseMeshDX8 : : ComputeMemoryUsed ( )
{
unsigned size = 0 ;
if ( GetVertexBuffer ( ) )
{
size + = GetVertexBuffer ( ) - > VertexCount ( ) * GetVertexBuffer ( ) - > VertexSize ( ) ;
}
if ( GetIndexBuffer ( ) )
{
size + = GetIndexBuffer ( ) - > IndexCount ( ) * GetIndexBuffer ( ) - > IndexSize ( ) ;
}
return size ;
}
//-----------------------------------------------------------------------------
// Locks mesh for modifying
//-----------------------------------------------------------------------------
void CBaseMeshDX8 : : ModifyBeginEx ( bool bReadOnly , int nFirstVertex , int nVertexCount , int nFirstIndex , int nIndexCount , MeshDesc_t & desc )
{
LOCK_SHADERAPI ( ) ;
// for the time being, disallow for most cases
Assert ( 0 ) ;
}
void CBaseMeshDX8 : : ModifyBegin ( int nFirstVertex , int nVertexCount , int nFirstIndex , int nIndexCount , MeshDesc_t & desc )
{
LOCK_SHADERAPI ( ) ;
// for the time being, disallow for most cases
Assert ( 0 ) ;
}
void CBaseMeshDX8 : : ModifyEnd ( MeshDesc_t & desc )
{
LOCK_SHADERAPI ( ) ;
// for the time being, disallow for most cases
Assert ( 0 ) ;
}
//-----------------------------------------------------------------------------
// Begins a pass
//-----------------------------------------------------------------------------
void CBaseMeshDX8 : : BeginPass ( )
{
LOCK_SHADERAPI ( ) ;
}
//-----------------------------------------------------------------------------
// Sets the render state and gets the drawing going
//-----------------------------------------------------------------------------
inline void CBaseMeshDX8 : : DrawMesh ( )
{
# ifdef DBGFLAG_ASSERT
// Make sure we're not drawing...
Assert ( ! m_IsDrawing ) ;
m_IsDrawing = true ;
# endif
// This is going to cause RenderPass to get called a bunch
ShaderAPI ( ) - > DrawMesh ( this ) ;
# ifdef DBGFLAG_ASSERT
m_IsDrawing = false ;
# endif
}
//-----------------------------------------------------------------------------
// Spews the mesh data
//-----------------------------------------------------------------------------
void CBaseMeshDX8 : : Spew ( int nVertexCount , int nIndexCount , const MeshDesc_t & spewDesc )
{
LOCK_SHADERAPI ( ) ;
// This has regressed.
int i ;
// FIXME: just fall back to the base class (CVertexBufferBase) version of this function!
# ifdef _DEBUG
if ( m_pMaterial )
{
Plat_DebugString ( ( const char * ) m_pMaterial - > GetName ( ) ) ;
Plat_DebugString ( " \n " ) ;
}
# endif // _DEBUG
// This is needed so buffering can just use this
VertexFormat_t fmt = m_VertexFormat ;
// Set up the vertex descriptor
MeshDesc_t desc = spewDesc ;
char tempbuf [ 256 ] ;
char * temp = tempbuf ;
sprintf ( tempbuf , " \n Verts: (Vertex Format %llx) \n " , fmt ) ;
Plat_DebugString ( tempbuf ) ;
CVertexBufferBase : : PrintVertexFormat ( fmt ) ;
int numBoneWeights = NumBoneWeights ( fmt ) ;
for ( i = 0 ; i < nVertexCount ; + + i )
{
temp + = sprintf ( temp , " [%4d] " , i + desc . m_nFirstVertex ) ;
if ( fmt & VERTEX_POSITION )
{
D3DXVECTOR3 & pos = Position ( desc , i ) ;
temp + = sprintf ( temp , " P %8.2f %8.2f %8.2f " ,
pos [ 0 ] , pos [ 1 ] , pos [ 2 ] ) ;
}
if ( fmt & VERTEX_WRINKLE )
{
float flWrinkle = Wrinkle ( desc , i ) ;
temp + = sprintf ( temp , " Wr %8.2f " , flWrinkle ) ;
}
if ( numBoneWeights > 0 )
{
temp + = sprintf ( temp , " BW " ) ;
float * pWeight = BoneWeight ( desc , i ) ;
for ( int j = 0 ; j < numBoneWeights ; + + j )
{
temp + = sprintf ( temp , " %1.2f " , pWeight [ j ] ) ;
}
}
if ( fmt & VERTEX_BONE_INDEX )
{
unsigned char * pIndex = BoneIndex ( desc , i ) ;
temp + = sprintf ( temp , " BI %d %d %d %d " , ( int ) pIndex [ 0 ] , ( int ) pIndex [ 1 ] , ( int ) pIndex [ 2 ] , ( int ) pIndex [ 3 ] ) ;
Assert ( pIndex [ 0 ] < 16 ) ;
Assert ( pIndex [ 1 ] < 16 ) ;
Assert ( pIndex [ 2 ] < 16 ) ;
Assert ( pIndex [ 3 ] < 16 ) ;
}
if ( fmt & VERTEX_NORMAL )
{
D3DXVECTOR3 & normal = Normal ( desc , i ) ;
temp + = sprintf ( temp , " N %1.2f %1.2f %1.2f " ,
normal [ 0 ] , normal [ 1 ] , normal [ 2 ] ) ;
}
if ( fmt & VERTEX_COLOR )
{
unsigned char * pColor = Color ( desc , i ) ;
temp + = sprintf ( temp , " C b %3d g %3d r %3d a %3d " ,
pColor [ 0 ] , pColor [ 1 ] , pColor [ 2 ] , pColor [ 3 ] ) ;
}
for ( int j = 0 ; j < VERTEX_MAX_TEXTURE_COORDINATES ; + + j )
{
if ( TexCoordSize ( j , fmt ) > 0 )
{
D3DXVECTOR2 & texcoord = TexCoord ( desc , i , j ) ;
temp + = sprintf ( temp , " T%d %.2f %.2f " , j , texcoord [ 0 ] , texcoord [ 1 ] ) ;
}
}
if ( fmt & VERTEX_TANGENT_S )
{
D3DXVECTOR3 & tangentS = TangentS ( desc , i ) ;
temp + = sprintf ( temp , " S %1.2f %1.2f %1.2f " ,
tangentS [ 0 ] , tangentS [ 1 ] , tangentS [ 2 ] ) ;
}
if ( fmt & VERTEX_TANGENT_T )
{
D3DXVECTOR3 & tangentT = TangentT ( desc , i ) ;
temp + = sprintf ( temp , " T %1.2f %1.2f %1.2f " ,
tangentT [ 0 ] , tangentT [ 1 ] , tangentT [ 2 ] ) ;
}
sprintf ( temp , " \n " ) ;
Plat_DebugString ( tempbuf ) ;
temp = tempbuf ;
}
sprintf ( tempbuf , " \n Indices: %d \n " , nIndexCount ) ;
Plat_DebugString ( tempbuf ) ;
for ( i = 0 ; i < nIndexCount ; + + i )
{
temp + = sprintf ( temp , " %d " , ( int ) desc . m_pIndices [ i ] ) ;
if ( ( i & 0x0F ) = = 0x0F )
{
sprintf ( temp , " \n " ) ;
Plat_DebugString ( tempbuf ) ;
tempbuf [ 0 ] = ' \0 ' ;
temp = tempbuf ;
}
}
sprintf ( temp , " \n " ) ;
Plat_DebugString ( tempbuf ) ;
}
void CBaseMeshDX8 : : ValidateData ( int nVertexCount , int nIndexCount , const MeshDesc_t & spewDesc )
{
LOCK_SHADERAPI ( ) ;
# ifdef VALIDATE_DEBUG
int i ;
// FIXME: just fall back to the base class (CVertexBufferBase) version of this function!
// This is needed so buffering can just use this
VertexFormat_t fmt = m_pMaterial - > GetVertexUsage ( ) ;
// Set up the vertex descriptor
MeshDesc_t desc = spewDesc ;
int numBoneWeights = NumBoneWeights ( fmt ) ;
for ( i = 0 ; i < nVertexCount ; + + i )
{
if ( fmt & VERTEX_POSITION )
{
D3DXVECTOR3 & pos = Position ( desc , i ) ;
Assert ( IsFinite ( pos [ 0 ] ) & & IsFinite ( pos [ 1 ] ) & & IsFinite ( pos [ 2 ] ) ) ;
}
if ( fmt & VERTEX_WRINKLE )
{
float flWrinkle = Wrinkle ( desc , i ) ;
Assert ( IsFinite ( flWrinkle ) ) ;
}
if ( numBoneWeights > 0 )
{
float * pWeight = BoneWeight ( desc , i ) ;
for ( int j = 0 ; j < numBoneWeights ; + + j )
{
Assert ( pWeight [ j ] > = 0.0f & & pWeight [ j ] < = 1.0f ) ;
}
}
if ( fmt & VERTEX_BONE_INDEX )
{
unsigned char * pIndex = BoneIndex ( desc , i ) ;
Assert ( pIndex [ 0 ] > = 0 & & pIndex [ 0 ] < 16 ) ;
Assert ( pIndex [ 1 ] > = 0 & & pIndex [ 1 ] < 16 ) ;
Assert ( pIndex [ 2 ] > = 0 & & pIndex [ 2 ] < 16 ) ;
Assert ( pIndex [ 3 ] > = 0 & & pIndex [ 3 ] < 16 ) ;
}
if ( fmt & VERTEX_NORMAL )
{
D3DXVECTOR3 & normal = Normal ( desc , i ) ;
Assert ( normal [ 0 ] > = - 1.05f & & normal [ 0 ] < = 1.05f ) ;
Assert ( normal [ 1 ] > = - 1.05f & & normal [ 1 ] < = 1.05f ) ;
Assert ( normal [ 2 ] > = - 1.05f & & normal [ 2 ] < = 1.05f ) ;
}
if ( fmt & VERTEX_COLOR )
{
int * pColor = ( int * ) Color ( desc , i ) ;
Assert ( * pColor ! = FLOAT32_NAN_BITS ) ;
}
for ( int j = 0 ; j < VERTEX_MAX_TEXTURE_COORDINATES ; + + j )
{
if ( TexCoordSize ( j , fmt ) > 0 )
{
D3DXVECTOR2 & texcoord = TexCoord ( desc , i , j ) ;
Assert ( IsFinite ( texcoord [ 0 ] ) & & IsFinite ( texcoord [ 1 ] ) ) ;
}
}
if ( fmt & VERTEX_TANGENT_S )
{
D3DXVECTOR3 & tangentS = TangentS ( desc , i ) ;
Assert ( IsFinite ( tangentS [ 0 ] ) & & IsFinite ( tangentS [ 1 ] ) & & IsFinite ( tangentS [ 2 ] ) ) ;
}
if ( fmt & VERTEX_TANGENT_T )
{
D3DXVECTOR3 & tangentT = TangentT ( desc , i ) ;
Assert ( IsFinite ( tangentT [ 0 ] ) & & IsFinite ( tangentT [ 1 ] ) & & IsFinite ( tangentT [ 2 ] ) ) ;
}
}
# endif // _DEBUG
}
void CBaseMeshDX8 : : Draw ( CPrimList * pLists , int nLists )
{
LOCK_SHADERAPI ( ) ;
Assert ( ! " CBaseMeshDX8::Draw(CPrimList, int): should never get here. " ) ;
}
// Copy verts and/or indices to a mesh builder. This only works for temp meshes!
void CBaseMeshDX8 : : 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 )
{
LOCK_SHADERAPI ( ) ;
Assert ( false ) ;
Warning ( " CopyToMeshBuilder called on something other than a temp mesh. \n " ) ;
}
//-----------------------------------------------------------------------------
//
// static mesh
//
//-----------------------------------------------------------------------------
CPrimList * CMeshDX8 : : s_pPrims ;
int CMeshDX8 : : s_nPrims ;
unsigned int CMeshDX8 : : s_FirstVertex ;
unsigned int CMeshDX8 : : s_NumVertices ;
//-----------------------------------------------------------------------------
// Computes the mode
//-----------------------------------------------------------------------------
inline D3DPRIMITIVETYPE ComputeMode ( MaterialPrimitiveType_t type )
{
switch ( type )
{
# ifdef _X360
case MATERIAL_INSTANCED_QUADS :
return D3DPT_QUADLIST ;
# endif
case MATERIAL_POINTS :
return D3DPT_POINTLIST ;
case MATERIAL_LINES :
return D3DPT_LINELIST ;
case MATERIAL_TRIANGLES :
return D3DPT_TRIANGLELIST ;
case MATERIAL_TRIANGLE_STRIP :
return D3DPT_TRIANGLESTRIP ;
// Here, we expect to have the type set later. only works for static meshes
case MATERIAL_HETEROGENOUS :
return ( D3DPRIMITIVETYPE ) - 1 ;
default :
Assert ( 0 ) ;
return ( D3DPRIMITIVETYPE ) - 1 ;
}
}
//-----------------------------------------------------------------------------
// constructor
//-----------------------------------------------------------------------------
CMeshDX8 : : CMeshDX8 ( const char * pTextureGroupName ) : m_NumVertices ( 0 ) , m_NumIndices ( 0 ) , m_pVertexBuffer ( 0 ) ,
m_pColorMesh ( 0 ) , m_nColorMeshVertOffsetInBytes ( 0 ) ,
m_pIndexBuffer ( 0 ) , m_Type ( MATERIAL_TRIANGLES ) , m_IsVBLocked ( false ) ,
m_IsIBLocked ( false )
{
m_pTextureGroupName = pTextureGroupName ;
m_Mode = ComputeMode ( m_Type ) ;
m_bHasFlexVerts = false ;
m_pFlexVertexBuffer = NULL ;
m_nFlexVertOffsetInBytes = 0 ;
}
CMeshDX8 : : ~ CMeshDX8 ( )
{
// Don't release the vertex buffer
if ( ! g_MeshMgr . IsDynamicMesh ( this ) )
{
if ( m_pVertexBuffer )
{
delete m_pVertexBuffer ;
}
if ( m_pIndexBuffer )
{
SafeRelease ( & m_pIndexBuffer ) ;
}
}
}
void CMeshDX8 : : SetFlexMesh ( IMesh * pMesh , int nVertexOffsetInBytes )
{
if ( ! ShaderUtil ( ) - > OnSetFlexMesh ( this , pMesh , nVertexOffsetInBytes ) )
return ;
LOCK_SHADERAPI ( ) ;
m_nFlexVertOffsetInBytes = nVertexOffsetInBytes ; // Offset into dynamic mesh (in bytes)
if ( pMesh )
{
m_flexVertCount = pMesh - > VertexCount ( ) ;
pMesh - > MarkAsDrawn ( ) ;
CBaseMeshDX8 * pBaseMesh = static_cast < CBaseMeshDX8 * > ( pMesh ) ;
m_pFlexVertexBuffer = pBaseMesh - > GetVertexBuffer ( ) ;
m_bHasFlexVerts = true ;
}
else
{
m_flexVertCount = 0 ;
m_pFlexVertexBuffer = NULL ;
m_bHasFlexVerts = false ;
}
}
void CMeshDX8 : : DisableFlexMesh ( )
{
CMeshDX8 : : SetFlexMesh ( NULL , 0 ) ;
}
bool CMeshDX8 : : HasFlexMesh ( ) const
{
LOCK_SHADERAPI ( ) ;
return m_bHasFlexVerts ;
}
void CMeshDX8 : : SetColorMesh ( IMesh * pColorMesh , int nVertexOffsetInBytes )
{
if ( ! ShaderUtil ( ) - > OnSetColorMesh ( this , pColorMesh , nVertexOffsetInBytes ) )
return ;
LOCK_SHADERAPI ( ) ;
m_pColorMesh = ( CMeshDX8 * ) pColorMesh ; // dangerous conversion! garymcthack
m_nColorMeshVertOffsetInBytes = nVertexOffsetInBytes ;
Assert ( m_pColorMesh | | ( nVertexOffsetInBytes = = 0 ) ) ;
# ifdef _DEBUG
if ( pColorMesh )
{
int nVertexCount = VertexCount ( ) ;
int numVertsColorMesh = m_pColorMesh - > VertexCount ( ) ;
Assert ( numVertsColorMesh > = nVertexCount ) ;
}
# endif
}
void CMeshDX8 : : HandleLateCreation ( )
{
if ( m_pVertexBuffer )
{
m_pVertexBuffer - > HandleLateCreation ( ) ;
}
if ( m_pIndexBuffer )
{
m_pIndexBuffer - > HandleLateCreation ( ) ;
}
if ( m_pFlexVertexBuffer )
{
m_pFlexVertexBuffer - > HandleLateCreation ( ) ;
}
if ( m_pColorMesh )
{
m_pColorMesh - > HandleLateCreation ( ) ;
}
}
bool CMeshDX8 : : HasColorMesh ( ) const
{
LOCK_SHADERAPI ( ) ;
return ( m_pColorMesh ! = NULL ) ;
}
//-----------------------------------------------------------------------------
// Locks/ unlocks the vertex buffer
//-----------------------------------------------------------------------------
bool CMeshDX8 : : Lock ( int nVertexCount , bool bAppend , VertexDesc_t & desc )
{
Assert ( ! m_IsVBLocked ) ;
// Just give the app crap buffers to fill up while we're suppressed...
if ( g_pShaderDeviceDx8 - > IsDeactivated ( ) | | ( nVertexCount = = 0 ) )
{
// Set up the vertex descriptor
CVertexBufferBase : : ComputeVertexDescription ( 0 , 0 , desc ) ;
desc . m_nFirstVertex = 0 ;
return false ;
}
// Static vertex buffer case
if ( ! m_pVertexBuffer )
{
int size = g_MeshMgr . VertexFormatSize ( m_VertexFormat ) ;
m_pVertexBuffer = new CVertexBuffer ( Dx9Device ( ) , m_VertexFormat , 0 , size , nVertexCount , m_pTextureGroupName , ShaderAPI ( ) - > UsingSoftwareVertexProcessing ( ) ) ;
}
// Lock it baby
int nMaxVerts , nMaxIndices ;
g_MeshMgr . GetMaxToRender ( this , false , & nMaxVerts , & nMaxIndices ) ;
if ( ! g_pHardwareConfig - > SupportsStreamOffset ( ) )
{
// Without stream offset, we can't use VBs greater than 65535 verts (due to our using 16-bit indices)
Assert ( nVertexCount < = nMaxVerts ) ;
}
unsigned char * pVertexMemory = m_pVertexBuffer - > Lock ( nVertexCount , desc . m_nFirstVertex ) ;
if ( ! pVertexMemory )
{
if ( nVertexCount > nMaxVerts )
{
Assert ( 0 ) ;
Error ( " Too many verts for a dynamic vertex buffer (%d>%d) Tell a programmer to up VERTEX_BUFFER_SIZE. \n " ,
( int ) nVertexCount , ( int ) nMaxVerts ) ;
}
else
{
// Check if paged pool is in critical state ( < 5% free )
PAGED_POOL_INFO_t ppi ;
if ( ( SYSCALL_SUCCESS = = Plat_GetPagedPoolInfo ( & ppi ) ) & &
( ( ppi . numPagesFree * 20 ) < ( ppi . numPagesUsed + ppi . numPagesFree ) ) )
{
Error ( " Out of OS Paged Pool Memory! For more information, please see \n http://support.steampowered.com/cgi-bin/steampowered.cfg/php/enduser/std_adp.php?p_faqid=150 \n " ) ;
}
else
{
Assert ( 0 ) ;
Error ( " failed to lock vertex buffer in CMeshDX8::LockVertexBuffer: nVertexCount=%d, nFirstVertex=%d \n " , nVertexCount , desc . m_nFirstVertex ) ;
}
}
CVertexBufferBase : : ComputeVertexDescription ( 0 , 0 , desc ) ;
return false ;
}
// Set up the vertex descriptor
CVertexBufferBase : : ComputeVertexDescription ( pVertexMemory , m_VertexFormat , desc ) ;
m_IsVBLocked = true ;
# ifdef RECORDING
m_LockVertexBufferSize = nVertexCount * desc . m_ActualVertexSize ;
m_LockVertexBuffer = pVertexMemory ;
# endif
return true ;
}
void CMeshDX8 : : Unlock ( int nVertexCount , VertexDesc_t & desc )
{
// NOTE: This can happen if another application finishes
// initializing during the construction of a mesh
if ( ! m_IsVBLocked )
return ;
// This is recorded for debugging. . not sent to dx.
RECORD_COMMAND ( DX8_SET_VERTEX_BUFFER_FORMAT , 2 ) ;
RECORD_INT ( m_pVertexBuffer - > UID ( ) ) ;
RECORD_INT ( m_VertexFormat ) ;
RECORD_COMMAND ( DX8_VERTEX_DATA , 3 ) ;
RECORD_INT ( m_pVertexBuffer - > UID ( ) ) ;
RECORD_INT ( m_LockVertexBufferSize ) ;
RECORD_STRUCT ( m_LockVertexBuffer , m_LockVertexBufferSize ) ;
Assert ( m_pVertexBuffer ) ;
m_pVertexBuffer - > Unlock ( nVertexCount ) ;
m_IsVBLocked = false ;
}
//-----------------------------------------------------------------------------
// Locks/unlocks the index buffer
//-----------------------------------------------------------------------------
int CMeshDX8 : : Lock ( bool bReadOnly , int nFirstIndex , int nIndexCount , IndexDesc_t & desc )
{
Assert ( ! m_IsIBLocked ) ;
// Just give the app crap buffers to fill up while we're suppressed...
if ( g_pShaderDeviceDx8 - > IsDeactivated ( ) | | ( nIndexCount = = 0 ) )
{
// Set up a bogus index descriptor
desc . m_pIndices = g_nScratchIndexBuffer ;
desc . m_nIndexSize = 0 ;
return 0 ;
}
// Static vertex buffer case
if ( ! m_pIndexBuffer )
{
SafeAssign ( & m_pIndexBuffer , new CIndexBuffer ( Dx9Device ( ) , nIndexCount , ShaderAPI ( ) - > UsingSoftwareVertexProcessing ( ) ) ) ;
}
int startIndex ;
desc . m_pIndices = m_pIndexBuffer - > Lock ( bReadOnly , nIndexCount , startIndex , nFirstIndex ) ;
if ( ! desc . m_pIndices )
{
desc . m_pIndices = g_nScratchIndexBuffer ;
desc . m_nIndexSize = 0 ;
// Check if paged pool is in critical state ( < 5% free )
PAGED_POOL_INFO_t ppi ;
if ( ( SYSCALL_SUCCESS = = Plat_GetPagedPoolInfo ( & ppi ) ) & &
( ( ppi . numPagesFree * 20 ) < ( ppi . numPagesUsed + ppi . numPagesFree ) ) )
{
Error ( " Out of OS Paged Pool Memory! For more information, please see \n http://support.steampowered.com/cgi-bin/steampowered.cfg/php/enduser/std_adp.php?p_faqid=150 \n " ) ;
}
else
{
Assert ( 0 ) ;
Error ( " failed to lock index buffer in CMeshDX8::LockIndexBuffer \n " ) ;
}
return 0 ;
}
desc . m_nIndexSize = 1 ;
m_IsIBLocked = true ;
# if defined( RECORDING ) || defined( CHECK_INDICES )
m_LockIndexBufferSize = nIndexCount * 2 ;
m_LockIndexBuffer = desc . m_pIndices ;
# endif
return startIndex ;
}
void CMeshDX8 : : Unlock ( int nIndexCount , IndexDesc_t & desc )
{
// NOTE: This can happen if another application finishes
// initializing during the construction of a mesh
if ( ! m_IsIBLocked )
return ;
RECORD_COMMAND ( DX8_INDEX_DATA , 3 ) ;
RECORD_INT ( m_pIndexBuffer - > UID ( ) ) ;
RECORD_INT ( m_LockIndexBufferSize ) ;
RECORD_STRUCT ( m_LockIndexBuffer , m_LockIndexBufferSize ) ;
Assert ( m_pIndexBuffer ) ;
# ifdef CHECK_INDICES
m_pIndexBuffer - > UpdateShadowIndices ( ( unsigned short * ) m_LockIndexBuffer ) ;
# endif // CHECK_INDICES
// Unlock, and indicate how many vertices we actually used
m_pIndexBuffer - > Unlock ( nIndexCount ) ;
m_IsIBLocked = false ;
}
//-----------------------------------------------------------------------------
// Locks/unlocks the entire mesh
//-----------------------------------------------------------------------------
void CMeshDX8 : : LockMesh ( int nVertexCount , int nIndexCount , MeshDesc_t & desc )
{
ShaderUtil ( ) - > SyncMatrices ( ) ;
g_ShaderMutex . Lock ( ) ;
VPROF ( " CMeshDX8::LockMesh " ) ;
Lock ( nVertexCount , false , * static_cast < VertexDesc_t * > ( & desc ) ) ;
if ( m_Type ! = MATERIAL_POINTS )
{
Lock ( false , - 1 , nIndexCount , * static_cast < IndexDesc_t * > ( & desc ) ) ;
}
else
{
desc . m_pIndices = g_nScratchIndexBuffer ;
desc . m_nIndexSize = 0 ;
}
CBaseMeshDX8 : : m_bMeshLocked = true ;
}
void CMeshDX8 : : UnlockMesh ( int nVertexCount , int nIndexCount , MeshDesc_t & desc )
{
VPROF ( " CMeshDX8::UnlockMesh " ) ;
Assert ( CBaseMeshDX8 : : m_bMeshLocked ) ;
Unlock ( nVertexCount , * static_cast < VertexDesc_t * > ( & desc ) ) ;
if ( m_Type ! = MATERIAL_POINTS )
{
Unlock ( nIndexCount , * static_cast < IndexDesc_t * > ( & desc ) ) ;
}
// The actual # we wrote
m_NumVertices = nVertexCount ;
m_NumIndices = nIndexCount ;
CBaseMeshDX8 : : m_bMeshLocked = false ;
g_ShaderMutex . Unlock ( ) ;
}
//-----------------------------------------------------------------------------
// Locks mesh for modifying
//-----------------------------------------------------------------------------
void CMeshDX8 : : ModifyBeginEx ( bool bReadOnly , int nFirstVertex , int nVertexCount , int nFirstIndex , int nIndexCount , MeshDesc_t & desc )
{
VPROF ( " CMeshDX8::ModifyBegin " ) ;
// Just give the app crap buffers to fill up while we're suppressed...
if ( g_pShaderDeviceDx8 - > IsDeactivated ( ) )
{
// Set up a bogus descriptor
g_MeshMgr . ComputeVertexDescription ( 0 , 0 , desc ) ;
desc . m_pIndices = g_nScratchIndexBuffer ;
desc . m_nIndexSize = 0 ;
return ;
}
Assert ( m_pVertexBuffer ) ;
// Lock it baby
unsigned char * pVertexMemory = m_pVertexBuffer - > Modify ( bReadOnly , nFirstVertex , nVertexCount ) ;
if ( pVertexMemory )
{
m_IsVBLocked = true ;
g_MeshMgr . ComputeVertexDescription ( pVertexMemory , m_VertexFormat , desc ) ;
# ifdef RECORDING
m_LockVertexBufferSize = nVertexCount * desc . m_ActualVertexSize ;
m_LockVertexBuffer = pVertexMemory ;
# endif
}
desc . m_nFirstVertex = nFirstVertex ;
Lock ( bReadOnly , nFirstIndex , nIndexCount , * static_cast < IndexDesc_t * > ( & desc ) ) ;
}
void CMeshDX8 : : ModifyBegin ( int nFirstVertex , int nVertexCount , int nFirstIndex , int nIndexCount , MeshDesc_t & desc )
{
ModifyBeginEx ( false , nFirstVertex , nVertexCount , nFirstIndex , nIndexCount , desc ) ;
}
void CMeshDX8 : : ModifyEnd ( MeshDesc_t & desc )
{
VPROF ( " CMeshDX8::ModifyEnd " ) ;
Unlock ( 0 , * static_cast < IndexDesc_t * > ( & desc ) ) ;
Unlock ( 0 , * static_cast < VertexDesc_t * > ( & desc ) ) ;
}
//-----------------------------------------------------------------------------
// returns the # of vertices (static meshes only)
//-----------------------------------------------------------------------------
int CMeshDX8 : : VertexCount ( ) const
{
return m_pVertexBuffer ? m_pVertexBuffer - > VertexCount ( ) : 0 ;
}
//-----------------------------------------------------------------------------
// returns the # of indices
//-----------------------------------------------------------------------------
int CMeshDX8 : : IndexCount ( ) const
{
return m_pIndexBuffer ? m_pIndexBuffer - > IndexCount ( ) : 0 ;
}
//-----------------------------------------------------------------------------
// Sets up the vertex and index buffers
//-----------------------------------------------------------------------------
void CMeshDX8 : : UseIndexBuffer ( CIndexBuffer * pBuffer )
{
SafeAssign ( & m_pIndexBuffer , pBuffer ) ;
}
void CMeshDX8 : : UseVertexBuffer ( CVertexBuffer * pBuffer )
{
m_pVertexBuffer = pBuffer ;
}
//-----------------------------------------------------------------------------
// Sets the primitive type
//-----------------------------------------------------------------------------
void CMeshDX8 : : SetPrimitiveType ( MaterialPrimitiveType_t type )
{
Assert ( IsX360 ( ) | | ( type ! = MATERIAL_INSTANCED_QUADS ) ) ;
if ( ! ShaderUtil ( ) - > OnSetPrimitiveType ( this , type ) )
{
return ;
}
LOCK_SHADERAPI ( ) ;
m_Type = type ;
m_Mode = ComputeMode ( type ) ;
}
MaterialPrimitiveType_t CMeshDX8 : : GetPrimitiveType ( ) const
{
return m_Type ;
}
//-----------------------------------------------------------------------------
// Computes the number of primitives we're gonna draw
//-----------------------------------------------------------------------------
int CMeshDX8 : : NumPrimitives ( int nVertexCount , int nIndexCount ) const
{
switch ( m_Mode )
{
case D3DPT_POINTLIST :
return nVertexCount ;
case D3DPT_LINELIST :
return nIndexCount / 2 ;
case D3DPT_TRIANGLELIST :
return nIndexCount / 3 ;
case D3DPT_TRIANGLESTRIP :
return nIndexCount - 2 ;
default :
// invalid, baby!
Assert ( 0 ) ;
}
return 0 ;
}
//-----------------------------------------------------------------------------
// Checks if it's a valid format
//-----------------------------------------------------------------------------
# ifdef _DEBUG
static void OutputVertexFormat ( VertexFormat_t format )
{
// FIXME: this is a duplicate of the function in meshdx8.cpp
VertexCompressionType_t compressionType = CompressionType ( format ) ;
if ( format & VERTEX_POSITION )
{
Warning ( " VERTEX_POSITION| " ) ;
}
if ( format & VERTEX_NORMAL )
{
if ( compressionType = = VERTEX_COMPRESSION_ON )
Warning ( " VERTEX_NORMAL[COMPRESSED]| " ) ;
else
Warning ( " VERTEX_NORMAL| " ) ;
}
if ( format & VERTEX_COLOR )
{
Warning ( " VERTEX_COLOR| " ) ;
}
if ( format & VERTEX_SPECULAR )
{
Warning ( " VERTEX_SPECULAR| " ) ;
}
if ( format & VERTEX_TANGENT_S )
{
Warning ( " VERTEX_TANGENT_S| " ) ;
}
if ( format & VERTEX_TANGENT_T )
{
Warning ( " VERTEX_TANGENT_T| " ) ;
}
if ( format & VERTEX_BONE_INDEX )
{
Warning ( " VERTEX_BONE_INDEX| " ) ;
}
if ( format & VERTEX_FORMAT_VERTEX_SHADER )
{
Warning ( " VERTEX_FORMAT_VERTEX_SHADER| " ) ;
}
Warning ( " \n Bone weights: %d (%s) \n " , NumBoneWeights ( format ) ,
( CompressionType ( format ) = = VERTEX_COMPRESSION_ON ? " compressed " : " uncompressed " ) ) ;
Warning ( " user data size: %d (%s) \n " , UserDataSize ( format ) ,
( CompressionType ( format ) = = VERTEX_COMPRESSION_ON ? " compressed " : " uncompressed " ) ) ;
Warning ( " num tex coords: %d \n " , NumTextureCoordinates ( format ) ) ;
// NOTE: This doesn't print texcoord sizes.
}
# endif
bool CMeshDX8 : : IsValidVertexFormat ( VertexFormat_t vertexFormat )
{
// FIXME: Make this a debug-only check on say 6th July 2007 (after a week or so's testing)
// (i.e. avoid the 360 release build perf. hit for when we ship)
bool bCheckCompression = ( m_VertexFormat & VERTEX_FORMAT_COMPRESSED ) & &
( ( vertexFormat = = VERTEX_FORMAT_INVALID ) | | ( ( vertexFormat & VERTEX_FORMAT_COMPRESSED ) = = 0 ) ) ;
if ( bCheckCompression | | IsPC ( ) | | IsDebug ( ) )
{
IMaterialInternal * pMaterial = ShaderAPI ( ) - > GetBoundMaterial ( ) ;
Assert ( pMaterial ) ;
// the material format should match the vertex usage, unless another format is passed in
if ( vertexFormat = = VERTEX_FORMAT_INVALID )
{
vertexFormat = pMaterial - > GetVertexUsage ( ) & ~ ( VERTEX_FORMAT_VERTEX_SHADER | VERTEX_FORMAT_USE_EXACT_FORMAT ) ;
// Blat out unused fields
vertexFormat & = ~ g_MeshMgr . UnusedVertexFields ( ) ;
int nUnusedTextureCoords = g_MeshMgr . UnusedTextureCoords ( ) ;
for ( int i = 0 ; i < VERTEX_MAX_TEXTURE_COORDINATES ; + + i )
{
if ( nUnusedTextureCoords & ( 1 < < i ) )
{
vertexFormat & = ~ VERTEX_TEXCOORD_MASK ( i ) ;
}
}
}
else
{
vertexFormat & = ~ ( VERTEX_FORMAT_VERTEX_SHADER | VERTEX_FORMAT_USE_EXACT_FORMAT ) ;
}
bool bIsValid = ( ( VERTEX_FORMAT_FIELD_MASK & vertexFormat ) & ( VERTEX_FORMAT_FIELD_MASK & ~ m_VertexFormat ) ) = = 0 ;
if ( m_VertexFormat & VERTEX_FORMAT_COMPRESSED )
{
// We shouldn't get compressed verts if this material doesn't support them!
if ( ( vertexFormat & VERTEX_FORMAT_COMPRESSED ) = = 0 )
{
static int numWarnings = 0 ;
if ( numWarnings + + = = 0 )
{
// NOTE: ComputeVertexFormat() will make sure no materials support VERTEX_FORMAT_COMPRESSED
// if vertex compression is disabled in the config
if ( g_pHardwareConfig - > SupportsCompressedVertices ( ) = = VERTEX_COMPRESSION_NONE )
Warning ( " ERROR: Compressed vertices in use but vertex compression is disabled (or not supported on this hardware)! \n " ) ;
else
Warning ( " ERROR: Compressed vertices in use but material does not support them! \n " ) ;
}
Assert ( 0 ) ;
bIsValid = false ;
}
}
bIsValid = bIsValid & & UserDataSize ( m_VertexFormat ) > = UserDataSize ( vertexFormat ) ;
for ( int i = 0 ; i < VERTEX_MAX_TEXTURE_COORDINATES ; i + + )
{
if ( TexCoordSize ( i , m_VertexFormat ) < TexCoordSize ( i , vertexFormat ) )
{
bIsValid = false ;
}
}
// NOTE: It can totally be valid to have more weights than the current number of bones.
// The -1 here is because if we have N bones, we can have only (N-1) weights,
// since the Nth is implied (the weights sum to 1).
int nWeightCount = NumBoneWeights ( m_VertexFormat ) ;
bIsValid = bIsValid & & ( nWeightCount > = ( g_pShaderAPI - > GetCurrentNumBones ( ) - 1 ) ) ;
# ifdef _DEBUG
if ( ! bIsValid )
{
Warning ( " Material Format: " ) ;
if ( g_pShaderAPI - > GetCurrentNumBones ( ) > 0 )
{
vertexFormat | = VERTEX_BONE_INDEX ;
vertexFormat & = ~ VERTEX_BONE_WEIGHT_MASK ;
vertexFormat | = VERTEX_BONEWEIGHT ( 2 ) ;
}
OutputVertexFormat ( vertexFormat ) ;
Warning ( " Mesh Format: " ) ;
OutputVertexFormat ( m_VertexFormat ) ;
}
# endif
return bIsValid ;
}
return true ;
}
//-----------------------------------------------------------------------------
// Stream source setting methods
//-----------------------------------------------------------------------------
void CMeshDX8 : : SetVertexIDStreamState ( )
{
// FIXME: this method duplicates the code in CMeshMgr::SetVertexIDStreamState
if ( IsX360 ( ) )
return ;
bool bUsingVertexID = IsUsingVertexID ( ) ;
if ( bUsingVertexID ! = g_bUsingVertexID )
{
if ( bUsingVertexID )
{
// NOTE: Morphing doesn't work with dynamic buffers!!! BLEAH
// It's because the indices (which are not 0 based for dynamic buffers)
// are accessing both the vertexID buffer + the regular vertex buffer.
// This *might* be fixable with baseVertexIndex?
// NOTE: At the moment, vertex id is only used for hw morphing. I've got it
// set up so that a shader that supports hw morphing always says it uses vertex id.
// If we ever use vertex id for something other than hw morphing, we're going
// to have to revisit how those shaders say they want to use vertex id
// or fix this some other way
Assert ( ! g_pShaderAPI - > IsHWMorphingEnabled ( ) | | ! m_pVertexBuffer - > IsDynamic ( ) ) ;
CVertexBuffer * pVertexIDBuffer = g_MeshMgr . GetVertexIDBuffer ( ) ;
RECORD_COMMAND ( DX8_SET_STREAM_SOURCE , 4 ) ;
RECORD_INT ( pVertexIDBuffer - > UID ( ) ) ;
RECORD_INT ( 3 ) ;
RECORD_INT ( 0 ) ;
RECORD_INT ( pVertexIDBuffer - > VertexSize ( ) ) ;
D3DSetStreamSource ( 3 , pVertexIDBuffer - > GetInterface ( ) , 0 , pVertexIDBuffer - > VertexSize ( ) ) ;
pVertexIDBuffer - > HandlePerFrameTextureStats ( ShaderAPI ( ) - > GetCurrentFrameCounter ( ) ) ;
}
else
{
RECORD_COMMAND ( DX8_SET_STREAM_SOURCE , 4 ) ;
RECORD_INT ( - 1 ) ; // vertex buffer id
RECORD_INT ( 3 ) ; // stream
RECORD_INT ( 0 ) ; // vertex offset
RECORD_INT ( 0 ) ; // vertex size
D3DSetStreamSource ( 3 , 0 , 0 , 0 ) ;
}
g_bUsingVertexID = bUsingVertexID ;
}
}
void CMeshDX8 : : SetColorStreamState ( )
{
if ( ( m_pColorMesh ! = g_pLastColorMesh ) | | ( m_nColorMeshVertOffsetInBytes ! = g_nLastColorMeshVertOffsetInBytes ) )
{
if ( m_pColorMesh )
{
RECORD_COMMAND ( DX8_SET_STREAM_SOURCE , 4 ) ;
RECORD_INT ( m_pColorMesh - > GetVertexBuffer ( ) - > UID ( ) ) ;
RECORD_INT ( 1 ) ;
RECORD_INT ( m_nColorMeshVertOffsetInBytes ) ;
RECORD_INT ( m_pColorMesh - > GetVertexBuffer ( ) - > VertexSize ( ) ) ;
D3DSetStreamSource ( 1 , m_pColorMesh - > GetVertexBuffer ( ) - > GetInterface ( ) ,
m_nColorMeshVertOffsetInBytes , m_pColorMesh - > GetVertexBuffer ( ) - > VertexSize ( ) ) ;
m_pColorMesh - > GetVertexBuffer ( ) - > HandlePerFrameTextureStats ( ShaderAPI ( ) - > GetCurrentFrameCounter ( ) ) ;
}
else
{
RECORD_COMMAND ( DX8_SET_STREAM_SOURCE , 4 ) ;
RECORD_INT ( - 1 ) ; // vertex buffer id
RECORD_INT ( 1 ) ; // stream
RECORD_INT ( 0 ) ; // vertex offset
RECORD_INT ( 0 ) ; // vertex size
D3DSetStreamSource ( 1 , 0 , 0 , 0 ) ;
}
g_pLastColorMesh = m_pColorMesh ;
g_nLastColorMeshVertOffsetInBytes = m_nColorMeshVertOffsetInBytes ;
}
}
void CMeshDX8 : : SetVertexStreamState ( int nVertOffsetInBytes )
{
// Calls in here assume shader support...
if ( HardwareConfig ( ) - > SupportsVertexAndPixelShaders ( ) )
{
if ( HasFlexMesh ( ) )
{
// m_pFlexVertexBuffer is the flex buffer down inside the CMeshMgr singleton
D3DSetStreamSource ( 2 , m_pFlexVertexBuffer - > GetInterface ( ) , m_nFlexVertOffsetInBytes , m_pFlexVertexBuffer - > VertexSize ( ) ) ;
if ( g_pHardwareConfig - > Caps ( ) . m_SupportsVertexShaders_2_0 )
{
float c [ 4 ] = { 1.0f , g_pMaterialSystemHardwareConfig - > SupportsPixelShaders_2_b ( ) ? 1.0f : 0.0f , 0.0f , 0.0f } ;
ShaderAPI ( ) - > SetVertexShaderConstant ( VERTEX_SHADER_FLEXSCALE , c , 1 ) ;
}
g_bFlexMeshStreamSet = true ;
}
else
{
Assert ( nVertOffsetInBytes = = 0 ) ;
Assert ( m_pVertexBuffer ) ;
// HACK...point stream 2 at the same VB which is bound to stream 0...
// NOTE: D3D debug DLLs will RIP if stream 0 has a smaller stride than the largest
// offset in the stream 2 vertex decl elements (which are position(12)+wrinkle(4)+normal(12))
// If this fires, go find the material/shader which is requesting a really 'thin'
// stream 0 vertex, and fatten it up slightly (e.g. add a D3DCOLOR element)
int minimumStreamZeroStride = 4 * sizeof ( float ) ;
Assert ( m_pVertexBuffer - > VertexSize ( ) > = minimumStreamZeroStride ) ;
if ( m_pVertexBuffer - > VertexSize ( ) < minimumStreamZeroStride )
{
static bool bWarned = false ;
if ( ! bWarned )
{
Warning ( " Shader specifying too-thin vertex format, should be at least %d bytes! (Suppressing furthur warnings) \n " , minimumStreamZeroStride ) ;
bWarned = true ;
}
}
// Set a 4kb all-zero static VB into the flex/wrinkle stream with a stride of 1 bytes, so the vertex shader always reads valid floating point values (otherwise it can get NaN's/Inf's, and under OpenGL this is bad on NVidia)
// togl requires non-zero strides, but on D3D9 we can set a stride of 0 for a little more efficiency.
D3DSetStreamSource ( 2 , g_MeshMgr . GetZeroVertexBuffer ( ) , 0 , IsOpenGL ( ) ? 4 : 0 ) ;
if ( g_pHardwareConfig - > Caps ( ) . m_SupportsVertexShaders_2_0 )
{
float c [ 4 ] = { 0.0f , 0.0f , 0.0f , 0.0f } ;
ShaderAPI ( ) - > SetVertexShaderConstant ( VERTEX_SHADER_FLEXSCALE , c , 1 ) ;
}
g_bFlexMeshStreamSet = false ;
}
}
// MESHFIXME: Make sure this jives between the mesh/ib/vb version.
# ifdef _X360
if ( ( g_pLastVertex ! = m_pVertexBuffer ) | | ( m_pVertexBuffer - > IsDynamic ( ) ) | | ( g_nLastVertOffsetInBytes ! = nVertOffsetInBytes ) )
# else
if ( ( g_pLastVertex ! = m_pVertexBuffer ) | | ( g_nLastVertOffsetInBytes ! = nVertOffsetInBytes ) )
# endif
{
Assert ( m_pVertexBuffer ) ;
RECORD_COMMAND ( DX8_SET_STREAM_SOURCE , 4 ) ;
RECORD_INT ( m_pVertexBuffer - > UID ( ) ) ;
RECORD_INT ( 0 ) ;
RECORD_INT ( nVertOffsetInBytes ) ;
RECORD_INT ( m_pVertexBuffer - > VertexSize ( ) ) ;
D3DSetStreamSource ( 0 , m_pVertexBuffer - > GetInterface ( ) , nVertOffsetInBytes , m_pVertexBuffer - > VertexSize ( ) ) ;
m_pVertexBuffer - > HandlePerFrameTextureStats ( ShaderAPI ( ) - > GetCurrentFrameCounter ( ) ) ;
g_pLastVertex = m_pVertexBuffer ;
g_nLastVertOffsetInBytes = nVertOffsetInBytes ;
}
}
void CMeshDX8 : : SetIndexStreamState ( int firstVertexIdx )
{
# ifdef _X360
if ( ( g_pLastIndexBuffer ! = NULL ) | | ( g_pLastIndex ! = m_pIndexBuffer ) | | ( m_pIndexBuffer - > IsDynamic ( ) ) | | ( firstVertexIdx ! = g_LastVertexIdx ) )
# else
if ( ( g_pLastIndexBuffer ! = NULL ) | | ( g_pLastIndex ! = m_pIndexBuffer ) | | ( firstVertexIdx ! = g_LastVertexIdx ) )
# endif
{
Assert ( m_pIndexBuffer ) ;
RECORD_COMMAND ( DX8_SET_INDICES , 2 ) ;
RECORD_INT ( m_pIndexBuffer - > UID ( ) ) ;
RECORD_INT ( firstVertexIdx ) ;
Dx9Device ( ) - > SetIndices ( m_pIndexBuffer - > GetInterface ( ) ) ;
m_pIndexBuffer - > HandlePerFrameTextureStats ( ShaderAPI ( ) - > GetCurrentFrameCounter ( ) ) ;
m_FirstIndex = firstVertexIdx ;
SafeAssign ( & g_pLastIndex , m_pIndexBuffer ) ;
g_pLastIndexBuffer = NULL ;
g_LastVertexIdx = firstVertexIdx ;
}
}
bool CMeshDX8 : : SetRenderState ( int nVertexOffsetInBytes , int nFirstVertexIdx , VertexFormat_t vertexFormat )
{
// Can't set the state if we're deactivated
if ( g_pShaderDeviceDx8 - > IsDeactivated ( ) )
{
ResetMeshRenderState ( ) ;
return false ;
}
g_LastVertexFormat = vertexFormat ;
SetVertexIDStreamState ( ) ;
SetColorStreamState ( ) ;
SetVertexStreamState ( nVertexOffsetInBytes ) ;
SetIndexStreamState ( nFirstVertexIdx ) ;
return true ;
}
//-----------------------------------------------------------------------------
// Draws the static mesh
//-----------------------------------------------------------------------------
void CMeshDX8 : : Draw ( int nFirstIndex , int nIndexCount )
{
Assert ( m_pVertexBuffer ) ;
if ( ! m_pVertexBuffer )
{
return ;
}
if ( ! ShaderUtil ( ) - > OnDrawMesh ( this , nFirstIndex , nIndexCount ) )
{
MarkAsDrawn ( ) ;
return ;
}
CPrimList primList ;
if ( nFirstIndex = = - 1 | | nIndexCount = = 0 )
{
primList . m_FirstIndex = 0 ;
primList . m_NumIndices = m_NumIndices ;
}
else
{
primList . m_FirstIndex = nFirstIndex ;
primList . m_NumIndices = nIndexCount ;
}
DrawInternal ( & primList , 1 ) ;
}
void CMeshDX8 : : Draw ( CPrimList * pLists , int nLists )
{
Assert ( m_pVertexBuffer ) ;
if ( ! m_pVertexBuffer )
{
return ;
}
if ( ! ShaderUtil ( ) - > OnDrawMesh ( this , pLists , nLists ) )
{
MarkAsDrawn ( ) ;
return ;
}
DrawInternal ( pLists , nLists ) ;
}
void CMeshDX8 : : DrawInternal ( CPrimList * pLists , int nLists )
{
HandleLateCreation ( ) ;
// Make sure there's something to draw..
int i ;
for ( i = 0 ; i < nLists ; i + + )
{
if ( pLists [ i ] . m_NumIndices > 0 )
break ;
}
if ( i = = nLists )
return ;
// can't do these in selection mode!
Assert ( ! ShaderAPI ( ) - > IsInSelectionMode ( ) ) ;
if ( ! SetRenderState ( 0 , 0 ) )
return ;
s_pPrims = pLists ;
s_nPrims = nLists ;
# ifdef _DEBUG
for ( i = 0 ; i < nLists ; + + i )
{
Assert ( pLists [ i ] . m_NumIndices > 0 ) ;
}
# endif
s_FirstVertex = 0 ;
s_NumVertices = m_pVertexBuffer - > VertexCount ( ) ;
DrawMesh ( ) ;
}
# ifdef CHECK_INDICES
void CMeshDX8 : : CheckIndices ( CPrimList * pPrim , int numPrimitives )
{
// g_pLastVertex - this is the current vertex buffer
// g_pLastColorMesh - this is the current color mesh, if there is one.
// g_pLastIndex - this is the current index buffer.
// vertoffset : m_FirstIndex
if ( m_Mode = = D3DPT_TRIANGLELIST | | m_Mode = = D3DPT_TRIANGLESTRIP )
{
Assert ( pPrim - > m_FirstIndex > = 0 & & pPrim - > m_FirstIndex < g_pLastIndex - > IndexCount ( ) ) ;
int i ;
for ( i = 0 ; i < 2 ; i + + )
{
CVertexBuffer * pMesh ;
if ( i = = 0 )
{
pMesh = g_pLastVertex ;
Assert ( pMesh ) ;
}
else
{
if ( ! g_pLastColorMesh )
{
continue ;
}
pMesh = g_pLastColorMesh - > m_pVertexBuffer ;
if ( ! pMesh )
{
continue ;
}
}
Assert ( s_FirstVertex > = 0 & &
( int ) ( s_FirstVertex + m_FirstIndex ) < pMesh - > VertexCount ( ) ) ;
int nIndexCount = 0 ;
if ( m_Mode = = D3DPT_TRIANGLELIST )
{
nIndexCount = numPrimitives * 3 ;
}
else if ( m_Mode = = D3DPT_TRIANGLESTRIP )
{
nIndexCount = numPrimitives + 2 ;
}
else
{
Assert ( 0 ) ;
}
int j ;
for ( j = 0 ; j < nIndexCount ; j + + )
{
int index = g_pLastIndex - > GetShadowIndex ( j + pPrim - > m_FirstIndex ) ;
if ( ( index < ( int ) s_FirstVertex ) | | ( index > = ( int ) ( s_FirstVertex + s_NumVertices ) ) )
Warning ( " %s invalid index: %d [%u..%u] \n " , __FUNCTION__ , index , s_FirstVertex , s_FirstVertex + s_NumVertices - 1 ) ;
Assert ( index > = ( int ) s_FirstVertex ) ;
Assert ( index < ( int ) ( s_FirstVertex + s_NumVertices ) ) ;
}
}
}
}
# endif // CHECK_INDICES
//-----------------------------------------------------------------------------
// Actually does the dirty deed of rendering
//-----------------------------------------------------------------------------
void CMeshDX8 : : RenderPass ( )
{
LOCK_SHADERAPI ( ) ;
VPROF ( " CMeshDX8::RenderPass " ) ;
HandleLateCreation ( ) ;
Assert ( m_Type ! = MATERIAL_HETEROGENOUS ) ;
// make sure the vertex format is a superset of the current material's
// vertex format...
if ( ! IsValidVertexFormat ( g_LastVertexFormat ) )
{
Warning ( " Material %s does not support vertex format used by the mesh (maybe missing fields or mismatched vertex compression?), mesh will not be rendered. Grab a programmer! \n " ,
ShaderAPI ( ) - > GetBoundMaterial ( ) - > GetName ( ) ) ;
return ;
}
for ( int iPrim = 0 ; iPrim < s_nPrims ; iPrim + + )
{
CPrimList * pPrim = & s_pPrims [ iPrim ] ;
if ( pPrim - > m_NumIndices = = 0 )
continue ;
if ( ( m_Type = = MATERIAL_POINTS ) | | ( m_Type = = MATERIAL_INSTANCED_QUADS ) )
{
tmZone ( TELEMETRY_LEVEL1 , TMZF_NONE , " Dx9Device_DrawPrimitive " ) ;
// (For point/instanced-quad lists, we don't actually fill in indices, but we treat it as
// though there are indices for the list up until here).
Dx9Device ( ) - > DrawPrimitive ( m_Mode , s_FirstVertex , pPrim - > m_NumIndices ) ;
}
else
{
int numPrimitives = NumPrimitives ( s_NumVertices , pPrim - > m_NumIndices ) ;
# ifdef CHECK_INDICES
CheckIndices ( pPrim , numPrimitives ) ;
# endif // CHECK_INDICES
{
VPROF ( " Dx9Device()->DrawIndexedPrimitive " ) ;
VPROF_INCREMENT_COUNTER ( " DrawIndexedPrimitive " , 1 ) ;
VPROF_INCREMENT_COUNTER ( " numPrimitives " , numPrimitives ) ;
VPROF_INCREMENT_GROUP_COUNTER ( " render/DrawIndexedPrimitive " , COUNTER_GROUP_TELEMETRY , 1 ) ;
VPROF_INCREMENT_GROUP_COUNTER ( " render/numPrimitives " , COUNTER_GROUP_TELEMETRY , 1 ) ;
Dx9Device ( ) - > DrawIndexedPrimitive (
m_Mode , // Member of the D3DPRIMITIVETYPE enumerated type, describing the type of primitive to render. D3DPT_POINTLIST is not supported with this method.
m_FirstIndex , // Offset from the start of the vertex buffer to the first vertex index. An index of 0 in the index buffer refers to this location in the vertex buffer.
s_FirstVertex , // Minimum vertex index for vertices used during this call. This is a zero based index relative to BaseVertexIndex.
// The first Vertex in the vertexbuffer that we are currently using for the current batch.
s_NumVertices , // Number of vertices used during this call. The first vertex is located at index: BaseVertexIndex + MinIndex.
pPrim - > m_FirstIndex , // Index of the first index to use when accesssing the vertex buffer. Beginning at StartIndex to index vertices from the vertex buffer.
numPrimitives ) ; // Number of primitives to render. The number of vertices used is a function of the primitive count and the primitive type.
}
}
}
if ( g_pLastVertex )
{
g_pLastVertex - > MarkUsedInRendering ( ) ;
}
if ( g_pLastIndex )
{
g_pLastIndex - > MarkUsedInRendering ( ) ;
}
}
//-----------------------------------------------------------------------------
//
// Dynamic mesh implementation
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
CDynamicMeshDX8 : : CDynamicMeshDX8 ( ) : CMeshDX8 ( " CDynamicMeshDX8 " )
{
m_nBufferId = 0 ;
ResetVertexAndIndexCounts ( ) ;
}
CDynamicMeshDX8 : : ~ CDynamicMeshDX8 ( )
{
}
//-----------------------------------------------------------------------------
// Initializes the dynamic mesh
//-----------------------------------------------------------------------------
void CDynamicMeshDX8 : : Init ( int nBufferId )
{
m_nBufferId = nBufferId ;
}
//-----------------------------------------------------------------------------
// Resets buffering state
//-----------------------------------------------------------------------------
void CDynamicMeshDX8 : : ResetVertexAndIndexCounts ( )
{
m_TotalVertices = m_TotalIndices = 0 ;
m_FirstIndex = m_nFirstVertex = - 1 ;
m_HasDrawn = false ;
}
//-----------------------------------------------------------------------------
// Resets the state in case of a task switch
//-----------------------------------------------------------------------------
void CDynamicMeshDX8 : : Reset ( )
{
m_VertexFormat = 0 ;
m_pVertexBuffer = 0 ;
SafeRelease ( & m_pIndexBuffer ) ;
ResetVertexAndIndexCounts ( ) ;
// Force the render state to be updated next time
ResetMeshRenderState ( ) ;
}
//-----------------------------------------------------------------------------
// Sets the vertex format associated with the dynamic mesh
//-----------------------------------------------------------------------------
void CDynamicMeshDX8 : : SetVertexFormat ( VertexFormat_t format )
{
if ( g_pShaderDeviceDx8 - > IsDeactivated ( ) )
return ;
if ( CompressionType ( format ) ! = VERTEX_COMPRESSION_NONE )
{
// UNDONE: support compressed dynamic meshes if needed (pro: less VB memory, con: CMeshBuilder gets slower)
Warning ( " ERROR: dynamic meshes cannot use compressed vertices! \n " ) ;
Assert ( 0 ) ;
format & = ~ VERTEX_FORMAT_COMPRESSED ;
}
if ( ( format ! = m_VertexFormat ) | | m_VertexOverride | | m_IndexOverride )
{
m_VertexFormat = format ;
UseVertexBuffer ( g_MeshMgr . FindOrCreateVertexBuffer ( m_nBufferId , format ) ) ;
if ( m_nBufferId = = 0 )
{
UseIndexBuffer ( g_MeshMgr . GetDynamicIndexBuffer ( ) ) ;
}
m_VertexOverride = m_IndexOverride = false ;
}
}
void CDynamicMeshDX8 : : OverrideVertexBuffer ( CVertexBuffer * pVertexBuffer )
{
UseVertexBuffer ( pVertexBuffer ) ;
m_VertexOverride = true ;
}
void CDynamicMeshDX8 : : OverrideIndexBuffer ( CIndexBuffer * pIndexBuffer )
{
UseIndexBuffer ( pIndexBuffer ) ;
m_IndexOverride = true ;
}
//-----------------------------------------------------------------------------
// Do I need to reset the vertex format?
//-----------------------------------------------------------------------------
bool CDynamicMeshDX8 : : NeedsVertexFormatReset ( VertexFormat_t fmt ) const
{
return m_VertexOverride | | m_IndexOverride | | ( m_VertexFormat ! = fmt ) ;
}
//-----------------------------------------------------------------------------
// Locks/unlocks the entire mesh
//-----------------------------------------------------------------------------
bool CDynamicMeshDX8 : : HasEnoughRoom ( int nVertexCount , int nIndexCount ) const
{
if ( g_pShaderDeviceDx8 - > IsDeactivated ( ) )
return false ;
Assert ( m_pVertexBuffer ! = NULL ) ;
// We need space in both the vertex and index buffer
return m_pVertexBuffer - > HasEnoughRoom ( nVertexCount ) & &
m_pIndexBuffer - > HasEnoughRoom ( nIndexCount ) ;
}
//-----------------------------------------------------------------------------
// returns the number of indices in the mesh
//-----------------------------------------------------------------------------
int CDynamicMeshDX8 : : IndexCount ( ) const
{
return m_TotalIndices ;
}
//-----------------------------------------------------------------------------
// Operation to do pre-lock (only called for buffered meshes)
//-----------------------------------------------------------------------------
void CDynamicMeshDX8 : : PreLock ( )
{
if ( m_HasDrawn )
{
// Start again then
ResetVertexAndIndexCounts ( ) ;
}
}
//-----------------------------------------------------------------------------
// Locks/unlocks the entire mesh
//-----------------------------------------------------------------------------
void CDynamicMeshDX8 : : LockMesh ( int nVertexCount , int nIndexCount , MeshDesc_t & desc )
{
tmZoneFiltered ( TELEMETRY_LEVEL0 , 50 , TMZF_NONE , " %s %d %d " , __FUNCTION__ , nVertexCount , nIndexCount ) ;
ShaderUtil ( ) - > SyncMatrices ( ) ;
{
tmZoneFiltered ( TELEMETRY_LEVEL0 , 50 , TMZF_NONE , " g_ShaderMutex.Lock " ) ;
g_ShaderMutex . Lock ( ) ;
}
// Yes, this may well also be called from BufferedMesh but that's ok
{
tmZoneFiltered ( TELEMETRY_LEVEL0 , 50 , TMZF_NONE , " PreLock " ) ;
PreLock ( ) ;
}
if ( m_VertexOverride )
{
nVertexCount = 0 ;
}
if ( m_IndexOverride )
{
nIndexCount = 0 ;
}
{
tmZoneFiltered ( TELEMETRY_LEVEL0 , 50 , TMZF_NONE , " Lock " ) ;
Lock ( nVertexCount , false , * static_cast < VertexDesc_t * > ( & desc ) ) ;
}
if ( m_nFirstVertex < 0 )
{
m_nFirstVertex = desc . m_nFirstVertex ;
}
// When we're using a static index buffer or a flex mesh, the indices assume vertices start at 0
if ( m_IndexOverride | | HasFlexMesh ( ) )
{
desc . m_nFirstVertex - = m_nFirstVertex ;
}
// Don't add indices for points; DrawIndexedPrimitive not supported for them.
if ( m_Type ! = MATERIAL_POINTS )
{
int nFirstIndex ;
{
tmZoneFiltered ( TELEMETRY_LEVEL0 , 50 , TMZF_NONE , " Lock nFirstIndex " ) ;
nFirstIndex = Lock ( false , - 1 , nIndexCount , * static_cast < IndexDesc_t * > ( & desc ) ) ;
}
if ( m_FirstIndex < 0 )
{
m_FirstIndex = nFirstIndex ;
}
}
else
{
desc . m_pIndices = g_nScratchIndexBuffer ;
desc . m_nIndexSize = 0 ;
}
CBaseMeshDX8 : : m_bMeshLocked = true ;
}
//-----------------------------------------------------------------------------
// Unlocks the mesh
//-----------------------------------------------------------------------------
void CDynamicMeshDX8 : : UnlockMesh ( int nVertexCount , int nIndexCount , MeshDesc_t & desc )
{
m_TotalVertices + = nVertexCount ;
m_TotalIndices + = nIndexCount ;
if ( DebugTrace ( ) )
{
Spew ( nVertexCount , nIndexCount , desc ) ;
}
CMeshDX8 : : UnlockMesh ( nVertexCount , nIndexCount , desc ) ;
// This is handled in the CMeshDX8::UnlockMesh above.
//CBaseMeshDX8::m_bMeshLocked = false;
}
//-----------------------------------------------------------------------------
// Draws it
//-----------------------------------------------------------------------------
void CDynamicMeshDX8 : : Draw ( int nFirstIndex , int nIndexCount )
{
if ( ! ShaderUtil ( ) - > OnDrawMesh ( this , nFirstIndex , nIndexCount ) )
{
MarkAsDrawn ( ) ;
return ;
}
VPROF ( " CDynamicMeshDX8::Draw " ) ;
m_HasDrawn = true ;
if ( m_IndexOverride | | m_VertexOverride | |
( ( m_TotalVertices > 0 ) & & ( m_TotalIndices > 0 | | m_Type = = MATERIAL_POINTS | | m_Type = = MATERIAL_INSTANCED_QUADS ) ) )
{
Assert ( ! m_IsDrawing ) ;
HandleLateCreation ( ) ;
// only have a non-zero first vertex when we are using static indices
int nFirstVertex = m_VertexOverride ? 0 : m_nFirstVertex ;
int actualFirstVertex = m_IndexOverride ? nFirstVertex : 0 ;
int nVertexOffsetInBytes = HasFlexMesh ( ) ? nFirstVertex * g_MeshMgr . VertexFormatSize ( GetVertexFormat ( ) ) : 0 ;
int baseIndex = m_IndexOverride ? 0 : m_FirstIndex ;
// Overriding with the dynamic index buffer, preserve state!
if ( m_IndexOverride & & m_pIndexBuffer = = g_MeshMgr . GetDynamicIndexBuffer ( ) )
{
baseIndex = m_FirstIndex ;
}
VertexFormat_t fmt = m_VertexOverride ? GetVertexFormat ( ) : VERTEX_FORMAT_INVALID ;
if ( ! SetRenderState ( nVertexOffsetInBytes , actualFirstVertex , fmt ) )
return ;
// Draws a portion of the mesh
int numVertices = m_VertexOverride ? m_pVertexBuffer - > VertexCount ( ) : m_TotalVertices ;
if ( ( nFirstIndex ! = - 1 ) & & ( nIndexCount ! = 0 ) )
{
nFirstIndex + = baseIndex ;
}
else
{
// by default we draw the whole thing
nFirstIndex = baseIndex ;
if ( m_IndexOverride )
{
nIndexCount = m_pIndexBuffer - > IndexCount ( ) ;
Assert ( nIndexCount ! = 0 ) ;
}
else
{
nIndexCount = m_TotalIndices ;
// Fake out the index count if we're drawing points/instanced-quads
if ( ( m_Type = = MATERIAL_POINTS ) | | ( m_Type = = MATERIAL_INSTANCED_QUADS ) )
{
nIndexCount = m_TotalVertices ;
}
Assert ( nIndexCount ! = 0 ) ;
}
}
// Fix up nFirstVertex to indicate the first vertex used in the data
if ( ! HasFlexMesh ( ) )
{
actualFirstVertex = nFirstVertex - actualFirstVertex ;
}
s_FirstVertex = actualFirstVertex ;
s_NumVertices = numVertices ;
// Build a primlist with 1 element..
CPrimList prim ;
prim . m_FirstIndex = nFirstIndex ;
prim . m_NumIndices = nIndexCount ;
Assert ( nIndexCount ! = 0 ) ;
s_pPrims = & prim ;
s_nPrims = 1 ;
DrawMesh ( ) ;
s_pPrims = NULL ;
}
}
//-----------------------------------------------------------------------------
// This is useful when we need to dynamically modify data; just set the
// render state and draw the pass immediately
//-----------------------------------------------------------------------------
void CDynamicMeshDX8 : : DrawSinglePassImmediately ( )
{
if ( ( m_TotalVertices > 0 ) | | ( m_TotalIndices > 0 ) )
{
Assert ( ! m_IsDrawing ) ;
// Set the render state
if ( SetRenderState ( 0 , 0 ) )
{
s_FirstVertex = m_nFirstVertex ;
s_NumVertices = m_TotalVertices ;
// Make a temporary PrimList to hold the indices.
CPrimList prim ( m_FirstIndex , m_TotalIndices ) ;
Assert ( m_TotalIndices ! = 0 ) ;
s_pPrims = & prim ;
s_nPrims = 1 ;
// Render it
RenderPass ( ) ;
}
// We're done with our data
ResetVertexAndIndexCounts ( ) ;
}
}
//-----------------------------------------------------------------------------
//
// A mesh that stores temporary vertex data in the correct format (for modification)
//
//-----------------------------------------------------------------------------
// Used in rendering sub-parts of the mesh
unsigned int CTempMeshDX8 : : s_NumIndices ;
unsigned int CTempMeshDX8 : : s_FirstIndex ;
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
CTempMeshDX8 : : CTempMeshDX8 ( bool isDynamic ) : m_VertexSize ( 0xFFFF ) , m_IsDynamic ( isDynamic )
{
# ifdef DBGFLAG_ASSERT
m_Locked = false ;
m_InPass = false ;
# endif
}
CTempMeshDX8 : : ~ CTempMeshDX8 ( )
{
}
//-----------------------------------------------------------------------------
// Is the temp mesh dynamic?
//-----------------------------------------------------------------------------
bool CTempMeshDX8 : : IsDynamic ( ) const
{
return m_IsDynamic ;
}
//-----------------------------------------------------------------------------
// Sets the vertex format
//-----------------------------------------------------------------------------
void CTempMeshDX8 : : SetVertexFormat ( VertexFormat_t format )
{
CBaseMeshDX8 : : SetVertexFormat ( format ) ;
m_VertexSize = g_MeshMgr . VertexFormatSize ( format ) ;
}
//-----------------------------------------------------------------------------
// returns the # of vertices (static meshes only)
//-----------------------------------------------------------------------------
int CTempMeshDX8 : : VertexCount ( ) const
{
return m_VertexSize ? m_VertexData . Count ( ) / m_VertexSize : 0 ;
}
//-----------------------------------------------------------------------------
// returns the # of indices
//-----------------------------------------------------------------------------
int CTempMeshDX8 : : IndexCount ( ) const
{
return m_IndexData . Count ( ) ;
}
void CTempMeshDX8 : : ModifyBeginEx ( bool bReadOnly , int nFirstVertex , int nVertexCount , int nFirstIndex , int nIndexCount , MeshDesc_t & desc )
{
Assert ( ! m_Locked ) ;
m_LockedVerts = nVertexCount ;
m_LockedIndices = nIndexCount ;
if ( nVertexCount > 0 )
{
int vertexByteOffset = m_VertexSize * nFirstVertex ;
// Lock it baby
unsigned char * pVertexMemory = & m_VertexData [ vertexByteOffset ] ;
// Compute the vertex index..
desc . m_nFirstVertex = vertexByteOffset / m_VertexSize ;
// Set up the mesh descriptor
g_MeshMgr . ComputeVertexDescription ( pVertexMemory , m_VertexFormat , desc ) ;
}
else
{
desc . m_nFirstVertex = 0 ;
// Set up the mesh descriptor
g_MeshMgr . ComputeVertexDescription ( 0 , 0 , desc ) ;
}
if ( m_Type ! = MATERIAL_POINTS & & nIndexCount > 0 )
{
desc . m_pIndices = & m_IndexData [ nFirstIndex ] ;
desc . m_nIndexSize = 1 ;
}
else
{
desc . m_pIndices = g_nScratchIndexBuffer ;
desc . m_nIndexSize = 0 ;
}
# ifdef DBGFLAG_ASSERT
m_Locked = true ;
# endif
}
void CTempMeshDX8 : : ModifyBegin ( int nFirstVertex , int nVertexCount , int nFirstIndex , int nIndexCount , MeshDesc_t & desc )
{
ModifyBeginEx ( false , nFirstVertex , nVertexCount , nFirstIndex , nIndexCount , desc ) ;
}
void CTempMeshDX8 : : ModifyEnd ( MeshDesc_t & desc )
{
# ifdef DBGFLAG_ASSERT
Assert ( m_Locked ) ;
m_Locked = false ;
# endif
}
//-----------------------------------------------------------------------------
// Locks/unlocks the mesh
//-----------------------------------------------------------------------------
void CTempMeshDX8 : : LockMesh ( int nVertexCount , int nIndexCount , MeshDesc_t & desc )
{
ShaderUtil ( ) - > SyncMatrices ( ) ;
g_ShaderMutex . Lock ( ) ;
Assert ( ! m_Locked ) ;
m_LockedVerts = nVertexCount ;
m_LockedIndices = nIndexCount ;
if ( nVertexCount > 0 )
{
int vertexByteOffset = m_VertexData . AddMultipleToTail ( m_VertexSize * nVertexCount ) ;
// Lock it baby
unsigned char * pVertexMemory = & m_VertexData [ vertexByteOffset ] ;
// Compute the vertex index..
desc . m_nFirstVertex = vertexByteOffset / m_VertexSize ;
// Set up the mesh descriptor
g_MeshMgr . ComputeVertexDescription ( pVertexMemory , m_VertexFormat , desc ) ;
}
else
{
desc . m_nFirstVertex = 0 ;
// Set up the mesh descriptor
g_MeshMgr . ComputeVertexDescription ( 0 , 0 , desc ) ;
}
if ( m_Type ! = MATERIAL_POINTS & & nIndexCount > 0 )
{
int nFirstIndex = m_IndexData . AddMultipleToTail ( nIndexCount ) ;
desc . m_pIndices = & m_IndexData [ nFirstIndex ] ;
desc . m_nIndexSize = 1 ;
}
else
{
desc . m_pIndices = g_nScratchIndexBuffer ;
desc . m_nIndexSize = 0 ;
}
# ifdef DBGFLAG_ASSERT
m_Locked = true ;
# endif
CBaseMeshDX8 : : m_bMeshLocked = true ;
}
void CTempMeshDX8 : : UnlockMesh ( int nVertexCount , int nIndexCount , MeshDesc_t & desc )
{
Assert ( m_Locked ) ;
// Remove unused vertices and indices
int verticesToRemove = m_LockedVerts - nVertexCount ;
if ( verticesToRemove ! = 0 )
{
m_VertexData . RemoveMultiple ( m_VertexData . Count ( ) - verticesToRemove , verticesToRemove ) ;
}
int indicesToRemove = m_LockedIndices - nIndexCount ;
if ( indicesToRemove ! = 0 )
{
m_IndexData . RemoveMultiple ( m_IndexData . Count ( ) - indicesToRemove , indicesToRemove ) ;
}
# ifdef DBGFLAG_ASSERT
m_Locked = false ;
# endif
CBaseMeshDX8 : : m_bMeshLocked = false ;
g_ShaderMutex . Unlock ( ) ;
}
//-----------------------------------------------------------------------------
// Sets the primitive type
//-----------------------------------------------------------------------------
void CTempMeshDX8 : : SetPrimitiveType ( MaterialPrimitiveType_t type )
{
// FIXME: Support MATERIAL_INSTANCED_QUADS for CTempMeshDX8 (X360 only)
Assert ( ( type ! = MATERIAL_INSTANCED_QUADS ) /* || IsX360() */ ) ;
m_Type = type ;
}
MaterialPrimitiveType_t CTempMeshDX8 : : GetPrimitiveType ( ) const
{
return m_Type ;
}
//-----------------------------------------------------------------------------
// Gets the dynamic mesh
//-----------------------------------------------------------------------------
CDynamicMeshDX8 * CTempMeshDX8 : : GetDynamicMesh ( )
{
return static_cast < CDynamicMeshDX8 * > ( g_MeshMgr . GetActualDynamicMesh ( m_VertexFormat ) ) ;
}
//-----------------------------------------------------------------------------
// Draws the entire mesh
//-----------------------------------------------------------------------------
void CTempMeshDX8 : : Draw ( int nFirstIndex , int nIndexCount )
{
if ( ! ShaderUtil ( ) - > OnDrawMesh ( this , nFirstIndex , nIndexCount ) )
{
MarkAsDrawn ( ) ;
return ;
}
if ( m_VertexData . Count ( ) > 0 )
{
if ( ! g_pShaderDeviceDx8 - > IsDeactivated ( ) )
{
# ifdef DRAW_SELECTION
if ( ! g_bDrawSelection & & ! ShaderAPI ( ) - > IsInSelectionMode ( ) )
# else
if ( ! ShaderAPI ( ) - > IsInSelectionMode ( ) )
# endif
{
s_FirstIndex = nFirstIndex ;
s_NumIndices = nIndexCount ;
DrawMesh ( ) ;
// This assertion fails if a BeginPass() call was not matched by
// a RenderPass() call
Assert ( ! m_InPass ) ;
}
else
{
TestSelection ( ) ;
}
}
// Clear out the data if this temp mesh is a dynamic one...
if ( m_IsDynamic )
{
m_VertexData . RemoveAll ( ) ;
m_IndexData . RemoveAll ( ) ;
}
}
}
void CTempMeshDX8 : : 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 )
{
int startOffset = iStartVert * m_VertexSize ;
int endOffset = ( iStartVert + nVerts ) * m_VertexSize ;
Assert ( startOffset > = 0 & & startOffset < = m_VertexData . Count ( ) ) ;
Assert ( endOffset > = 0 & & endOffset < = m_VertexData . Count ( ) & & endOffset > = startOffset ) ;
if ( endOffset > startOffset )
{
// FIXME: make this a method of CMeshBuilder (so the 'Position' pointer accessor can be removed)
// make sure it takes a VertexFormat_t parameter for src/dest match validation
memcpy ( ( void * ) builder . Position ( ) , & m_VertexData [ startOffset ] , endOffset - startOffset ) ;
builder . AdvanceVertices ( nVerts ) ;
}
for ( int i = 0 ; i < nIndices ; + + i )
{
builder . Index ( m_IndexData [ iStartIndex + i ] + indexOffset ) ;
builder . AdvanceIndex ( ) ;
}
}
//-----------------------------------------------------------------------------
// Selection mode helper functions
//-----------------------------------------------------------------------------
static void ComputeModelToView ( D3DXMATRIX & modelToView )
{
// Get the modelview matrix...
D3DXMATRIX world , view ;
ShaderAPI ( ) - > GetMatrix ( MATERIAL_MODEL , ( float * ) & world ) ;
ShaderAPI ( ) - > GetMatrix ( MATERIAL_VIEW , ( float * ) & view ) ;
D3DXMatrixMultiply ( & modelToView , & world , & view ) ;
}
static float ComputeCullFactor ( )
{
D3DCULL cullMode = ShaderAPI ( ) - > GetCullMode ( ) ;
float cullFactor ;
switch ( cullMode )
{
case D3DCULL_CCW :
cullFactor = - 1.0f ;
break ;
case D3DCULL_CW :
cullFactor = 1.0f ;
break ;
default :
cullFactor = 0.0f ;
break ;
} ;
return cullFactor ;
}
//-----------------------------------------------------------------------------
// Clip to viewport
//-----------------------------------------------------------------------------
static int g_NumClipVerts ;
static D3DXVECTOR3 g_ClipVerts [ 16 ] ;
static bool PointInsidePlane ( D3DXVECTOR3 * pVert , int normalInd , float val , bool nearClip )
{
if ( ( val > 0 ) | | nearClip )
return ( val - ( * pVert ) [ normalInd ] > = 0 ) ;
else
return ( ( * pVert ) [ normalInd ] - val > = 0 ) ;
}
static void IntersectPlane ( D3DXVECTOR3 * pStart , D3DXVECTOR3 * pEnd ,
int normalInd , float val , D3DXVECTOR3 * pOutVert )
{
D3DXVECTOR3 dir ;
D3DXVec3Subtract ( & dir , pEnd , pStart ) ;
Assert ( dir [ normalInd ] ! = 0.0f ) ;
float t = ( val - ( * pStart ) [ normalInd ] ) / dir [ normalInd ] ;
pOutVert - > x = pStart - > x + dir . x * t ;
pOutVert - > y = pStart - > y + dir . y * t ;
pOutVert - > z = pStart - > z + dir . z * t ;
// Avoid any precision problems.
( * pOutVert ) [ normalInd ] = val ;
}
static int ClipTriangleAgainstPlane ( D3DXVECTOR3 * * ppVert , int nVertexCount ,
D3DXVECTOR3 * * ppOutVert , int normalInd , float val , bool nearClip = false )
{
// Ye Olde Sutherland-Hodgman clipping algorithm
int numOutVerts = 0 ;
D3DXVECTOR3 * pStart = ppVert [ nVertexCount - 1 ] ;
bool startInside = PointInsidePlane ( pStart , normalInd , val , nearClip ) ;
for ( int i = 0 ; i < nVertexCount ; + + i )
{
D3DXVECTOR3 * pEnd = ppVert [ i ] ;
bool endInside = PointInsidePlane ( pEnd , normalInd , val , nearClip ) ;
if ( endInside )
{
if ( ! startInside )
{
IntersectPlane ( pStart , pEnd , normalInd , val , & g_ClipVerts [ g_NumClipVerts ] ) ;
ppOutVert [ numOutVerts + + ] = & g_ClipVerts [ g_NumClipVerts + + ] ;
}
ppOutVert [ numOutVerts + + ] = pEnd ;
}
else
{
if ( startInside )
{
IntersectPlane ( pStart , pEnd , normalInd , val , & g_ClipVerts [ g_NumClipVerts ] ) ;
ppOutVert [ numOutVerts + + ] = & g_ClipVerts [ g_NumClipVerts + + ] ;
}
}
pStart = pEnd ;
startInside = endInside ;
}
return numOutVerts ;
}
void CTempMeshDX8 : : ClipTriangle ( D3DXVECTOR3 * * ppVert , float zNear , D3DXMATRIX & projection )
{
int i ;
int nVertexCount = 3 ;
D3DXVECTOR3 * ppClipVert1 [ 10 ] ;
D3DXVECTOR3 * ppClipVert2 [ 10 ] ;
g_NumClipVerts = 0 ;
// Clip against the near plane in view space to prevent negative w.
// Clip against each plane
nVertexCount = ClipTriangleAgainstPlane ( ppVert , nVertexCount , ppClipVert1 , 2 , zNear , true ) ;
if ( nVertexCount < 3 )
return ;
// Sucks that I have to do this, but I have to clip near plane in view space
// Clipping in projection space is screwy when w < 0
// Transform the clipped points into projection space
Assert ( g_NumClipVerts < = 2 ) ;
for ( i = 0 ; i < nVertexCount ; + + i )
{
if ( ppClipVert1 [ i ] = = & g_ClipVerts [ 0 ] )
{
D3DXVec3TransformCoord ( & g_ClipVerts [ 0 ] , ppClipVert1 [ i ] , & projection ) ;
}
else if ( ppClipVert1 [ i ] = = & g_ClipVerts [ 1 ] )
{
D3DXVec3TransformCoord ( & g_ClipVerts [ 1 ] , ppClipVert1 [ i ] , & projection ) ;
}
else
{
D3DXVec3TransformCoord ( & g_ClipVerts [ g_NumClipVerts ] , ppClipVert1 [ i ] , & projection ) ;
ppClipVert1 [ i ] = & g_ClipVerts [ g_NumClipVerts ] ;
+ + g_NumClipVerts ;
}
}
nVertexCount = ClipTriangleAgainstPlane ( ppClipVert1 , nVertexCount , ppClipVert2 , 2 , 1.0f ) ;
if ( nVertexCount < 3 )
return ;
nVertexCount = ClipTriangleAgainstPlane ( ppClipVert2 , nVertexCount , ppClipVert1 , 0 , 1.0f ) ;
if ( nVertexCount < 3 )
return ;
nVertexCount = ClipTriangleAgainstPlane ( ppClipVert1 , nVertexCount , ppClipVert2 , 0 , - 1.0f ) ;
if ( nVertexCount < 3 )
return ;
nVertexCount = ClipTriangleAgainstPlane ( ppClipVert2 , nVertexCount , ppClipVert1 , 1 , 1.0f ) ;
if ( nVertexCount < 3 )
return ;
nVertexCount = ClipTriangleAgainstPlane ( ppClipVert1 , nVertexCount , ppClipVert2 , 1 , - 1.0f ) ;
if ( nVertexCount < 3 )
return ;
# ifdef DRAW_SELECTION
if ( 1 | | g_bDrawSelection )
{
srand ( * ( int * ) ( & ppClipVert2 [ 0 ] - > x ) ) ;
unsigned char r = ( unsigned char ) ( rand ( ) * 191.0f / VALVE_RAND_MAX ) + 64 ;
unsigned char g = ( unsigned char ) ( rand ( ) * 191.0f / VALVE_RAND_MAX ) + 64 ;
unsigned char b = ( unsigned char ) ( rand ( ) * 191.0f / VALVE_RAND_MAX ) + 64 ;
ShaderAPI ( ) - > SetupSelectionModeVisualizationState ( ) ;
CMeshBuilder * pMeshBuilder = ShaderAPI ( ) - > GetVertexModifyBuilder ( ) ;
IMesh * pMesh = GetDynamicMesh ( ) ;
pMeshBuilder - > Begin ( pMesh , MATERIAL_POLYGON , nVertexCount ) ;
for ( i = 0 ; i < nVertexCount ; + + i )
{
pMeshBuilder - > Position3fv ( * ppClipVert2 [ i ] ) ;
pMeshBuilder - > Color3ub ( r , g , b ) ;
pMeshBuilder - > AdvanceVertex ( ) ;
}
pMeshBuilder - > End ( ) ;
pMesh - > Draw ( ) ;
pMeshBuilder - > Begin ( pMesh , MATERIAL_LINE_LOOP , nVertexCount ) ;
for ( i = 0 ; i < nVertexCount ; + + i )
{
pMeshBuilder - > Position3fv ( * ppClipVert2 [ i ] ) ;
pMeshBuilder - > Color3ub ( 255 , 255 , 255 ) ;
pMeshBuilder - > AdvanceVertex ( ) ;
}
pMeshBuilder - > End ( ) ;
pMesh - > Draw ( ) ;
}
# endif
// Compute closest and furthest verts
float minz = ppClipVert2 [ 0 ] - > z ;
float maxz = ppClipVert2 [ 0 ] - > z ;
for ( i = 1 ; i < nVertexCount ; + + i )
{
if ( ppClipVert2 [ i ] - > z < minz )
minz = ppClipVert2 [ i ] - > z ;
else if ( ppClipVert2 [ i ] - > z > maxz )
maxz = ppClipVert2 [ i ] - > z ;
}
ShaderAPI ( ) - > RegisterSelectionHit ( minz , maxz ) ;
}
//-----------------------------------------------------------------------------
// Selection mode
//-----------------------------------------------------------------------------
void CTempMeshDX8 : : TestSelection ( )
{
// Note that this doesn't take into account any vertex modification
// done in a vertex shader. Also it doesn't take into account any clipping
// done in hardware
// Blow off points and lines; they don't matter
if ( ( m_Type ! = MATERIAL_TRIANGLES ) & & ( m_Type ! = MATERIAL_TRIANGLE_STRIP ) )
return ;
D3DXMATRIX modelToView , projection ;
ComputeModelToView ( modelToView ) ;
ShaderAPI ( ) - > GetMatrix ( MATERIAL_PROJECTION , ( float * ) & projection ) ;
float zNear = - projection . m [ 3 ] [ 2 ] / projection . m [ 2 ] [ 2 ] ;
D3DXVECTOR3 * pPos [ 3 ] ;
D3DXVECTOR3 edge [ 2 ] ;
D3DXVECTOR3 normal ;
int numTriangles ;
if ( m_Type = = MATERIAL_TRIANGLES )
numTriangles = m_IndexData . Count ( ) / 3 ;
else
numTriangles = m_IndexData . Count ( ) - 2 ;
float cullFactor = ComputeCullFactor ( ) ;
// Makes the lovely loop simpler
if ( m_Type = = MATERIAL_TRIANGLE_STRIP )
cullFactor * = - 1.0f ;
// We'll need some temporary memory to tell us if we're transformed the vert
int nVertexCount = m_VertexData . Count ( ) / m_VertexSize ;
static CUtlVector < unsigned char > transformedVert ;
int transformedVertSize = ( nVertexCount + 7 ) > > 3 ;
transformedVert . RemoveAll ( ) ;
transformedVert . EnsureCapacity ( transformedVertSize ) ;
transformedVert . AddMultipleToTail ( transformedVertSize ) ;
memset ( transformedVert . Base ( ) , 0 , transformedVertSize ) ;
int indexPos ;
for ( int i = 0 ; i < numTriangles ; + + i )
{
// Get the three indices
if ( m_Type = = MATERIAL_TRIANGLES )
{
indexPos = i * 3 ;
}
else
{
Assert ( m_Type = = MATERIAL_TRIANGLE_STRIP ) ;
cullFactor * = - 1.0f ;
indexPos = i ;
}
// BAH. Gotta clip to the near clip plane in view space to prevent
// negative w coords; negative coords throw off the projection-space clipper.
// Get the three positions in view space
int inFrontIdx = - 1 ;
for ( int j = 0 ; j < 3 ; + + j )
{
int index = m_IndexData [ indexPos ] ;
D3DXVECTOR3 * pPosition = ( D3DXVECTOR3 * ) & m_VertexData [ index * m_VertexSize ] ;
if ( ( transformedVert [ index > > 3 ] & ( 1 < < ( index & 0x7 ) ) ) = = 0 )
{
D3DXVec3TransformCoord ( pPosition , pPosition , & modelToView ) ;
transformedVert [ index > > 3 ] | = ( 1 < < ( index & 0x7 ) ) ;
}
pPos [ j ] = pPosition ;
if ( pPos [ j ] - > z < 0.0f )
inFrontIdx = j ;
+ + indexPos ;
}
// all points are behind the camera
if ( inFrontIdx < 0 )
continue ;
// backface cull....
D3DXVec3Subtract ( & edge [ 0 ] , pPos [ 1 ] , pPos [ 0 ] ) ;
D3DXVec3Subtract ( & edge [ 1 ] , pPos [ 2 ] , pPos [ 0 ] ) ;
D3DXVec3Cross ( & normal , & edge [ 0 ] , & edge [ 1 ] ) ;
float dot = D3DXVec3Dot ( & normal , pPos [ inFrontIdx ] ) ;
if ( dot * cullFactor > 0.0f )
continue ;
// Clip to viewport
ClipTriangle ( pPos , zNear , projection ) ;
}
}
//-----------------------------------------------------------------------------
// Begins a render pass
//-----------------------------------------------------------------------------
void CTempMeshDX8 : : BeginPass ( )
{
Assert ( ! m_InPass ) ;
# ifdef DBGFLAG_ASSERT
m_InPass = true ;
# endif
CMeshBuilder * pMeshBuilder = ShaderAPI ( ) - > GetVertexModifyBuilder ( ) ;
CDynamicMeshDX8 * pMesh = GetDynamicMesh ( ) ;
int nIndexCount ;
int nFirstIndex ;
if ( ( s_FirstIndex = = - 1 ) & & ( s_NumIndices = = 0 ) )
{
nIndexCount = m_IndexData . Count ( ) ;
nFirstIndex = 0 ;
}
else
{
nIndexCount = s_NumIndices ;
nFirstIndex = s_FirstIndex ;
}
int i ;
int nVertexCount = m_VertexData . Count ( ) / m_VertexSize ;
pMeshBuilder - > Begin ( pMesh , m_Type , nVertexCount , nIndexCount ) ;
// Copy in the vertex data...
// Note that since we pad the vertices, it's faster for us to simply
// copy the fields we're using...
Assert ( pMeshBuilder - > BaseVertexData ( ) ) ;
memcpy ( pMeshBuilder - > BaseVertexData ( ) , m_VertexData . Base ( ) , m_VertexData . Count ( ) ) ;
pMeshBuilder - > AdvanceVertices ( m_VertexData . Count ( ) / m_VertexSize ) ;
for ( i = 0 ; i < nIndexCount ; + + i )
{
pMeshBuilder - > Index ( m_IndexData [ nFirstIndex + i ] ) ;
pMeshBuilder - > AdvanceIndex ( ) ;
}
// NOTE: The client is expected to modify the data after this call is made
pMeshBuilder - > Reset ( ) ;
}
//-----------------------------------------------------------------------------
// Draws a single pass
//-----------------------------------------------------------------------------
void CTempMeshDX8 : : RenderPass ( )
{
Assert ( m_InPass ) ;
# ifdef DBGFLAG_ASSERT
m_InPass = false ;
# endif
// Have the shader API modify the vertex data as it needs
// This vertex data is modified based on state set by the material
ShaderAPI ( ) - > ModifyVertexData ( ) ;
// Done building the mesh
ShaderAPI ( ) - > GetVertexModifyBuilder ( ) - > End ( ) ;
// Have the dynamic mesh render a single pass...
GetDynamicMesh ( ) - > DrawSinglePassImmediately ( ) ;
}
//-----------------------------------------------------------------------------
//
// Buffered mesh implementation
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
CBufferedMeshDX8 : : CBufferedMeshDX8 ( ) : m_IsFlushing ( false ) , m_WasRendered ( true )
{
m_pMesh = NULL ;
# ifdef DEBUG_BUFFERED_STATE
m_BufferedStateSet = false ;
# endif
}
CBufferedMeshDX8 : : ~ CBufferedMeshDX8 ( )
{
}
//-----------------------------------------------------------------------------
// Sets the mesh
//-----------------------------------------------------------------------------
void CBufferedMeshDX8 : : SetMesh ( CBaseMeshDX8 * pMesh )
{
if ( m_pMesh ! = pMesh )
{
ShaderAPI ( ) - > FlushBufferedPrimitives ( ) ;
m_pMesh = pMesh ;
}
}
//-----------------------------------------------------------------------------
// Spews the mesh data
//-----------------------------------------------------------------------------
void CBufferedMeshDX8 : : Spew ( int nVertexCount , int nIndexCount , const MeshDesc_t & spewDesc )
{
if ( m_pMesh )
{
m_pMesh - > Spew ( nVertexCount , nIndexCount , spewDesc ) ;
}
}
//-----------------------------------------------------------------------------
// Sets the material
//-----------------------------------------------------------------------------
void CBufferedMeshDX8 : : SetVertexFormat ( VertexFormat_t format )
{
Assert ( m_pMesh ) ;
if ( m_pMesh - > NeedsVertexFormatReset ( format ) )
{
ShaderAPI ( ) - > FlushBufferedPrimitives ( ) ;
m_pMesh - > SetVertexFormat ( format ) ;
}
}
void CBufferedMeshDX8 : : SetMorphFormat ( MorphFormat_t format )
{
Assert ( m_pMesh ) ;
m_pMesh - > SetMorphFormat ( format ) ;
}
VertexFormat_t CBufferedMeshDX8 : : GetVertexFormat ( ) const
{
Assert ( m_pMesh ) ;
return m_pMesh - > GetVertexFormat ( ) ;
}
void CBufferedMeshDX8 : : SetMaterial ( IMaterial * pMaterial )
{
# if _DEBUG
Assert ( m_pMesh ) ;
m_pMesh - > SetMaterial ( pMaterial ) ;
# endif
}
void CBufferedMeshDX8 : : ValidateData ( int nVertexCount , int nIndexCount , const MeshDesc_t & spewDesc )
{
# if _DEBUG
Assert ( m_pMesh ) ;
m_pMesh - > ValidateData ( nVertexCount , nIndexCount , spewDesc ) ;
# endif
}
//-----------------------------------------------------------------------------
// Sets the flex mesh to render with this mesh
//-----------------------------------------------------------------------------
void CBufferedMeshDX8 : : SetFlexMesh ( IMesh * pMesh , int nVertexOffsetInBytes )
{
// FIXME: Probably are situations where we don't need to flush,
// but this is going to look different in a very short while, so I'm not going to bother
ShaderAPI ( ) - > FlushBufferedPrimitives ( ) ;
m_pMesh - > SetFlexMesh ( pMesh , nVertexOffsetInBytes ) ;
}
//-----------------------------------------------------------------------------
// checks to see if it was rendered..
//-----------------------------------------------------------------------------
void CBufferedMeshDX8 : : ResetRendered ( )
{
m_WasRendered = false ;
}
bool CBufferedMeshDX8 : : WasNotRendered ( ) const
{
return ! m_WasRendered ;
}
//-----------------------------------------------------------------------------
// "Draws" it
//-----------------------------------------------------------------------------
void CBufferedMeshDX8 : : Draw ( int nFirstIndex , int nIndexCount )
{
if ( ! ShaderUtil ( ) - > OnDrawMesh ( this , nFirstIndex , nIndexCount ) )
{
m_WasRendered = true ;
MarkAsDrawn ( ) ;
return ;
}
Assert ( ! m_IsFlushing & & ! m_WasRendered ) ;
// Gotta draw all of the buffered mesh
Assert ( ( nFirstIndex = = - 1 ) & & ( nIndexCount = = 0 ) ) ;
// No need to draw it more than once...
m_WasRendered = true ;
// We've got something to flush
m_FlushNeeded = true ;
// Less than 0 indices indicates we were using a standard buffer
if ( m_pMesh - > HasFlexMesh ( ) | | ! ShaderUtil ( ) - > GetConfig ( ) . bBufferPrimitives )
{
ShaderAPI ( ) - > FlushBufferedPrimitives ( ) ;
}
}
//-----------------------------------------------------------------------------
// Sets the primitive mode
//-----------------------------------------------------------------------------
void CBufferedMeshDX8 : : SetPrimitiveType ( MaterialPrimitiveType_t type )
{
Assert ( IsX360 ( ) | | ( type ! = MATERIAL_INSTANCED_QUADS ) ) ;
Assert ( type ! = MATERIAL_HETEROGENOUS ) ;
if ( type ! = GetPrimitiveType ( ) )
{
ShaderAPI ( ) - > FlushBufferedPrimitives ( ) ;
m_pMesh - > SetPrimitiveType ( type ) ;
}
}
MaterialPrimitiveType_t CBufferedMeshDX8 : : GetPrimitiveType ( ) const
{
return m_pMesh - > GetPrimitiveType ( ) ;
}
//-----------------------------------------------------------------------------
// Locks/unlocks the entire mesh
//-----------------------------------------------------------------------------
void CBufferedMeshDX8 : : LockMesh ( int nVertexCount , int nIndexCount , MeshDesc_t & desc )
{
ShaderUtil ( ) - > SyncMatrices ( ) ;
Assert ( m_pMesh ) ;
Assert ( m_WasRendered ) ;
// Do some pre-lock processing
m_pMesh - > PreLock ( ) ;
// for tristrips, gotta make degenerate ones...
m_ExtraIndices = 0 ;
bool tristripFixup = ( m_pMesh - > IndexCount ( ) ! = 0 ) & &
( m_pMesh - > GetPrimitiveType ( ) = = MATERIAL_TRIANGLE_STRIP ) ;
if ( tristripFixup )
{
m_ExtraIndices = ( m_pMesh - > IndexCount ( ) & 0x1 ) ! = 0 ? 3 : 2 ;
nIndexCount + = m_ExtraIndices ;
}
// Flush if we gotta
if ( ! m_pMesh - > HasEnoughRoom ( nVertexCount , nIndexCount ) )
{
ShaderAPI ( ) - > FlushBufferedPrimitives ( ) ;
}
m_pMesh - > LockMesh ( nVertexCount , nIndexCount , desc ) ;
// This is taken care of in the function above.
// CBaseMeshDX8::m_bMeshLocked = true;
// Deal with fixing up the tristrip..
if ( tristripFixup & & desc . m_nIndexSize )
{
char buf [ 32 ] ;
if ( DebugTrace ( ) )
{
if ( m_ExtraIndices = = 3 )
sprintf ( buf , " Link Index: %d %d \n " , m_LastIndex , m_LastIndex ) ;
else
sprintf ( buf , " Link Index: %d \n " , m_LastIndex ) ;
Plat_DebugString ( buf ) ;
}
* desc . m_pIndices + + = m_LastIndex ;
if ( m_ExtraIndices = = 3 )
{
* desc . m_pIndices + + = m_LastIndex ;
}
// Leave room for the last padding index
+ + desc . m_pIndices ;
}
m_WasRendered = false ;
# ifdef DEBUG_BUFFERED_MESHES
if ( m_BufferedStateSet )
{
BufferedState_t compare ;
ShaderAPI ( ) - > GetBufferedState ( compare ) ;
Assert ( ! memcmp ( & compare , & m_BufferedState , sizeof ( compare ) ) ) ;
}
else
{
ShaderAPI ( ) - > GetBufferedState ( m_BufferedState ) ;
m_BufferedStateSet = true ;
}
# endif
}
//-----------------------------------------------------------------------------
// Locks/unlocks the entire mesh
//-----------------------------------------------------------------------------
void CBufferedMeshDX8 : : UnlockMesh ( int nVertexCount , int nIndexCount , MeshDesc_t & desc )
{
Assert ( m_pMesh ) ;
// Gotta fix up the first index to batch strips reasonably
if ( ( m_pMesh - > GetPrimitiveType ( ) = = MATERIAL_TRIANGLE_STRIP ) & & desc . m_nIndexSize )
{
if ( m_ExtraIndices > 0 )
{
* ( desc . m_pIndices - 1 ) = * desc . m_pIndices ;
if ( DebugTrace ( ) )
{
char buf [ 32 ] ;
sprintf ( buf , " Link Index: %d \n " , * desc . m_pIndices ) ;
Plat_DebugString ( buf ) ;
}
}
// Remember the last index for next time
m_LastIndex = desc . m_pIndices [ nIndexCount - 1 ] ;
nIndexCount + = m_ExtraIndices ;
}
m_pMesh - > UnlockMesh ( nVertexCount , nIndexCount , desc ) ;
// This is taken care of in the function above.
// CBaseMeshDX8::m_bMeshLocked = false;
}
//-----------------------------------------------------------------------------
// Renders a pass
//-----------------------------------------------------------------------------
void CBufferedMeshDX8 : : RenderPass ( )
{
// this should never be called!
Assert ( 0 ) ;
}
//-----------------------------------------------------------------------------
// Flushes queued data
//-----------------------------------------------------------------------------
void CBufferedMeshDX8 : : Flush ( )
{
// If you are hitting this assert you are causing a flush between a
// meshbuilder begin/end and you are more than likely losing rendering data.
AssertOnce ( ! CBaseMeshDX8 : : m_bMeshLocked ) ;
if ( m_pMesh & & ! m_IsFlushing & & m_FlushNeeded )
{
VPROF ( " CBufferedMeshDX8::Flush " ) ;
# ifdef DEBUG_BUFFERED_MESHES
if ( m_BufferedStateSet )
{
BufferedState_t compare ;
ShaderAPI ( ) - > GetBufferedState ( compare ) ;
Assert ( ! memcmp ( & compare , & m_BufferedState , sizeof ( compare ) ) ) ;
m_BufferedStateSet = false ;
}
# endif
m_IsFlushing = true ;
// Actually draws the data using the mesh's material
static_cast < IMesh * > ( m_pMesh ) - > Draw ( ) ;
m_IsFlushing = false ;
m_FlushNeeded = false ;
m_pMesh - > SetFlexMesh ( NULL , 0 ) ;
}
}
//-----------------------------------------------------------------------------
//
// Mesh manager implementation
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Constructor, destructor
//-----------------------------------------------------------------------------
CMeshMgr : : CMeshMgr ( ) :
m_pDynamicIndexBuffer ( 0 ) ,
m_DynamicTempMesh ( true ) ,
m_pVertexIDBuffer ( 0 ) ,
m_pCurrentVertexBuffer ( NULL ) ,
m_CurrentVertexFormat ( 0 ) ,
m_pCurrentIndexBuffer ( NULL ) ,
m_DynamicIndexBuffer ( SHADER_BUFFER_TYPE_DYNAMIC , MATERIAL_INDEX_FORMAT_16BIT , INDEX_BUFFER_SIZE , " dynamic " ) ,
m_DynamicVertexBuffer ( SHADER_BUFFER_TYPE_DYNAMIC , VERTEX_FORMAT_UNKNOWN , DYNAMIC_VERTEX_BUFFER_MEMORY , " dynamic " )
{
m_bUseFatVertices = false ;
m_nIndexBufferOffset = 0 ;
memset ( m_pVertexBufferOffset , 0 , sizeof ( m_pVertexBufferOffset ) ) ;
memset ( m_pCurrentVertexStride , 0 , sizeof ( m_pCurrentVertexStride ) ) ;
memset ( m_pFirstVertex , 0 , sizeof ( m_pFirstVertex ) ) ;
memset ( m_pVertexCount , 0 , sizeof ( m_pVertexCount ) ) ;
m_nUnusedVertexFields = 0 ;
m_nUnusedTextureCoords = 0 ;
m_pZeroVertexBuffer = NULL ;
}
CMeshMgr : : ~ CMeshMgr ( )
{
}
//-----------------------------------------------------------------------------
// Initialize, shutdown
//-----------------------------------------------------------------------------
void CMeshMgr : : Init ( )
{
m_DynamicMesh . Init ( 0 ) ;
m_DynamicFlexMesh . Init ( 1 ) ;
CreateDynamicIndexBuffer ( ) ;
// If we're running in vs3.0, allocate a vertexID buffer
CreateVertexIDBuffer ( ) ;
CreateZeroVertexBuffer ( ) ;
m_BufferedMode = ! IsX360 ( ) ;
}
void CMeshMgr : : Shutdown ( )
{
CleanUp ( ) ;
}
//-----------------------------------------------------------------------------
// Task switch...
//-----------------------------------------------------------------------------
void CMeshMgr : : ReleaseBuffers ( )
{
if ( IsPC ( ) & & mat_debugalttab . GetBool ( ) )
{
Warning ( " mat_debugalttab: CMeshMgr::ReleaseBuffers \n " ) ;
}
CleanUp ( ) ;
m_DynamicMesh . Reset ( ) ;
m_DynamicFlexMesh . Reset ( ) ;
}
void CMeshMgr : : RestoreBuffers ( )
{
if ( IsPC ( ) & & mat_debugalttab . GetBool ( ) )
{
Warning ( " mat_debugalttab: CMeshMgr::RestoreBuffers \n " ) ;
}
Init ( ) ;
}
//-----------------------------------------------------------------------------
// Cleans up vertex and index buffers
//-----------------------------------------------------------------------------
void CMeshMgr : : CleanUp ( )
{
DestroyDynamicIndexBuffer ( ) ;
DestroyVertexBuffers ( ) ;
// If we're running in vs3.0, allocate a vertexID buffer
DestroyVertexIDBuffer ( ) ;
DestroyZeroVertexBuffer ( ) ;
}
//-----------------------------------------------------------------------------
// Fills a vertexID buffer
//-----------------------------------------------------------------------------
void CMeshMgr : : FillVertexIDBuffer ( CVertexBuffer * pVertexIDBuffer , int nCount )
{
if ( IsX360 ( ) )
return ;
// Fill the buffer with the values 0->(nCount-1)
int nBaseVertexIndex = 0 ;
float * pBuffer = ( float * ) pVertexIDBuffer - > Lock ( nCount , nBaseVertexIndex ) ;
for ( int i = 0 ; i < nCount ; + + i )
{
* pBuffer + + = ( float ) i ;
}
pVertexIDBuffer - > Unlock ( nCount ) ;
}
//-----------------------------------------------------------------------------
// Creates, destroys the dynamic index buffer
//-----------------------------------------------------------------------------
void CMeshMgr : : CreateDynamicIndexBuffer ( )
{
DestroyDynamicIndexBuffer ( ) ;
SafeAssign ( & m_pDynamicIndexBuffer , new CIndexBuffer ( Dx9Device ( ) , INDEX_BUFFER_SIZE , ShaderAPI ( ) - > UsingSoftwareVertexProcessing ( ) , true ) ) ;
}
void CMeshMgr : : DestroyDynamicIndexBuffer ( )
{
SafeRelease ( & m_pDynamicIndexBuffer ) ;
}
//-----------------------------------------------------------------------------
// Creates, destroys the vertexID buffer
//-----------------------------------------------------------------------------
void CMeshMgr : : CreateVertexIDBuffer ( )
{
if ( IsX360 ( ) )
return ;
DestroyVertexIDBuffer ( ) ;
// Track mesh allocations
g_VBAllocTracker - > TrackMeshAllocations ( " CreateVertexIDBuffer " ) ;
if ( g_pHardwareConfig - > HasFastVertexTextures ( ) )
{
m_pVertexIDBuffer = new CVertexBuffer ( Dx9Device ( ) , 0 , 0 , sizeof ( float ) ,
VERTEX_BUFFER_SIZE , TEXTURE_GROUP_STATIC_VERTEX_BUFFER_OTHER , ShaderAPI ( ) - > UsingSoftwareVertexProcessing ( ) ) ;
FillVertexIDBuffer ( m_pVertexIDBuffer , VERTEX_BUFFER_SIZE ) ;
}
g_VBAllocTracker - > TrackMeshAllocations ( NULL ) ;
}
void CMeshMgr : : CreateZeroVertexBuffer ( )
{
if ( ! m_pZeroVertexBuffer )
{
// In GL glVertexAttribPointer() doesn't support strides of 0, so we need to allocate a dummy vertex buffer large enough to handle 16-bit indices with a stride of 4 byte per vertex, plus a bit more for safety (in case basevertexindex is > 0).
// We could also try just disabling any vertex attribs that fetch from stream 2 and need 0's, but AMD reports this could hit a slow path in the driver. Argh.
uint nBufSize = IsOpenGL ( ) ? ( 65536 * 2 * 4 ) : 4096 ;
HRESULT hr = Dx9Device ( ) - > CreateVertexBuffer ( nBufSize , D3DUSAGE_WRITEONLY , 0 , D3DPOOL_DEFAULT , & m_pZeroVertexBuffer , NULL ) ;
if ( ! FAILED ( hr ) )
{
void * pData = NULL ;
m_pZeroVertexBuffer - > Lock ( 0 , nBufSize , & pData , D3DLOCK_NOSYSLOCK ) ;
if ( pData )
{
V_memset ( pData , 0 , nBufSize ) ;
m_pZeroVertexBuffer - > Unlock ( ) ;
}
}
}
}
void CMeshMgr : : DestroyZeroVertexBuffer ( )
{
if ( m_pZeroVertexBuffer )
{
m_pZeroVertexBuffer - > Release ( ) ;
m_pZeroVertexBuffer = NULL ;
}
}
void CMeshMgr : : DestroyVertexIDBuffer ( )
{
if ( m_pVertexIDBuffer )
{
delete m_pVertexIDBuffer ;
m_pVertexIDBuffer = NULL ;
}
}
CVertexBuffer * CMeshMgr : : GetVertexIDBuffer ( )
{
return m_pVertexIDBuffer ;
}
//-----------------------------------------------------------------------------
// Unused vertex fields
//-----------------------------------------------------------------------------
void CMeshMgr : : MarkUnusedVertexFields ( unsigned int nFlags , int nTexCoordCount , bool * pUnusedTexCoords )
{
m_nUnusedVertexFields = nFlags ;
m_nUnusedTextureCoords = 0 ;
for ( int i = 0 ; i < nTexCoordCount ; + + i )
{
if ( pUnusedTexCoords [ i ] )
{
m_nUnusedTextureCoords | = ( 1 < < i ) ;
}
}
}
//-----------------------------------------------------------------------------
// Is the mesh dynamic?
//-----------------------------------------------------------------------------
bool CMeshMgr : : IsDynamicMesh ( IMesh * pMesh ) const
{
return ( pMesh = = & m_DynamicMesh ) | | ( pMesh = = & m_DynamicFlexMesh ) ;
}
bool CMeshMgr : : IsBufferedDynamicMesh ( IMesh * pMesh ) const
{
return ( pMesh = = & m_BufferedMesh ) ;
}
bool CMeshMgr : : IsDynamicVertexBuffer ( IVertexBuffer * pVertexBuffer ) const
{
return ( pVertexBuffer = = & m_DynamicVertexBuffer ) ;
}
bool CMeshMgr : : IsDynamicIndexBuffer ( IIndexBuffer * pIndexBuffer ) const
{
return ( pIndexBuffer = = & m_DynamicIndexBuffer ) ;
}
//-----------------------------------------------------------------------------
// Discards the dynamic vertex and index buffer
//-----------------------------------------------------------------------------
void CMeshMgr : : DiscardVertexBuffers ( )
{
VPROF_BUDGET ( " CMeshMgr::DiscardVertexBuffers " , VPROF_BUDGETGROUP_SWAP_BUFFERS ) ;
// This shouldn't be necessary, but it seems to be on GeForce 2
// It helps when running WC and the engine simultaneously.
ResetMeshRenderState ( ) ;
if ( ! g_pShaderDeviceDx8 - > IsDeactivated ( ) )
{
for ( int i = m_DynamicVertexBuffers . Count ( ) ; - - i > = 0 ; )
{
m_DynamicVertexBuffers [ i ] . m_pBuffer - > FlushAtFrameStart ( ) ;
}
m_pDynamicIndexBuffer - > FlushAtFrameStart ( ) ;
}
}
//-----------------------------------------------------------------------------
// Releases all dynamic vertex buffers
//-----------------------------------------------------------------------------
void CMeshMgr : : DestroyVertexBuffers ( )
{
// Necessary for cleanup
RECORD_COMMAND ( DX8_SET_STREAM_SOURCE , 4 ) ;
RECORD_INT ( - 1 ) ;
RECORD_INT ( 0 ) ;
RECORD_INT ( 0 ) ;
RECORD_INT ( 0 ) ;
D3DSetStreamSource ( 0 , 0 , 0 , 0 ) ;
RECORD_COMMAND ( DX8_SET_STREAM_SOURCE , 4 ) ;
RECORD_INT ( - 1 ) ;
RECORD_INT ( 1 ) ;
RECORD_INT ( 0 ) ;
RECORD_INT ( 0 ) ;
D3DSetStreamSource ( 1 , 0 , 0 , 0 ) ;
RECORD_COMMAND ( DX8_SET_STREAM_SOURCE , 4 ) ;
RECORD_INT ( - 1 ) ;
RECORD_INT ( 2 ) ;
RECORD_INT ( 0 ) ;
RECORD_INT ( 0 ) ;
D3DSetStreamSource ( 2 , 0 , 0 , 0 ) ;
# ifndef _X360
RECORD_COMMAND ( DX8_SET_STREAM_SOURCE , 4 ) ;
RECORD_INT ( - 1 ) ;
RECORD_INT ( 3 ) ;
RECORD_INT ( 0 ) ;
RECORD_INT ( 0 ) ;
D3DSetStreamSource ( 3 , 0 , 0 , 0 ) ;
# endif
for ( int i = m_DynamicVertexBuffers . Count ( ) ; - - i > = 0 ; )
{
if ( m_DynamicVertexBuffers [ i ] . m_pBuffer )
{
delete m_DynamicVertexBuffers [ i ] . m_pBuffer ;
}
}
m_DynamicVertexBuffers . RemoveAll ( ) ;
m_DynamicMesh . Reset ( ) ;
m_DynamicFlexMesh . Reset ( ) ;
}
//-----------------------------------------------------------------------------
// Flushes the dynamic mesh
//-----------------------------------------------------------------------------
void CMeshMgr : : Flush ( )
{
if ( IsPC ( ) )
{
m_BufferedMesh . HandleLateCreation ( ) ;
m_BufferedMesh . Flush ( ) ;
}
}
//-----------------------------------------------------------------------------
// Creates, destroys static meshes
//-----------------------------------------------------------------------------
IMesh * CMeshMgr : : CreateStaticMesh ( VertexFormat_t format , const char * pTextureBudgetGroup , IMaterial * pMaterial )
{
// FIXME: Use a fixed-size allocator
CMeshDX8 * pNewMesh = new CMeshDX8 ( pTextureBudgetGroup ) ;
pNewMesh - > SetVertexFormat ( format ) ;
if ( pMaterial ! = NULL )
{
pNewMesh - > SetMorphFormat ( pMaterial - > GetMorphFormat ( ) ) ;
pNewMesh - > SetMaterial ( pMaterial ) ;
}
return pNewMesh ;
}
void CMeshMgr : : DestroyStaticMesh ( IMesh * pMesh )
{
// Don't destroy the dynamic mesh!
Assert ( ! IsDynamicMesh ( pMesh ) ) ;
CBaseMeshDX8 * pMeshImp = static_cast < CBaseMeshDX8 * > ( pMesh ) ;
if ( pMeshImp )
{
delete pMeshImp ;
}
}
//-----------------------------------------------------------------------------
// Gets at the *real* dynamic mesh
//-----------------------------------------------------------------------------
IMesh * CMeshMgr : : GetActualDynamicMesh ( VertexFormat_t format )
{
m_DynamicMesh . SetVertexFormat ( format ) ;
return & m_DynamicMesh ;
}
//-----------------------------------------------------------------------------
// Copy a static mesh index buffer to a dynamic mesh index buffer
//-----------------------------------------------------------------------------
void CMeshMgr : : CopyStaticMeshIndexBufferToTempMeshIndexBuffer ( CTempMeshDX8 * pDstIndexMesh ,
CMeshDX8 * pSrcIndexMesh )
{
tmZoneFiltered ( TELEMETRY_LEVEL0 , 50 , TMZF_NONE , " %s " , __FUNCTION__ ) ;
Assert ( ! pSrcIndexMesh - > IsDynamic ( ) ) ;
int nIndexCount = pSrcIndexMesh - > IndexCount ( ) ;
CMeshBuilder dstMeshBuilder ;
dstMeshBuilder . Begin ( pDstIndexMesh , pSrcIndexMesh - > GetPrimitiveType ( ) , 0 , nIndexCount ) ;
CIndexBuffer * srcIndexBuffer = pSrcIndexMesh - > GetIndexBuffer ( ) ;
int dummy = 0 ;
unsigned short * srcIndexArray = srcIndexBuffer - > Lock ( false , nIndexCount , dummy , 0 ) ;
int i ;
for ( i = 0 ; i < nIndexCount ; i + + )
{
dstMeshBuilder . Index ( srcIndexArray [ i ] ) ;
dstMeshBuilder . AdvanceIndex ( ) ;
}
srcIndexBuffer - > Unlock ( 0 ) ;
dstMeshBuilder . End ( ) ;
}
IMesh * CMeshMgr : : GetFlexMesh ( )
{
if ( g_pMaterialSystemHardwareConfig - > SupportsPixelShaders_2_b ( ) )
{
// FIXME: Kinda ugly size.. 28 bytes
m_DynamicFlexMesh . SetVertexFormat ( VERTEX_POSITION | VERTEX_NORMAL | VERTEX_WRINKLE | VERTEX_FORMAT_USE_EXACT_FORMAT ) ;
}
else
{
// Same size as a pair of float3s (24 bytes)
m_DynamicFlexMesh . SetVertexFormat ( VERTEX_POSITION | VERTEX_NORMAL | VERTEX_FORMAT_USE_EXACT_FORMAT ) ;
}
return & m_DynamicFlexMesh ;
}
//-----------------------------------------------------------------------------
// Gets at the dynamic mesh
//-----------------------------------------------------------------------------
IMesh * CMeshMgr : : GetDynamicMesh ( IMaterial * pMaterial , VertexFormat_t vertexFormat , int nHWSkinBoneCount ,
bool buffered , IMesh * pVertexOverride , IMesh * pIndexOverride )
{
tmZoneFiltered ( TELEMETRY_LEVEL0 , 50 , TMZF_NONE , " %s " , __FUNCTION__ ) ;
Assert ( ( pMaterial = = NULL ) | | ( ( IMaterialInternal * ) pMaterial ) - > IsRealTimeVersion ( ) ) ;
if ( IsX360 ( ) )
{
buffered = false ;
}
// Can't be buffered if we're overriding the buffers
if ( pVertexOverride | | pIndexOverride )
{
buffered = false ;
}
// When going from buffered to unbuffered mode, need to flush..
if ( ( m_BufferedMode ! = buffered ) & & m_BufferedMode )
{
m_BufferedMesh . SetMesh ( 0 ) ;
}
m_BufferedMode = buffered ;
IMaterialInternal * pMatInternal = static_cast < IMaterialInternal * > ( pMaterial ) ;
bool needTempMesh = ShaderAPI ( ) - > IsInSelectionMode ( ) ;
# ifdef DRAW_SELECTION
if ( g_bDrawSelection )
{
needTempMesh = true ;
}
# endif
CBaseMeshDX8 * pMesh ;
if ( needTempMesh )
{
// These haven't been implemented yet for temp meshes!
// I'm not a hundred percent sure how to implement them; it would
// involve a lock and a copy at least, which would stall the entire
// rendering pipeline.
Assert ( ! pVertexOverride ) ;
if ( pIndexOverride )
{
CopyStaticMeshIndexBufferToTempMeshIndexBuffer ( & m_DynamicTempMesh ,
( CMeshDX8 * ) pIndexOverride ) ;
}
pMesh = & m_DynamicTempMesh ;
}
else
{
pMesh = & m_DynamicMesh ;
}
if ( m_BufferedMode )
{
Assert ( ! m_BufferedMesh . WasNotRendered ( ) ) ;
m_BufferedMesh . SetMesh ( pMesh ) ;
pMesh = & m_BufferedMesh ;
}
if ( ! pVertexOverride )
{
// Remove VERTEX_FORMAT_COMPRESSED from the material's format (dynamic meshes don't
// support compression, and all materials should support uncompressed verts too)
VertexFormat_t materialFormat = pMatInternal - > GetVertexFormat ( ) & ~ VERTEX_FORMAT_COMPRESSED ;
VertexFormat_t fmt = ( vertexFormat ! = 0 ) ? vertexFormat : materialFormat ;
if ( vertexFormat ! = 0 )
{
int nVertexFormatBoneWeights = NumBoneWeights ( vertexFormat ) ;
if ( nHWSkinBoneCount < nVertexFormatBoneWeights )
{
nHWSkinBoneCount = nVertexFormatBoneWeights ;
}
}
// Force the requested number of bone weights
fmt & = ~ VERTEX_BONE_WEIGHT_MASK ;
if ( nHWSkinBoneCount > 0 )
{
fmt | = VERTEX_BONEWEIGHT ( 2 ) ;
fmt | = VERTEX_BONE_INDEX ;
}
pMesh - > SetVertexFormat ( fmt ) ;
}
else
{
CBaseMeshDX8 * pDX8Mesh = static_cast < CBaseMeshDX8 * > ( pVertexOverride ) ;
pMesh - > SetVertexFormat ( pDX8Mesh - > GetVertexFormat ( ) ) ;
}
pMesh - > SetMorphFormat ( pMatInternal - > GetMorphFormat ( ) ) ;
pMesh - > SetMaterial ( pMatInternal ) ;
// Note this works because we're guaranteed to not be using a buffered mesh
// when we have overrides on
// FIXME: Make work for temp meshes
if ( pMesh = = & m_DynamicMesh )
{
CBaseMeshDX8 * pBaseVertex = static_cast < CBaseMeshDX8 * > ( pVertexOverride ) ;
if ( pBaseVertex )
{
m_DynamicMesh . OverrideVertexBuffer ( pBaseVertex - > GetVertexBuffer ( ) ) ;
}
CBaseMeshDX8 * pBaseIndex = static_cast < CBaseMeshDX8 * > ( pIndexOverride ) ;
if ( pBaseIndex )
{
m_DynamicMesh . OverrideIndexBuffer ( pBaseIndex - > GetIndexBuffer ( ) ) ;
}
}
return pMesh ;
}
//-----------------------------------------------------------------------------
// Used to construct vertex data
//-----------------------------------------------------------------------------
void CMeshMgr : : ComputeVertexDescription ( unsigned char * pBuffer ,
VertexFormat_t vertexFormat , MeshDesc_t & desc ) const
{
ComputeVertexDesc ( pBuffer , vertexFormat , ( VertexDesc_t & ) desc ) ;
}
//-----------------------------------------------------------------------------
// Computes the vertex format
//-----------------------------------------------------------------------------
VertexFormat_t CMeshMgr : : ComputeVertexFormat ( unsigned int flags ,
int nTexCoordArraySize , int * pTexCoordDimensions , int numBoneWeights ,
int userDataSize ) const
{
// Construct a bitfield that makes sense and is unique from the standard FVF formats
VertexFormat_t fmt = flags & ~ VERTEX_FORMAT_USE_EXACT_FORMAT ;
if ( g_pHardwareConfig - > SupportsCompressedVertices ( ) = = VERTEX_COMPRESSION_NONE )
{
// Vertex compression is disabled - make sure all materials
// say "No!" to compressed verts ( tested in IsValidVertexFormat() )
fmt & = ~ VERTEX_FORMAT_COMPRESSED ;
}
// This'll take 3 bits at most
Assert ( numBoneWeights < = 4 ) ;
if ( numBoneWeights > 0 )
{
fmt | = VERTEX_BONEWEIGHT ( 2 ) ; // Always exactly two weights
}
// Size is measured in # of floats
Assert ( userDataSize < = 4 ) ;
fmt | = VERTEX_USERDATA_SIZE ( userDataSize ) ;
// NOTE: If pTexCoordDimensions isn't specified, then nTexCoordArraySize
// is interpreted as meaning that we have n 2D texcoords in the first N texcoord slots
nTexCoordArraySize = min ( nTexCoordArraySize , ( int ) VERTEX_MAX_TEXTURE_COORDINATES ) ;
for ( int i = 0 ; i < nTexCoordArraySize ; + + i )
{
if ( pTexCoordDimensions )
{
Assert ( pTexCoordDimensions [ i ] > = 0 & & pTexCoordDimensions [ i ] < = 4 ) ;
fmt | = VERTEX_TEXCOORD_SIZE ( ( TextureStage_t ) i , pTexCoordDimensions [ i ] ) ;
}
else
{
fmt | = VERTEX_TEXCOORD_SIZE ( ( TextureStage_t ) i , 2 ) ;
}
}
return fmt ;
}
//-----------------------------------------------------------------------------
// Use fat vertices (for tools)
//-----------------------------------------------------------------------------
void CMeshMgr : : UseFatVertices ( bool bUseFat )
{
m_bUseFatVertices = bUseFat ;
}
//-----------------------------------------------------------------------------
// Returns the number of vertices we can render using the dynamic mesh
//-----------------------------------------------------------------------------
void CMeshMgr : : GetMaxToRender ( IMesh * pMesh , bool bMaxUntilFlush , int * pMaxVerts , int * pMaxIndices )
{
CBaseMeshDX8 * pBaseMesh = static_cast < CBaseMeshDX8 * > ( pMesh ) ;
if ( ! pBaseMesh )
{
* pMaxVerts = 0 ;
* pMaxIndices = m_pDynamicIndexBuffer - > IndexCount ( ) ;
return ;
}
if ( IsBufferedDynamicMesh ( pMesh ) )
{
pBaseMesh = ( CBaseMeshDX8 * ) static_cast < CBufferedMeshDX8 * > ( pBaseMesh ) - > GetMesh ( ) ;
pMesh = pBaseMesh ;
}
// Static mesh? Max you can use is 65535
if ( ! IsDynamicMesh ( pMesh ) )
{
* pMaxVerts = 65535 ;
* pMaxIndices = 65535 ;
return ;
}
CVertexBuffer * pVertexBuffer = pBaseMesh - > GetVertexBuffer ( ) ;
CIndexBuffer * pIndexBuffer = pBaseMesh - > GetIndexBuffer ( ) ;
if ( ! pVertexBuffer )
{
* pMaxVerts = 0 ;
* pMaxIndices = 0 ;
return ;
}
if ( ! bMaxUntilFlush )
{
* pMaxVerts = ShaderAPI ( ) - > GetCurrentDynamicVBSize ( ) / pVertexBuffer - > VertexSize ( ) ;
if ( * pMaxVerts > 65535 )
{
* pMaxVerts = 65535 ;
}
* pMaxIndices = pIndexBuffer ? pIndexBuffer - > IndexCount ( ) : 0 ;
return ;
}
* pMaxVerts = pVertexBuffer - > NumVerticesUntilFlush ( ) ;
* pMaxIndices = pIndexBuffer ? pIndexBuffer - > IndexCount ( ) - pIndexBuffer - > IndexPosition ( ) : 0 ;
if ( * pMaxVerts = = 0 )
{
* pMaxVerts = ShaderAPI ( ) - > GetCurrentDynamicVBSize ( ) / pVertexBuffer - > VertexSize ( ) ;
}
if ( * pMaxVerts > 65535 )
{
* pMaxVerts = 65535 ;
}
if ( * pMaxIndices = = 0 )
{
* pMaxIndices = pIndexBuffer ? pIndexBuffer - > IndexCount ( ) : 0 ;
}
}
int CMeshMgr : : GetMaxVerticesToRender ( IMaterial * pMaterial )
{
Assert ( ( pMaterial = = NULL ) | | ( ( IMaterialInternal * ) pMaterial ) - > IsRealTimeVersion ( ) ) ;
// Be conservative, assume no compression (in here, we don't know if the caller will used a compressed VB or not)
// FIXME: allow the caller to specify which compression type should be used to compute size from the vertex format
// (this can vary between multiple VBs/Meshes using the same material)
VertexFormat_t fmt = pMaterial - > GetVertexFormat ( ) & ~ VERTEX_FORMAT_COMPRESSED ;
int nVertexSize = VertexFormatSize ( fmt ) ;
if ( nVertexSize = = 0 )
{
// unable to determine vertex format information, possibly due to device loss.
Warning ( " bad vertex size for material %s \n " , pMaterial - > GetName ( ) ) ;
return 0 ;
}
int nMaxVerts = ShaderAPI ( ) - > GetCurrentDynamicVBSize ( ) / nVertexSize ;
return MIN ( nMaxVerts , 65535 ) ;
}
int CMeshMgr : : GetMaxIndicesToRender ( )
{
return INDEX_BUFFER_SIZE ;
}
//-----------------------------------------------------------------------------
// Returns a vertex buffer appropriate for the flags
//-----------------------------------------------------------------------------
CVertexBuffer * CMeshMgr : : FindOrCreateVertexBuffer ( int nDynamicBufferId , VertexFormat_t vertexFormat )
{
int vertexSize = VertexFormatSize ( vertexFormat ) ;
while ( m_DynamicVertexBuffers . Count ( ) < = nDynamicBufferId )
{
// Track VB allocations (override any prior allocator string set higher up on the callstack)
g_VBAllocTracker - > TrackMeshAllocations ( NULL ) ;
g_VBAllocTracker - > TrackMeshAllocations ( " CMeshMgr::FindOrCreateVertexBuffer (dynamic VB) " ) ;
// create the single 1MB dynamic vb that will be shared amongst all consumers
// the correct thing is to use the largest expected vertex format size of max elements, but this
// creates an undesirably large buffer - instead create the buffer we want, and fix consumers that bork
// NOTE: GetCurrentDynamicVBSize returns a smaller value during level transitions
int nBufferMemory = ShaderAPI ( ) - > GetCurrentDynamicVBSize ( ) ;
int nIndex = m_DynamicVertexBuffers . AddToTail ( ) ;
m_DynamicVertexBuffers [ nIndex ] . m_VertexSize = 0 ;
m_DynamicVertexBuffers [ nIndex ] . m_pBuffer = new CVertexBuffer ( Dx9Device ( ) , 0 , 0 ,
nBufferMemory / VERTEX_BUFFER_SIZE , VERTEX_BUFFER_SIZE , TEXTURE_GROUP_STATIC_VERTEX_BUFFER_OTHER , ShaderAPI ( ) - > UsingSoftwareVertexProcessing ( ) , true ) ;
g_VBAllocTracker - > TrackMeshAllocations ( NULL ) ;
}
if ( m_DynamicVertexBuffers [ nDynamicBufferId ] . m_VertexSize ! = vertexSize )
{
// provide caller with dynamic vb in expected format
// NOTE: GetCurrentDynamicVBSize returns a smaller value during level transitions
int nBufferMemory = ShaderAPI ( ) - > GetCurrentDynamicVBSize ( ) ;
m_DynamicVertexBuffers [ nDynamicBufferId ] . m_VertexSize = vertexSize ;
m_DynamicVertexBuffers [ nDynamicBufferId ] . m_pBuffer - > ChangeConfiguration ( vertexSize , nBufferMemory ) ;
// size changed means stream stride needs update
// mark cached stream state as invalid to reset stream
if ( nDynamicBufferId = = 0 )
{
g_pLastVertex = NULL ;
}
}
return m_DynamicVertexBuffers [ nDynamicBufferId ] . m_pBuffer ;
}
CIndexBuffer * CMeshMgr : : GetDynamicIndexBuffer ( )
{
return m_pDynamicIndexBuffer ;
}
IVertexBuffer * CMeshMgr : : GetDynamicVertexBuffer ( IMaterial * pMaterial , bool buffered )
{
Assert ( 0 ) ;
return NULL ;
// return ( IMeshDX8 * )GetDynamicMesh( pMaterial, buffered, NULL, NULL );
}
IIndexBuffer * CMeshMgr : : GetDynamicIndexBuffer ( IMaterial * pMaterial , bool buffered )
{
Assert ( 0 ) ;
return NULL ;
// return ( IMeshDX8 * )GetDynamicMesh( pMaterial, buffered, NULL, NULL );
}
//-----------------------------------------------------------------------------
IVertexBuffer * CMeshMgr : : CreateVertexBuffer ( ShaderBufferType_t type , VertexFormat_t fmt , int nVertexCount , const char * pBudgetGroup )
{
// FIXME: Use a fixed-size allocator
CVertexBufferDx8 * pNewVertexBuffer = new CVertexBufferDx8 ( type , fmt , nVertexCount , pBudgetGroup ) ;
return pNewVertexBuffer ;
}
IIndexBuffer * CMeshMgr : : CreateIndexBuffer ( ShaderBufferType_t bufferType , MaterialIndexFormat_t fmt , int nIndexCount , const char * pBudgetGroup )
{
switch ( bufferType )
{
case SHADER_BUFFER_TYPE_STATIC :
case SHADER_BUFFER_TYPE_DYNAMIC :
{
CIndexBufferDx8 * pIndexBuffer = new CIndexBufferDx8 ( bufferType , fmt , nIndexCount , pBudgetGroup ) ;
return pIndexBuffer ;
}
case SHADER_BUFFER_TYPE_STATIC_TEMP :
case SHADER_BUFFER_TYPE_DYNAMIC_TEMP :
Assert ( 0 ) ;
return NULL ;
default :
Assert ( 0 ) ;
return NULL ;
}
}
void CMeshMgr : : DestroyVertexBuffer ( IVertexBuffer * pVertexBuffer )
{
if ( pVertexBuffer & & ! IsDynamicVertexBuffer ( pVertexBuffer ) )
{
delete pVertexBuffer ;
}
}
void CMeshMgr : : DestroyIndexBuffer ( IIndexBuffer * pIndexBuffer )
{
if ( pIndexBuffer & & ! IsDynamicIndexBuffer ( pIndexBuffer ) )
{
delete pIndexBuffer ;
}
}
// Do we need to specify the stream here in the case of locking multiple dynamic VBs on different streams?
IVertexBuffer * CMeshMgr : : GetDynamicVertexBuffer ( int streamID , VertexFormat_t vertexFormat , bool bBuffered )
{
if ( IsX360 ( ) )
{
bBuffered = false ;
}
if ( CompressionType ( vertexFormat ) ! = VERTEX_COMPRESSION_NONE )
{
// UNDONE: support compressed dynamic meshes if needed (pro: less VB memory, con: time spent compressing)
DebuggerBreak ( ) ;
return NULL ;
}
// MESHFIXME
#if 0
if ( ( m_BufferedMode ! = bBuffered ) & & m_BufferedMode )
{
m_BufferedIndexBuffer . SetIndexBuffer ( NULL ) ;
}
# endif
m_BufferedMode = bBuffered ;
Assert ( ! m_BufferedMode ) ; // MESHFIXME: don't deal with buffered VBs yet.
bool needTempMesh = ShaderAPI ( ) - > IsInSelectionMode ( ) ;
# ifdef DRAW_SELECTION
if ( g_bDrawSelection )
{
needTempMesh = true ;
}
# endif
Assert ( ! needTempMesh ) ; // MESHFIXME: don't support temp meshes here yet.
CVertexBufferDx8 * pVertexBuffer ;
if ( needTempMesh )
{
Assert ( 0 ) ; // MESHFIXME: don't do this yet.
// pVertexBuffer = &m_DynamicTempVertexBuffer;
pVertexBuffer = NULL ;
}
else
{
pVertexBuffer = & m_DynamicVertexBuffer ;
}
if ( m_BufferedMode )
{
Assert ( 0 ) ; // don't support this yet.
#if 0
Assert ( ! m_BufferedMesh . WasNotRendered ( ) ) ;
m_BufferedMesh . SetMesh ( pMesh ) ;
pMesh = & m_BufferedMesh ;
# endif
}
return pVertexBuffer ;
}
IIndexBuffer * CMeshMgr : : GetDynamicIndexBuffer ( MaterialIndexFormat_t fmt , bool bBuffered )
{
if ( IsX360 ( ) )
{
bBuffered = false ;
}
m_BufferedMode = bBuffered ;
Assert ( ! m_BufferedMode ) ;
# ifdef DBGFLAG_ASSERT
bool needTempMesh =
# endif
ShaderAPI ( ) - > IsInSelectionMode ( ) ;
# ifdef DRAW_SELECTION
if ( g_bDrawSelection )
{
needTempMesh = true ;
}
# endif
Assert ( ! needTempMesh ) ; // don't handle this yet. MESHFIXME
CIndexBufferBase * pIndexBuffer = & m_DynamicIndexBuffer ;
return pIndexBuffer ;
}
void CMeshMgr : : SetVertexIDStreamState ( )
{
if ( IsX360 ( ) )
return ;
// MESHFIXME : This path is only used for the new index/vertex buffer interfaces.
// MESHFIXME : This path is only used for the new index/vertex buffer interfaces.
bool bUsingVertexID = false ; //IsUsingVertexID();
// if ( bUsingVertexID != g_bUsingVertexID )
{
if ( bUsingVertexID )
{
// NOTE: Morphing doesn't work with dynamic buffers!!! BLEAH
// It's because the indices (which are not 0 based for dynamic buffers)
// are accessing both the vertexID buffer + the regular vertex buffer.
// This *might* be fixable with baseVertexIndex?
Assert ( ! m_pCurrentVertexBuffer - > IsDynamic ( ) ) ;
CVertexBuffer * pVertexIDBuffer = g_MeshMgr . GetVertexIDBuffer ( ) ;
RECORD_COMMAND ( DX8_SET_STREAM_SOURCE , 4 ) ;
RECORD_INT ( pVertexIDBuffer - > UID ( ) ) ;
RECORD_INT ( 3 ) ;
RECORD_INT ( 0 ) ;
RECORD_INT ( pVertexIDBuffer - > VertexSize ( ) ) ;
D3DSetStreamSource ( 3 , pVertexIDBuffer - > GetInterface ( ) , 0 , pVertexIDBuffer - > VertexSize ( ) ) ;
pVertexIDBuffer - > HandlePerFrameTextureStats ( ShaderAPI ( ) - > GetCurrentFrameCounter ( ) ) ;
}
else
{
RECORD_COMMAND ( DX8_SET_STREAM_SOURCE , 4 ) ;
RECORD_INT ( - 1 ) ; // vertex buffer id
RECORD_INT ( 3 ) ; // stream
RECORD_INT ( 0 ) ; // vertex offset
RECORD_INT ( 0 ) ; // vertex size
D3DSetStreamSource ( 3 , 0 , 0 , 0 ) ;
}
g_bUsingVertexID = bUsingVertexID ;
}
}
void CMeshMgr : : SetColorStreamState ( )
{
if ( g_pLastColorMesh )
{
RECORD_COMMAND ( DX8_SET_STREAM_SOURCE , 4 ) ;
RECORD_INT ( - 1 ) ; // vertex buffer id
RECORD_INT ( 1 ) ; // stream
RECORD_INT ( 0 ) ; // vertex offset
RECORD_INT ( 0 ) ; // vertex size
D3DSetStreamSource ( 1 , 0 , 0 , 0 ) ;
}
g_pLastColorMesh = NULL ;
g_nLastColorMeshVertOffsetInBytes = 0 ;
}
void CMeshMgr : : SetVertexStreamState ( int nVertOffsetInBytes , int nVertexStride )
{
// Calls in here assume shader support...
if ( HardwareConfig ( ) - > SupportsVertexAndPixelShaders ( ) )
{
// Set a 4kb all-zero static VB into the flex/wrinkle stream with a stride of 0 bytes, so the vertex shader always reads valid floating point values (otherwise it can get NaN's/Inf's, and under OpenGL this is bad on NVidia)
// togl requires non-zero strides, but on D3D9 we can set a stride of 0 for a little more efficiency.
D3DSetStreamSource ( 2 , g_MeshMgr . GetZeroVertexBuffer ( ) , 0 , IsOpenGL ( ) ? 4 : 0 ) ;
// cFlexScale.x masks flex in vertex shader
if ( g_pHardwareConfig - > Caps ( ) . m_SupportsVertexShaders_2_0 )
{
float c [ 4 ] = { 0.0f , 0.0f , 0.0f , 0.0f } ;
ShaderAPI ( ) - > SetVertexShaderConstant ( VERTEX_SHADER_FLEXSCALE , c , 1 ) ;
}
g_bFlexMeshStreamSet = false ;
}
// MESHFIXME : This path is only used for the new index/vertex buffer interfaces.
if ( g_pLastVertex | | ( g_pLastVertexBuffer ! = m_pCurrentVertexBuffer - > GetDx9Buffer ( ) ) | |
( g_nLastVertOffsetInBytes ! = nVertOffsetInBytes ) | | ( g_nLastVertStride ! = nVertexStride ) )
{
Assert ( m_pCurrentVertexBuffer & & m_pCurrentVertexBuffer - > GetDx9Buffer ( ) ) ;
D3DSetStreamSource ( 0 , m_pCurrentVertexBuffer - > GetDx9Buffer ( ) , nVertOffsetInBytes , nVertexStride ) ;
m_pCurrentVertexBuffer - > HandlePerFrameTextureStats ( ShaderAPI ( ) - > GetCurrentFrameCounter ( ) ) ;
g_pLastVertex = NULL ;
g_nLastVertStride = nVertexStride ;
g_pLastVertexBuffer = m_pCurrentVertexBuffer - > GetDx9Buffer ( ) ;
g_nLastVertOffsetInBytes = nVertOffsetInBytes ;
}
}
bool CMeshMgr : : SetRenderState ( int nVertexOffsetInBytes , int nFirstVertexIdx , VertexFormat_t vertexFormat , int nVertexStride )
{
// Can't set the state if we're deactivated
if ( g_pShaderDeviceDx8 - > IsDeactivated ( ) )
{
ResetMeshRenderState ( ) ;
return false ;
}
// make sure the vertex format is a superset of the current material's
// vertex format...
// MESHFIXME : This path is only used for the new index/vertex buffer interfaces.
#if 0
// FIXME
if ( ! IsValidVertexFormat ( vertexFormat ) )
{
Warning ( " Material %s is being applied to a model, you need $model=1 in the .vmt file! \n " ,
ShaderAPI ( ) - > GetBoundMaterial ( ) - > GetName ( ) ) ;
return false ;
}
# endif
SetVertexIDStreamState ( ) ;
SetColorStreamState ( ) ;
SetVertexStreamState ( nVertexOffsetInBytes , nVertexStride ) ;
SetIndexStreamState ( nFirstVertexIdx ) ;
return true ;
}
void CMeshMgr : : BindVertexBuffer ( int nStreamID , IVertexBuffer * pVertexBuffer , int nOffsetInBytes , int nFirstVertex , int nVertexCount , VertexFormat_t fmt , int nRepetitions )
{
// FIXME: Multiple stream support isn't implemented yet
Assert ( nStreamID = = 0 ) ;
m_pCurrentVertexBuffer = static_cast < CVertexBufferDx8 * > ( pVertexBuffer ) ;
m_CurrentVertexFormat = fmt ;
m_pVertexBufferOffset [ nStreamID ] = nOffsetInBytes ;
m_pCurrentVertexStride [ nStreamID ] = m_pCurrentVertexBuffer - > VertexSize ( ) ;
m_pFirstVertex [ nStreamID ] = nFirstVertex ;
m_pVertexCount [ nStreamID ] = nVertexCount ,
m_pVertexIDBuffer = NULL ;
}
void CMeshMgr : : BindIndexBuffer ( IIndexBuffer * pIndexBuffer , int nOffsetInBytes )
{
m_pCurrentIndexBuffer = static_cast < CIndexBufferBase * > ( pIndexBuffer ) ;
m_nIndexBufferOffset = nOffsetInBytes ;
}
void CMeshMgr : : Draw ( MaterialPrimitiveType_t primitiveType , int nFirstIndex , int nIndexCount )
{
// MESHFIXME : This path is only used for the new index/vertex buffer interfaces.
// make sure we aren't using a morph stream for this path.
// Assert( !IsUsingMorphData() );
// Assert( !m_pColorMesh );
SetRenderState ( m_pVertexBufferOffset [ 0 ] , /* nFirstVertexIdx */ 0 , m_CurrentVertexFormat , m_pCurrentVertexStride [ 0 ] ) ;
m_PrimitiveType = MATERIAL_TRIANGLES ;
Assert ( primitiveType = = MATERIAL_TRIANGLES ) ;
m_nFirstIndex = nFirstIndex ;
m_nNumIndices = nIndexCount ;
ShaderAPI ( ) - > DrawWithVertexAndIndexBuffers ( ) ;
}
void CMeshMgr : : RenderPassWithVertexAndIndexBuffers ( void )
{
// LOCK_SHADERAPI(); MESHFIXME
VPROF ( " CShaderAPIDX8::RenderPassWithVertexAndIndexBuffers " ) ;
Assert ( m_PrimitiveType ! = MATERIAL_HETEROGENOUS ) ;
// for ( int iPrim=0; iPrim < s_nPrims; iPrim++ )
{
// CPrimList *pPrim = &s_pPrims[iPrim];
// if ( pPrim->m_NumIndices == 0 )
// continue;
if ( m_PrimitiveType = = MATERIAL_POINTS )
{
// (For point lists, we don't actually fill in indices, but we treat it as
// though there are indices for the list up until here).
Assert ( 0 ) ;
// Dx9Device()->DrawPrimitive( ComputeMode( m_PrimitiveType ), s_FirstVertex, pPrim->m_NumIndices );
}
else
{
// int numPrimitives = NumPrimitives( s_NumVertices, pPrim->m_NumIndices );
// Warning( "CMeshMgr::RenderPassWithVertexAndIndexBuffers: DrawIndexedPrimitive: m_nFirstIndex = %d numPrimitives = %d\n", ( int )( ( CDynamiCIndexBufferDx8 * )m_pCurrentIndexBuffer )->m_FirstIndex, ( int )( m_nNumIndices / 3 ) );
{
VPROF ( " Dx9Device()->DrawIndexedPrimitive " ) ;
// VPROF_INCREMENT_COUNTER( "DrawIndexedPrimitive", 1 );
// VPROF_INCREMENT_COUNTER( "numPrimitives", numPrimitives );
// Dx9Device()->DrawIndexedPrimitive(
// m_Mode,
// m_FirstIndex,
// s_FirstVertex,
// s_NumVertices,
// pPrim->m_FirstIndex,
// numPrimitives );
Assert ( m_nFirstIndex > = 0 ) ;
# ifdef CHECK_INDICES
// g_pLastVertex - this is the current vertex buffer
// g_pLastColorMesh - this is the curent color mesh, if there is one.
// g_pLastIndex - this is the current index buffer.
// vertoffset : m_FirstIndex
CIndexBufferDx8 * pIndexBuffer = assert_cast < CIndexBufferDx8 * > ( m_pCurrentIndexBuffer ) ;
if ( m_PrimitiveType = = MATERIAL_TRIANGLES | | m_PrimitiveType = = MATERIAL_TRIANGLE_STRIP )
{
// FIXME: need to be able to deal with multiple stream here, but don't bother for now.
int j ;
int numVerts = m_pVertexCount [ 0 ] ;
for ( j = 0 ; j < m_nNumIndices ; j + + )
{
int index = pIndexBuffer - > GetShadowIndex ( j + m_nFirstIndex ) ;
Assert ( index > = m_pFirstVertex [ 0 ] ) ;
Assert ( index < m_pFirstVertex [ 0 ] + numVerts ) ;
}
}
# endif // CHECK_INDICES
Dx9Device ( ) - > DrawIndexedPrimitive (
ComputeMode ( m_PrimitiveType ) , // Member of the D3DPRIMITIVETYPE enumerated type, describing the type of primitive to render. D3DPT_POINTLIST is not supported with this method.
/*m_FirstIndex*/ 0 , // Offset from the start of the vertex buffer to the first vertex index. An index of 0 in the index buffer refers to this location in the vertex buffer.
/*s_FirstVertex*/ m_pFirstVertex [ 0 ] , // Minimum vertex index for vertices used during this call. This is a zero based index relative to BaseVertexIndex.
// This is zero for now since we don't do more than one batch yet with the new mesh interface.
/*s_NumVertices*/ m_pVertexCount [ 0 ] ,
// Number of vertices used during this call. The first vertex is located at index: BaseVertexIndex + MinIndex.
// This is simple the number of verts in the current vertex buffer for now since we don't do more than one batch with the new mesh interface.
m_nFirstIndex /*pPrim->m_FirstIndex*/ , // Index of the first index to use when accesssing the vertex buffer. Beginning at StartIndex to index vertices from the vertex buffer.
m_nNumIndices / 3 /*numPrimitives*/ // Number of primitives to render. The number of vertices used is a function of the primitive count and the primitive type.
) ;
Assert ( CMeshDX8 : : s_FirstVertex = = 0 ) ;
Assert ( CMeshDX8 : : s_NumVertices = = 0 ) ;
}
}
}
}
//-----------------------------------------------------------------------------
void CMeshMgr : : SetIndexStreamState ( int firstVertexIdx )
{
CIndexBufferDx8 * pIndexBuffer = assert_cast < CIndexBufferDx8 * > ( m_pCurrentIndexBuffer ) ;
IDirect3DIndexBuffer9 * pDx9Buffer = pIndexBuffer ? pIndexBuffer - > GetDx9Buffer ( ) : NULL ;
if ( g_pLastIndex | | g_pLastIndexBuffer ! = pDx9Buffer )
{
Dx9Device ( ) - > SetIndices ( pDx9Buffer ) ;
pIndexBuffer - > HandlePerFrameTextureStats ( ShaderAPI ( ) - > GetCurrentFrameCounter ( ) ) ;
g_pLastIndexBuffer = pDx9Buffer ;
SafeRelease ( & g_pLastIndex ) ;
g_LastVertexIdx = - 1 ;
}
}