Counter Strike : Global Offensive Source Code
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

//==== 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