You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
541 lines
16 KiB
541 lines
16 KiB
//==== Copyright © 1996-2008, Valve Corporation, All rights reserved. =======//
|
|
//
|
|
// Purpose:
|
|
//
|
|
//===========================================================================//
|
|
|
|
#ifndef INDEXDATA_H
|
|
#define INDEXDATA_H
|
|
|
|
#ifdef _WIN32
|
|
#pragma once
|
|
#endif
|
|
|
|
#include "tier0/platform.h"
|
|
#include "rendersystem/irendercontext.h"
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Helper class used to define index buffers
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
template < class T > class CIndexData
|
|
{
|
|
public:
|
|
CIndexData( IRenderContext* pRenderContext, HRenderBuffer hIndexBuffer );
|
|
CIndexData( IRenderContext* pRenderContext, RenderBufferType_t nType, int nIndexCount, const char *pDebugName, const char *pBudgetGroup );
|
|
|
|
// This constructor is meant to be used with instance rendering.
|
|
// Passing in either 0 or INT_MAX here means the client code
|
|
// doesn't know how many instances will be rendered.
|
|
CIndexData( IRenderContext* pRenderContext, RenderBufferType_t nType, int nIndexCount, int nMaxInstanceCount, const char *pDebugName, const char *pBudgetGroup );
|
|
~CIndexData();
|
|
|
|
// Begins, ends modification of the index buffer (returns true if the lock succeeded)
|
|
// A lock may not succeed if there isn't enough room
|
|
// Passing in 0 locks the entire buffer
|
|
bool Lock( int nMaxIndexCount = 0 );
|
|
void Unlock();
|
|
|
|
// returns the number of indices
|
|
int IndexCount() const;
|
|
|
|
// returns the total # of indices in the entire buffer
|
|
int GetBufferIndexCount() const;
|
|
|
|
// Used to define the indices (only used if you aren't using primitives)
|
|
void Index( T nIndex );
|
|
|
|
// NOTE: This version is the one you really want to achieve write-combining;
|
|
// Write combining only works if you write in 4 bytes chunks.
|
|
void Index2( T nIndex1, T nIndex2 );
|
|
|
|
/*
|
|
void FastTriangle( T nStartVert );
|
|
void FastQuad( T nStartVert );
|
|
void FastPolygon( T nStartVert, int nEdgeCount );
|
|
void FastPolygonList( T nStartVert, int *pVertexCount, int polygonCount );
|
|
void FastIndexList( const T *pIndexList, T nStartVert, int indexCount );
|
|
*/
|
|
|
|
// Call this to detach ownership of the vertex buffer. Caller is responsible
|
|
// for deleting it now
|
|
HRenderBuffer TakeOwnership();
|
|
|
|
protected:
|
|
enum
|
|
{
|
|
BUFFER_OFFSET_UNINITIALIZED = 0xFFFFFFFF
|
|
};
|
|
|
|
void Init( IRenderContext* pRenderContext, RenderBufferType_t nType, int nIndexCount, int nMaxInstanceCount, const char *pDebugName, const char *pBudgetGroup );
|
|
void Release();
|
|
|
|
// Pointer to the memory we're writing
|
|
T* m_pMemory;
|
|
|
|
// The current index
|
|
int m_nIndexCount;
|
|
|
|
// Amount to increase the index count each time (0 if there was a lock failure)
|
|
int m_nIndexIncrement;
|
|
|
|
// The mesh we're modifying
|
|
IRenderContext* m_pRenderContext;
|
|
HRenderBuffer m_hIndexBuffer;
|
|
|
|
// Max number of indices
|
|
int m_nMaxIndexCount;
|
|
int m_nBufferIndexCount : 31;
|
|
int m_bShouldDeallocate : 1;
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Inline methods related to CIndexData
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Constructor
|
|
//-----------------------------------------------------------------------------
|
|
template< class T >
|
|
inline CIndexData<T>::CIndexData( IRenderContext* pRenderContext, HRenderBuffer hIndexBuffer )
|
|
{
|
|
m_pRenderContext = pRenderContext;
|
|
m_hIndexBuffer = hIndexBuffer;
|
|
m_bShouldDeallocate = false;
|
|
|
|
BufferDesc_t desc;
|
|
pRenderContext->GetDevice()->GetIndexBufferDesc( hIndexBuffer, &desc );
|
|
m_nBufferIndexCount = desc.m_nElementCount;
|
|
|
|
#ifdef _DEBUG
|
|
m_nIndexCount = 0;
|
|
m_nMaxIndexCount = 0;
|
|
m_pMemory = NULL;
|
|
m_nIndexIncrement = 0;
|
|
#endif
|
|
}
|
|
|
|
template< class T >
|
|
inline CIndexData<T>::CIndexData( IRenderContext* pRenderContext, RenderBufferType_t nType, int nIndexCount, const char *pDebugName, const char *pBudgetGroup )
|
|
{
|
|
Init( pRenderContext, nType, nIndexCount, 0, pDebugName, pBudgetGroup );
|
|
}
|
|
|
|
template< class T >
|
|
inline CIndexData<T>::CIndexData( IRenderContext* pRenderContext, RenderBufferType_t nType, int nIndexCount, int nMaxInstanceCount, const char *pDebugName, const char *pBudgetGroup )
|
|
{
|
|
if ( nMaxInstanceCount == 0 )
|
|
{
|
|
nMaxInstanceCount = INT_MAX;
|
|
}
|
|
Init( pRenderContext, nType, nIndexCount, nMaxInstanceCount, pDebugName, pBudgetGroup );
|
|
}
|
|
|
|
template< class T >
|
|
inline void CIndexData<T>::Init( IRenderContext* pRenderContext, RenderBufferType_t nType,
|
|
int nIndexCount, int nMaxInstanceCount, const char *pDebugName, const char *pBudgetGroup )
|
|
{
|
|
m_pRenderContext = pRenderContext;
|
|
|
|
BufferDesc_t indexDesc;
|
|
indexDesc.m_nElementSizeInBytes = sizeof(T);
|
|
indexDesc.m_nElementCount = nIndexCount;
|
|
indexDesc.m_pDebugName = pDebugName;
|
|
indexDesc.m_pBudgetGroupName = pBudgetGroup;
|
|
m_hIndexBuffer = pRenderContext->GetDevice()->CreateIndexBuffer( nType, indexDesc, nMaxInstanceCount );
|
|
m_nBufferIndexCount = nIndexCount;
|
|
m_bShouldDeallocate = true;
|
|
|
|
ResourceAddRef( m_hIndexBuffer );
|
|
|
|
#ifdef _DEBUG
|
|
m_nIndexCount = 0;
|
|
m_nMaxIndexCount = 0;
|
|
m_pMemory = NULL;
|
|
m_nIndexIncrement = 0;
|
|
#endif
|
|
}
|
|
|
|
template< class T >
|
|
inline CIndexData<T>::~CIndexData()
|
|
{
|
|
// If this assertion fails, you forgot to unlock
|
|
Assert( !m_pMemory );
|
|
Release();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Release
|
|
//-----------------------------------------------------------------------------
|
|
template< class T >
|
|
void CIndexData<T>::Release()
|
|
{
|
|
if ( m_bShouldDeallocate && ( m_hIndexBuffer != RENDER_BUFFER_HANDLE_INVALID ) )
|
|
{
|
|
ResourceRelease( m_hIndexBuffer );
|
|
m_pRenderContext->GetDevice()->DestroyIndexBuffer( m_hIndexBuffer );
|
|
m_hIndexBuffer = RENDER_BUFFER_HANDLE_INVALID;
|
|
m_bShouldDeallocate = false;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Call this to take ownership of the vertex buffer
|
|
//-----------------------------------------------------------------------------
|
|
template< class T >
|
|
inline HRenderBuffer CIndexData<T>::TakeOwnership()
|
|
{
|
|
if ( m_bShouldDeallocate )
|
|
{
|
|
ResourceRelease( m_hIndexBuffer );
|
|
}
|
|
m_bShouldDeallocate = false;
|
|
return m_hIndexBuffer;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Returns the buffer vertex count
|
|
//-----------------------------------------------------------------------------
|
|
template< class T >
|
|
inline int CIndexData<T>::GetBufferIndexCount() const
|
|
{
|
|
return m_nBufferIndexCount;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Begins, ends modification of the index buffer
|
|
//-----------------------------------------------------------------------------
|
|
template< class T >
|
|
inline bool CIndexData<T>::Lock( int nMaxIndexCount )
|
|
{
|
|
if ( nMaxIndexCount == 0 )
|
|
{
|
|
nMaxIndexCount = m_nBufferIndexCount;
|
|
}
|
|
|
|
// Lock the index buffer
|
|
LockDesc_t desc;
|
|
bool bOk = m_pRenderContext->LockIndexBuffer( m_hIndexBuffer, nMaxIndexCount * sizeof(T), &desc );
|
|
m_nIndexIncrement = bOk ? 1 : 0;
|
|
m_nMaxIndexCount = nMaxIndexCount * m_nIndexIncrement;
|
|
m_nIndexCount = 0;
|
|
m_pMemory = (T*)desc.m_pMemory;
|
|
return bOk;
|
|
}
|
|
|
|
template< class T >
|
|
inline void CIndexData<T>::Unlock()
|
|
{
|
|
LockDesc_t desc;
|
|
desc.m_pMemory = m_pMemory;
|
|
m_pRenderContext->UnlockIndexBuffer( m_hIndexBuffer, m_nIndexCount * sizeof(T), &desc );
|
|
|
|
#ifdef _DEBUG
|
|
m_nIndexCount = 0;
|
|
m_nMaxIndexCount = 0;
|
|
m_pMemory = 0;
|
|
m_nIndexIncrement = 0;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
//-----------------------------------------------------------------------------
|
|
// Binds this index buffer
|
|
//-----------------------------------------------------------------------------
|
|
inline void CIndexData<T>::Bind( IMatRenderContext *pContext )
|
|
{
|
|
pContext->BindIndexBuffer( m_pIndexBuffer, 0 );
|
|
}
|
|
*/
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// returns the number of indices
|
|
//-----------------------------------------------------------------------------
|
|
template< class T >
|
|
inline int CIndexData<T>::IndexCount() const
|
|
{
|
|
return m_nIndexCount;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Used to write data into the index buffer
|
|
//-----------------------------------------------------------------------------
|
|
template< class T >
|
|
inline void CIndexData<T>::Index( T nIndex )
|
|
{
|
|
// FIXME: Should we prevent use of this with T = uint16? (write-combining)
|
|
Assert( m_pMemory );
|
|
Assert( ( m_nIndexIncrement == 0 ) || ( m_nIndexCount < m_nMaxIndexCount ) );
|
|
m_pMemory[m_nIndexCount] = nIndex;
|
|
m_nIndexCount += m_nIndexIncrement;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// NOTE: This version is the one you really want to achieve write-combining;
|
|
// Write combining only works if you write in 4 bytes chunks.
|
|
//-----------------------------------------------------------------------------
|
|
template< >
|
|
inline void CIndexData<uint16>::Index2( uint16 nIndex1, uint16 nIndex2 )
|
|
{
|
|
Assert( m_pMemory );
|
|
Assert( ( m_nIndexIncrement == 0 ) || ( m_nIndexCount < m_nMaxIndexCount - 1 ) );
|
|
|
|
#ifndef _X360
|
|
uint32 nIndices = ( (uint32)nIndex1 ) | ( ( (uint32)nIndex2 ) << 16 );
|
|
#else
|
|
uint32 nIndices = ( (uint32)nIndex2 ) | ( ( (uint32)nIndex1 ) << 16 );
|
|
#endif
|
|
|
|
*(uint32*)( &m_pMemory[m_nIndexCount] ) = nIndices;
|
|
m_nIndexCount += m_nIndexIncrement + m_nIndexIncrement;
|
|
}
|
|
|
|
template< >
|
|
inline void CIndexData<uint32>::Index2( uint32 nIndex1, uint32 nIndex2 )
|
|
{
|
|
Assert( m_pMemory );
|
|
Assert( ( m_nIndexIncrement == 0 ) || ( m_nIndexCount < m_nMaxIndexCount - 1 ) );
|
|
|
|
m_pMemory[m_nIndexCount] = nIndex1;
|
|
m_pMemory[m_nIndexCount+1] = nIndex2;
|
|
m_nIndexCount += m_nIndexIncrement + m_nIndexIncrement;
|
|
}
|
|
|
|
template< class T >
|
|
inline void CIndexData<T>::Index2( T nIndex1, T nIndex2 )
|
|
{
|
|
COMPILE_TIME_ASSERT( 0 );
|
|
}
|
|
|
|
|
|
#if 0
|
|
template< class T >
|
|
inline void CIndexData<T>::FastTriangle( int startVert )
|
|
{
|
|
startVert += m_nIndexOffset;
|
|
m_pIndices[m_nCurrentIndex+0] = startVert;
|
|
m_pIndices[m_nCurrentIndex+1] = startVert + 1;
|
|
m_pIndices[m_nCurrentIndex+2] = startVert + 2;
|
|
|
|
AdvanceIndices(3);
|
|
}
|
|
|
|
template< class T >
|
|
inline void CIndexData<T>::FastQuad( int startVert )
|
|
{
|
|
startVert += m_nIndexOffset;
|
|
m_pIndices[m_nCurrentIndex+0] = startVert;
|
|
m_pIndices[m_nCurrentIndex+1] = startVert + 1;
|
|
m_pIndices[m_nCurrentIndex+2] = startVert + 2;
|
|
m_pIndices[m_nCurrentIndex+3] = startVert;
|
|
m_pIndices[m_nCurrentIndex+4] = startVert + 2;
|
|
m_pIndices[m_nCurrentIndex+5] = startVert + 3;
|
|
AdvanceIndices(6);
|
|
}
|
|
|
|
template< class T >
|
|
inline void CIndexData<T>::FastPolygon( int startVert, int triangleCount )
|
|
{
|
|
unsigned short *pIndex = &m_pIndices[m_nCurrentIndex];
|
|
startVert += m_nIndexOffset;
|
|
if ( !IsX360() )
|
|
{
|
|
// NOTE: IndexSize is 1 or 0 (0 for alt-tab)
|
|
// This prevents us from writing into bogus memory
|
|
Assert( m_nIndexSize == 0 || m_nIndexSize == 1 );
|
|
triangleCount *= m_nIndexSize;
|
|
}
|
|
for ( int v = 0; v < triangleCount; ++v )
|
|
{
|
|
*pIndex++ = startVert;
|
|
*pIndex++ = startVert + v + 1;
|
|
*pIndex++ = startVert + v + 2;
|
|
}
|
|
AdvanceIndices(triangleCount*3);
|
|
}
|
|
|
|
template< class T >
|
|
inline void CIndexData<T>::FastPolygonList( int startVert, int *pVertexCount, int polygonCount )
|
|
{
|
|
unsigned short *pIndex = &m_pIndices[m_nCurrentIndex];
|
|
startVert += m_nIndexOffset;
|
|
int indexOut = 0;
|
|
|
|
if ( !IsX360() )
|
|
{
|
|
// NOTE: IndexSize is 1 or 0 (0 for alt-tab)
|
|
// This prevents us from writing into bogus memory
|
|
Assert( m_nIndexSize == 0 || m_nIndexSize == 1 );
|
|
polygonCount *= m_nIndexSize;
|
|
}
|
|
|
|
for ( int i = 0; i < polygonCount; i++ )
|
|
{
|
|
int vertexCount = pVertexCount[i];
|
|
int triangleCount = vertexCount-2;
|
|
for ( int v = 0; v < triangleCount; ++v )
|
|
{
|
|
*pIndex++ = startVert;
|
|
*pIndex++ = startVert + v + 1;
|
|
*pIndex++ = startVert + v + 2;
|
|
}
|
|
startVert += vertexCount;
|
|
indexOut += triangleCount * 3;
|
|
}
|
|
AdvanceIndices(indexOut);
|
|
}
|
|
|
|
template< class T >
|
|
inline void CIndexData<T>::FastIndexList( const unsigned short *pIndexList, int startVert, int indexCount )
|
|
{
|
|
unsigned short *pIndexOut = &m_pIndices[m_nCurrentIndex];
|
|
startVert += m_nIndexOffset;
|
|
if ( !IsX360() )
|
|
{
|
|
// NOTE: IndexSize is 1 or 0 (0 for alt-tab)
|
|
// This prevents us from writing into bogus memory
|
|
Assert( m_nIndexSize == 0 || m_nIndexSize == 1 );
|
|
indexCount *= m_nIndexSize;
|
|
}
|
|
for ( int i = 0; i < indexCount; ++i )
|
|
{
|
|
pIndexOut[i] = startVert + pIndexList[i];
|
|
}
|
|
AdvanceIndices(indexCount);
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Dynamic index field creation
|
|
// NOTE: Draw call must occur prior to destruction of this class!
|
|
//-----------------------------------------------------------------------------
|
|
template< class T > class CDynamicIndexData : public CIndexData< T >
|
|
{
|
|
typedef CIndexData< T > BaseClass;
|
|
|
|
public:
|
|
CDynamicIndexData( IRenderContext* pRenderContext, int nIndexCount, const char *pDebugName, const char *pBudgetGroup );
|
|
|
|
// This constructor is meant to be used with instance rendering.
|
|
// Passing in either 0 or INT_MAX here means the client code
|
|
// doesn't know how many instances will be rendered.
|
|
CDynamicIndexData( IRenderContext* pRenderContext, int nIndexCount, int nMaxInstanceCount, const char *pDebugName, const char *pBudgetGroup );
|
|
~CDynamicIndexData();
|
|
void Release();
|
|
|
|
// Begins, ends modification of the vertex buffer (returns true if the lock succeeded)
|
|
// A lock may not succeed if there isn't enough room
|
|
bool Lock( );
|
|
|
|
// Binds the vb to a particular slot using a particular offset
|
|
void Bind( int nOffset );
|
|
|
|
private:
|
|
void Init( IRenderContext* pRenderContext, int nIndexCount, int nMaxInstanceCount, const char *pDebugName, const char *pBudgetGroup );
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Inline methods related to CDynamicIndexData
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Constructor
|
|
//-----------------------------------------------------------------------------
|
|
template< class T >
|
|
inline CDynamicIndexData<T>::CDynamicIndexData( IRenderContext* pRenderContext,
|
|
int nIndexCount, const char *pDebugName, const char *pBudgetGroup ) :
|
|
BaseClass( pRenderContext, RENDER_BUFFER_HANDLE_INVALID )
|
|
{
|
|
Init( pRenderContext, nIndexCount, 0, pDebugName, pBudgetGroup );
|
|
}
|
|
|
|
template< class T >
|
|
inline CDynamicIndexData<T>::CDynamicIndexData( IRenderContext* pRenderContext,
|
|
int nIndexCount, int nMaxInstanceCount, const char *pDebugName, const char *pBudgetGroup ) :
|
|
BaseClass( pRenderContext, RENDER_BUFFER_HANDLE_INVALID )
|
|
{
|
|
if ( nMaxInstanceCount == 0 )
|
|
{
|
|
nMaxInstanceCount = INT_MAX;
|
|
}
|
|
Init( pRenderContext, nIndexCount, nMaxInstanceCount, pDebugName, pBudgetGroup );
|
|
}
|
|
|
|
template< class T >
|
|
inline void CDynamicIndexData<T>::Init( IRenderContext* pRenderContext,
|
|
int nIndexCount, int nMaxInstanceCount, const char *pDebugName, const char *pBudgetGroup )
|
|
{
|
|
BufferDesc_t indexDesc;
|
|
indexDesc.m_nElementSizeInBytes = sizeof(T);
|
|
indexDesc.m_nElementCount = nIndexCount;
|
|
indexDesc.m_pDebugName = pDebugName;
|
|
indexDesc.m_pBudgetGroupName = pBudgetGroup;
|
|
this->m_hIndexBuffer = pRenderContext->CreateDynamicIndexBuffer( indexDesc, nMaxInstanceCount );
|
|
this->m_nBufferIndexCount = nIndexCount;
|
|
|
|
ResourceAddRef( m_hIndexBuffer );
|
|
}
|
|
|
|
template< class T >
|
|
inline CDynamicIndexData<T>::~CDynamicIndexData()
|
|
{
|
|
Release();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Release
|
|
//-----------------------------------------------------------------------------
|
|
template< class T >
|
|
void CDynamicIndexData<T>::Release()
|
|
{
|
|
if ( this->m_hIndexBuffer != RENDER_BUFFER_HANDLE_INVALID )
|
|
{
|
|
this->m_pRenderContext->DestroyDynamicIndexBuffer( this->m_hIndexBuffer );
|
|
ResourceRelease( m_hIndexBuffer );
|
|
this->m_hIndexBuffer = RENDER_BUFFER_HANDLE_INVALID;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Begins, ends modification of the buffer
|
|
//-----------------------------------------------------------------------------
|
|
template< class T >
|
|
inline bool CDynamicIndexData<T>::Lock( )
|
|
{
|
|
Assert( this->m_hIndexBuffer != RENDER_BUFFER_HANDLE_INVALID );
|
|
return BaseClass::Lock( );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Binds the ib to a particular stream using a particular offset
|
|
//-----------------------------------------------------------------------------
|
|
template< class T >
|
|
inline void CDynamicIndexData<T>::Bind( int nOffset )
|
|
{
|
|
this->m_pRenderContext->BindIndexBuffer( this->m_hIndexBuffer, nOffset );
|
|
}
|
|
|
|
|
|
|
|
#endif // INDEXDATA_H
|