|
|
|
/*==LICENSE==*
|
|
|
|
|
|
|
|
CyanWorlds.com Engine - MMOG client, server and tools
|
|
|
|
Copyright (C) 2011 Cyan Worlds, Inc.
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
Additional permissions under GNU GPL version 3 section 7
|
|
|
|
|
|
|
|
If you modify this Program, or any covered work, by linking or
|
|
|
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
|
|
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
|
|
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
|
|
|
(or a modified version of those libraries),
|
|
|
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
|
|
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
|
|
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
|
|
|
licensors of this Program grant you additional
|
|
|
|
permission to convey the resulting work. Corresponding Source for a
|
|
|
|
non-source form of such a combination shall include the source code for
|
|
|
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
|
|
|
work.
|
|
|
|
|
|
|
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
|
|
|
or by snail mail at:
|
|
|
|
Cyan Worlds, Inc.
|
|
|
|
14617 N Newport Hwy
|
|
|
|
Mead, WA 99021
|
|
|
|
|
|
|
|
*==LICENSE==*/
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// //
|
|
|
|
// plGBufferGroup Class Functions //
|
|
|
|
// Cyan, Inc. //
|
|
|
|
// //
|
|
|
|
//// Version History //////////////////////////////////////////////////////////
|
|
|
|
// //
|
|
|
|
// 2.21.2001 mcn - Created. //
|
|
|
|
// //
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#include "hsWindows.h"
|
|
|
|
#include "HeadSpin.h"
|
|
|
|
#include "plGBufferGroup.h"
|
|
|
|
#include "hsStream.h"
|
|
|
|
|
|
|
|
#include "plSurface/hsGMaterial.h"
|
|
|
|
#include "plDrawable/plGeometrySpan.h"
|
|
|
|
#include "plPipeline.h"
|
|
|
|
#include "hsGDeviceRef.h"
|
|
|
|
#include "plProfile.h"
|
|
|
|
|
|
|
|
#include "plVertCoder.h"
|
|
|
|
|
|
|
|
plProfile_CreateMemCounter("Buf Group Vertices", "Memory", MemBufGrpVertex);
|
|
|
|
plProfile_CreateMemCounter("Buf Group Indices", "Memory", MemBufGrpIndex);
|
|
|
|
plProfile_CreateTimer("Refill Vertex", "Draw", DrawRefillVertex);
|
|
|
|
plProfile_CreateTimer("Refill Index", "Draw", DrawRefillIndex);
|
|
|
|
|
|
|
|
const UInt32 plGBufferGroup::kMaxNumVertsPerBuffer = 32000;
|
|
|
|
const UInt32 plGBufferGroup::kMaxNumIndicesPerBuffer = 32000;
|
|
|
|
|
|
|
|
|
|
|
|
//// plGBufferTriangle Read and Write /////////////////////////////////////////
|
|
|
|
|
|
|
|
void plGBufferTriangle::Read( hsStream *s )
|
|
|
|
{
|
|
|
|
fIndex1 = s->ReadSwap16();
|
|
|
|
fIndex2 = s->ReadSwap16();
|
|
|
|
fIndex3 = s->ReadSwap16();
|
|
|
|
fSpanIndex = s->ReadSwap16();
|
|
|
|
fCenter.Read( s );
|
|
|
|
}
|
|
|
|
|
|
|
|
void plGBufferTriangle::Write( hsStream *s )
|
|
|
|
{
|
|
|
|
s->WriteSwap16( fIndex1 );
|
|
|
|
s->WriteSwap16( fIndex2 );
|
|
|
|
s->WriteSwap16( fIndex3 );
|
|
|
|
s->WriteSwap16( fSpanIndex );
|
|
|
|
fCenter.Write( s );
|
|
|
|
}
|
|
|
|
|
|
|
|
//// plGBufferCell Read/Write /////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void plGBufferCell::Read( hsStream *s )
|
|
|
|
{
|
|
|
|
fVtxStart = s->ReadSwap32();
|
|
|
|
fColorStart = s->ReadSwap32();
|
|
|
|
fLength = s->ReadSwap32();
|
|
|
|
}
|
|
|
|
|
|
|
|
void plGBufferCell::Write( hsStream *s )
|
|
|
|
{
|
|
|
|
s->WriteSwap32( fVtxStart );
|
|
|
|
s->WriteSwap32( fColorStart );
|
|
|
|
s->WriteSwap32( fLength );
|
|
|
|
}
|
|
|
|
|
|
|
|
//// Constructor //////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
plGBufferGroup::plGBufferGroup( UInt8 format, hsBool vertsVolatile, hsBool idxVolatile, int LOD )
|
|
|
|
{
|
|
|
|
fVertBuffStorage.Reset();
|
|
|
|
fIdxBuffStorage.Reset();
|
|
|
|
fColorBuffStorage.Reset();
|
|
|
|
fVertexBufferRefs.Reset();
|
|
|
|
fIndexBufferRefs.Reset();
|
|
|
|
fCells.Reset();
|
|
|
|
fNumVerts = fNumIndices = 0;
|
|
|
|
|
|
|
|
fFormat = format;
|
|
|
|
fStride = ICalcVertexSize( fLiteStride );
|
|
|
|
fVertsVolatile = vertsVolatile;
|
|
|
|
fIdxVolatile = idxVolatile;
|
|
|
|
fLOD = LOD;
|
|
|
|
}
|
|
|
|
|
|
|
|
//// Destructor ///////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
plGBufferGroup::~plGBufferGroup()
|
|
|
|
{
|
|
|
|
UInt32 i;
|
|
|
|
|
|
|
|
CleanUp();
|
|
|
|
|
|
|
|
for( i = 0; i < fVertexBufferRefs.GetCount(); i++ )
|
|
|
|
hsRefCnt_SafeUnRef( fVertexBufferRefs[ i ] );
|
|
|
|
|
|
|
|
for( i = 0; i < fIndexBufferRefs.GetCount(); i++ )
|
|
|
|
hsRefCnt_SafeUnRef( fIndexBufferRefs[ i ] );
|
|
|
|
|
|
|
|
fVertexBufferRefs.Reset();
|
|
|
|
fIndexBufferRefs.Reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
void plGBufferGroup::DirtyVertexBuffer(int i)
|
|
|
|
{
|
|
|
|
if( (i < fVertexBufferRefs.GetCount()) && fVertexBufferRefs[i] )
|
|
|
|
fVertexBufferRefs[i]->SetDirty(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void plGBufferGroup::DirtyIndexBuffer(int i)
|
|
|
|
{
|
|
|
|
if( (i < fIndexBufferRefs.GetCount()) && fIndexBufferRefs[i] )
|
|
|
|
fIndexBufferRefs[i]->SetDirty(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//// TidyUp ///////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void plGBufferGroup::TidyUp( void )
|
|
|
|
{
|
|
|
|
/* if( fVertBuffStorage.GetCount() == 0 && fNumVerts > 0 )
|
|
|
|
return; // Already tidy'd!
|
|
|
|
|
|
|
|
// IConvertToStorage();
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
void plGBufferGroup::PurgeVertBuffer(UInt32 idx)
|
|
|
|
{
|
|
|
|
if( AreVertsVolatile() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
//#define MF_TOSSER
|
|
|
|
#ifdef MF_TOSSER
|
|
|
|
plProfile_DelMem(MemBufGrpVertex, fVertBuffSizes[idx]);
|
|
|
|
delete [] fVertBuffStorage[idx];
|
|
|
|
fVertBuffStorage[idx] = nil;
|
|
|
|
|
|
|
|
plProfile_DelMem(MemBufGrpVertex, fColorBuffCounts[idx] * sizeof(plGBufferColor));
|
|
|
|
delete [] fColorBuffStorage[idx];
|
|
|
|
fColorBuffStorage[idx] = nil;
|
|
|
|
|
|
|
|
delete fCells[idx];
|
|
|
|
fCells[idx] = nil;
|
|
|
|
|
|
|
|
#endif // MF_TOSSER
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void plGBufferGroup::PurgeIndexBuffer(UInt32 idx)
|
|
|
|
{
|
|
|
|
if( AreIdxVolatile() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//// CleanUp //////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void plGBufferGroup::CleanUp( void )
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
|
|
// Clean up the storage
|
|
|
|
for( i = 0; i < fVertBuffStorage.GetCount(); i++ )
|
|
|
|
{
|
|
|
|
plProfile_DelMem(MemBufGrpVertex, fVertBuffSizes[i]);
|
|
|
|
delete [] fVertBuffStorage[ i ];
|
|
|
|
}
|
|
|
|
for( i = 0; i < fIdxBuffStorage.GetCount(); i++ )
|
|
|
|
{
|
|
|
|
plProfile_DelMem(MemBufGrpIndex, fIdxBuffCounts[i] * sizeof(UInt16));
|
|
|
|
delete [] fIdxBuffStorage[ i ];
|
|
|
|
}
|
|
|
|
for( i = 0; i < fColorBuffStorage.GetCount(); i++ )
|
|
|
|
{
|
|
|
|
plProfile_DelMem(MemBufGrpVertex, fColorBuffCounts[i] * sizeof(plGBufferColor));
|
|
|
|
delete [] fColorBuffStorage[ i ];
|
|
|
|
}
|
|
|
|
|
|
|
|
for( i = 0; i < fCells.GetCount(); i++ )
|
|
|
|
delete fCells[ i ];
|
|
|
|
|
|
|
|
fVertBuffStorage.Reset();
|
|
|
|
fVertBuffSizes.Reset();
|
|
|
|
fVertBuffStarts.Reset();
|
|
|
|
fVertBuffEnds.Reset();
|
|
|
|
fIdxBuffStorage.Reset();
|
|
|
|
fIdxBuffCounts.Reset();
|
|
|
|
fIdxBuffStarts.Reset();
|
|
|
|
fIdxBuffEnds.Reset();
|
|
|
|
fColorBuffStorage.Reset();
|
|
|
|
fColorBuffCounts.Reset();
|
|
|
|
|
|
|
|
fCells.Reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
//// SetVertexBufferRef ///////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void plGBufferGroup::SetVertexBufferRef( UInt32 index, hsGDeviceRef *vb )
|
|
|
|
{
|
|
|
|
hsAssert( index < fVertexBufferRefs.GetCount() + 1, "Vertex buffers must be assigned linearly!" );
|
|
|
|
|
|
|
|
if( (int)index > (int)fVertexBufferRefs.GetCount() - 1 )
|
|
|
|
{
|
|
|
|
fVertexBufferRefs.Append( vb );
|
|
|
|
hsRefCnt_SafeRef( vb );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hsRefCnt_SafeAssign( fVertexBufferRefs[ index ], vb );
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//// SetIndexBufferRef ////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void plGBufferGroup::SetIndexBufferRef( UInt32 index, hsGDeviceRef *ib )
|
|
|
|
{
|
|
|
|
hsAssert( index < fIndexBufferRefs.GetCount() + 1, "Index buffers must be assigned linearly!" );
|
|
|
|
|
|
|
|
if( (int)index > (int)fIndexBufferRefs.GetCount() - 1 )
|
|
|
|
{
|
|
|
|
fIndexBufferRefs.Append( ib );
|
|
|
|
hsRefCnt_SafeRef( ib );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hsRefCnt_SafeAssign( fIndexBufferRefs[ index ], ib );
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//// PrepForRendering /////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void plGBufferGroup::PrepForRendering( plPipeline *pipe, hsBool adjustForNvidiaLighting )
|
|
|
|
{
|
|
|
|
ISendStorageToBuffers( pipe, adjustForNvidiaLighting );
|
|
|
|
// The following line was taken out so we'd keep our data around, allowing
|
|
|
|
// us to rebuild the buffer if necessary on the fly
|
|
|
|
// CleanUp();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
hsGDeviceRef* plGBufferGroup::GetVertexBufferRef(UInt32 i)
|
|
|
|
{
|
|
|
|
if( i >= fVertexBufferRefs.GetCount() )
|
|
|
|
fVertexBufferRefs.ExpandAndZero(i+1);
|
|
|
|
|
|
|
|
return fVertexBufferRefs[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
hsGDeviceRef* plGBufferGroup::GetIndexBufferRef(UInt32 i)
|
|
|
|
{
|
|
|
|
if( i >= fIndexBufferRefs.GetCount() )
|
|
|
|
fIndexBufferRefs.ExpandAndZero(i+1);
|
|
|
|
|
|
|
|
return fIndexBufferRefs[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
//// ISendStorageToBuffers ////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void plGBufferGroup::ISendStorageToBuffers( plPipeline *pipe, hsBool adjustForNvidiaLighting )
|
|
|
|
{
|
|
|
|
plProfile_BeginTiming(DrawRefillVertex);
|
|
|
|
|
|
|
|
/// Creating or refreshing?
|
|
|
|
int i;
|
|
|
|
for( i = 0; i < fVertBuffStorage.GetCount(); i++ )
|
|
|
|
{
|
|
|
|
pipe->CheckVertexBufferRef(this, i);
|
|
|
|
}
|
|
|
|
plProfile_EndTiming(DrawRefillVertex);
|
|
|
|
|
|
|
|
plProfile_BeginTiming(DrawRefillIndex);
|
|
|
|
|
|
|
|
for( i = 0; i < fIdxBuffStorage.GetCount(); i++ )
|
|
|
|
{
|
|
|
|
pipe->CheckIndexBufferRef(this, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
plProfile_EndTiming(DrawRefillIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//// ICalcVertexSize //////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
UInt8 plGBufferGroup::ICalcVertexSize( UInt8 &liteStride )
|
|
|
|
{
|
|
|
|
UInt8 size;
|
|
|
|
|
|
|
|
|
|
|
|
size = sizeof( float ) * ( 3 + 3 ); // pos + normal
|
|
|
|
size += sizeof( float ) * 3 * GetNumUVs();
|
|
|
|
|
|
|
|
switch( fFormat & kSkinWeightMask )
|
|
|
|
{
|
|
|
|
case kSkinNoWeights: fNumSkinWeights = 0; break;
|
|
|
|
case kSkin1Weight: fNumSkinWeights = 1; break;
|
|
|
|
case kSkin2Weights: fNumSkinWeights = 2; break;
|
|
|
|
case kSkin3Weights: fNumSkinWeights = 3; break;
|
|
|
|
default: hsAssert( false, "Bad weight count in ICalcVertexSize()" );
|
|
|
|
}
|
|
|
|
if( fNumSkinWeights )
|
|
|
|
{
|
|
|
|
size += sizeof( float ) * fNumSkinWeights;
|
|
|
|
if( fFormat & kSkinIndices )
|
|
|
|
size += sizeof( UInt32 );
|
|
|
|
}
|
|
|
|
|
|
|
|
liteStride = size;
|
|
|
|
size += sizeof( DWORD ) * 2; // diffuse + specular
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
//// I/O Functions ////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void plGBufferGroup::Read( hsStream *s )
|
|
|
|
{
|
|
|
|
UInt32 totalDynSize, i, count, temp = 0, j;
|
|
|
|
UInt8 *vData;
|
|
|
|
UInt16 *iData;
|
|
|
|
plGBufferColor *cData;
|
|
|
|
|
|
|
|
|
|
|
|
s->ReadSwap( &fFormat );
|
|
|
|
totalDynSize = s->ReadSwap32();
|
|
|
|
fStride = ICalcVertexSize( fLiteStride );
|
|
|
|
|
|
|
|
fVertBuffSizes.Reset();
|
|
|
|
fVertBuffStarts.Reset();
|
|
|
|
fVertBuffEnds.Reset();
|
|
|
|
fColorBuffCounts.Reset();
|
|
|
|
fIdxBuffCounts.Reset();
|
|
|
|
fIdxBuffStarts.Reset();
|
|
|
|
fIdxBuffEnds.Reset();
|
|
|
|
fVertBuffStorage.Reset();
|
|
|
|
fIdxBuffStorage.Reset();
|
|
|
|
|
|
|
|
plVertCoder coder;
|
|
|
|
/// Create buffers and read in as we go
|
|
|
|
count = s->ReadSwap32();
|
|
|
|
for( i = 0; i < count; i++ )
|
|
|
|
{
|
|
|
|
if( fFormat & kEncoded )
|
|
|
|
{
|
|
|
|
const UInt16 numVerts = s->ReadSwap16();
|
|
|
|
const UInt32 size = numVerts * fStride;
|
|
|
|
|
|
|
|
fVertBuffSizes.Append(size);
|
|
|
|
fVertBuffStarts.Append(0);
|
|
|
|
fVertBuffEnds.Append(-1);
|
|
|
|
|
|
|
|
vData = TRACKED_NEW UInt8[size];
|
|
|
|
fVertBuffStorage.Append( vData );
|
|
|
|
plProfile_NewMem(MemBufGrpVertex, temp);
|
|
|
|
|
|
|
|
coder.Read(s, vData, fFormat, fStride, numVerts);
|
|
|
|
|
|
|
|
fColorBuffCounts.Append(0);
|
|
|
|
fColorBuffStorage.Append(nil);
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
temp = s->ReadSwap32();
|
|
|
|
|
|
|
|
fVertBuffSizes.Append( temp );
|
|
|
|
fVertBuffStarts.Append(0);
|
|
|
|
fVertBuffEnds.Append(-1);
|
|
|
|
|
|
|
|
vData = TRACKED_NEW UInt8[ temp ];
|
|
|
|
hsAssert( vData != nil, "Not enough memory to read in vertices" );
|
|
|
|
s->Read( temp, (void *)vData );
|
|
|
|
fVertBuffStorage.Append( vData );
|
|
|
|
plProfile_NewMem(MemBufGrpVertex, temp);
|
|
|
|
|
|
|
|
temp = s->ReadSwap32();
|
|
|
|
fColorBuffCounts.Append( temp );
|
|
|
|
|
|
|
|
if( temp > 0 )
|
|
|
|
{
|
|
|
|
cData = TRACKED_NEW plGBufferColor[ temp ];
|
|
|
|
s->Read( temp * sizeof( plGBufferColor ), (void *)cData );
|
|
|
|
plProfile_NewMem(MemBufGrpVertex, temp * sizeof(plGBufferColor));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
cData = nil;
|
|
|
|
|
|
|
|
fColorBuffStorage.Append( cData );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
count = s->ReadSwap32();
|
|
|
|
for( i = 0; i < count; i++ )
|
|
|
|
{
|
|
|
|
temp = s->ReadSwap32();
|
|
|
|
fIdxBuffCounts.Append( temp );
|
|
|
|
fIdxBuffStarts.Append(0);
|
|
|
|
fIdxBuffEnds.Append(-1);
|
|
|
|
|
|
|
|
iData = TRACKED_NEW UInt16[ temp ];
|
|
|
|
hsAssert( iData != nil, "Not enough memory to read in indices" );
|
|
|
|
s->ReadSwap16( temp, (UInt16 *)iData );
|
|
|
|
fIdxBuffStorage.Append( iData );
|
|
|
|
plProfile_NewMem(MemBufGrpIndex, temp * sizeof(UInt16));
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Read in cell arrays, one per vBuffer
|
|
|
|
for( i = 0; i < fVertBuffStorage.GetCount(); i++ )
|
|
|
|
{
|
|
|
|
temp = s->ReadSwap32();
|
|
|
|
|
|
|
|
fCells.Append( TRACKED_NEW hsTArray<plGBufferCell> );
|
|
|
|
fCells[ i ]->SetCount( temp );
|
|
|
|
|
|
|
|
for( j = 0; j < temp; j++ )
|
|
|
|
(*fCells[ i ])[ j ].Read( s );
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//#define VERT_LOG
|
|
|
|
|
|
|
|
void plGBufferGroup::Write( hsStream *s )
|
|
|
|
{
|
|
|
|
UInt32 totalDynSize, i, j;
|
|
|
|
|
|
|
|
#define MF_VERTCODE_ENABLED
|
|
|
|
#ifdef MF_VERTCODE_ENABLED
|
|
|
|
fFormat |= kEncoded;
|
|
|
|
#endif // MF_VERTCODE_ENABLED
|
|
|
|
|
|
|
|
#ifdef VERT_LOG
|
|
|
|
hsUNIXStream log;
|
|
|
|
log.Open("log\\GBuf.log", "ab");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/// Calc total dynamic data size, for fun
|
|
|
|
totalDynSize = 0;
|
|
|
|
for( i = 0; i < fVertBuffSizes.GetCount(); i++ )
|
|
|
|
totalDynSize += fVertBuffSizes[ i ];
|
|
|
|
for( i = 0; i < fIdxBuffCounts.GetCount(); i++ )
|
|
|
|
totalDynSize += sizeof( UInt16 ) * fIdxBuffCounts[ i ];
|
|
|
|
|
|
|
|
s->WriteSwap( fFormat );
|
|
|
|
s->WriteSwap32( totalDynSize );
|
|
|
|
|
|
|
|
plVertCoder coder;
|
|
|
|
|
|
|
|
/// Write out dyanmic data
|
|
|
|
s->WriteSwap32( (UInt32)fVertBuffStorage.GetCount() );
|
|
|
|
for( i = 0; i < fVertBuffStorage.GetCount(); i++ )
|
|
|
|
{
|
|
|
|
#ifdef MF_VERTCODE_ENABLED
|
|
|
|
|
|
|
|
hsAssert(fCells[i]->GetCount() == 1, "Data must be interleaved for compression");
|
|
|
|
UInt32 numVerts = fVertBuffSizes[i] / fStride;
|
|
|
|
s->WriteSwap16((UInt16)numVerts);
|
|
|
|
coder.Write(s, fVertBuffStorage[i], fFormat, fStride, (UInt16)numVerts);
|
|
|
|
|
|
|
|
#ifdef VERT_LOG
|
|
|
|
char buf[256];
|
|
|
|
sprintf(buf, "Vert Buff: %u bytes, idx=%u\r\n", fVertBuffSizes[i], i);
|
|
|
|
log.WriteString(buf);
|
|
|
|
for (int xx = 0; xx < fVertBuffSizes[i] / 4; xx++)
|
|
|
|
{
|
|
|
|
float* buff32 = (float*)fVertBuffStorage[i];
|
|
|
|
buff32 += xx;
|
|
|
|
sprintf(buf, "[%d]%f\r\n", xx*4, *buff32);
|
|
|
|
log.WriteString(buf);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#else // MF_VERTCODE_ENABLED
|
|
|
|
|
|
|
|
s->WriteSwap32( fVertBuffSizes[ i ] );
|
|
|
|
s->Write( fVertBuffSizes[ i ], (void *)fVertBuffStorage[ i ] );
|
|
|
|
|
|
|
|
|
|
|
|
s->WriteSwap32( fColorBuffCounts[ i ] );
|
|
|
|
s->Write( fColorBuffCounts[ i ] * sizeof( plGBufferColor ), (void *)fColorBuffStorage[ i ] );
|
|
|
|
|
|
|
|
#endif // MF_VERTCODE_ENABLED
|
|
|
|
}
|
|
|
|
|
|
|
|
s->WriteSwap32( (UInt32)fIdxBuffCounts.GetCount() );
|
|
|
|
for( i = 0; i < fIdxBuffStorage.GetCount(); i++ )
|
|
|
|
{
|
|
|
|
s->WriteSwap32( fIdxBuffCounts[ i ] );
|
|
|
|
s->WriteSwap16( fIdxBuffCounts[ i ], fIdxBuffStorage[ i ] );
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Write out cell arrays
|
|
|
|
for( i = 0; i < fVertBuffStorage.GetCount(); i++ )
|
|
|
|
{
|
|
|
|
s->WriteSwap32( fCells[ i ]->GetCount() );
|
|
|
|
for( j = 0; j < fCells[ i ]->GetCount(); j++ )
|
|
|
|
(*fCells[ i ])[ j ].Write( s );
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef VERT_LOG
|
|
|
|
log.Close();
|
|
|
|
#endif
|
|
|
|
// All done!
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
//// Editing Functions ////////////////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
//// DeleteVertsFromStorage ///////////////////////////////////////////////////
|
|
|
|
// Deletes a span of verts from the vertex storage. Remember to Prep this
|
|
|
|
// group after doing this!
|
|
|
|
// Note: does NOT adjust index storage, since we don't know inside here
|
|
|
|
// which indices to adjust. Have to call that separately.
|
|
|
|
// Note 2: for simplicity sake, we only do this for groups with ONE interleaved
|
|
|
|
// cell. Doing this for multiple separated cells would be, literally, hell.
|
|
|
|
|
|
|
|
void plGBufferGroup::DeleteVertsFromStorage( UInt32 which, UInt32 start, UInt32 length )
|
|
|
|
{
|
|
|
|
UInt8 *dstPtr, *srcPtr;
|
|
|
|
UInt32 amount;
|
|
|
|
|
|
|
|
|
|
|
|
hsAssert( fCells[ which ]->GetCount() == 1, "Cannot delete verts on a mixed buffer group" );
|
|
|
|
|
|
|
|
// Adjust cell 0
|
|
|
|
(*fCells[ which ])[ 0 ].fLength -= length;
|
|
|
|
|
|
|
|
start *= fStride;
|
|
|
|
length *= fStride;
|
|
|
|
|
|
|
|
if( start + length < fVertBuffSizes[ which ] )
|
|
|
|
{
|
|
|
|
dstPtr = &( fVertBuffStorage[ which ][ start ] );
|
|
|
|
srcPtr = &( fVertBuffStorage[ which ][ start + length ] );
|
|
|
|
|
|
|
|
amount = ( fVertBuffSizes[ which ] ) - ( start + length );
|
|
|
|
|
|
|
|
memmove( dstPtr, srcPtr, amount );
|
|
|
|
}
|
|
|
|
|
|
|
|
fVertBuffSizes[ which ] -= length;
|
|
|
|
plProfile_DelMem(MemBufGrpVertex, length);
|
|
|
|
|
|
|
|
if( fVertexBufferRefs.GetCount() > which && fVertexBufferRefs[ which ] != nil )
|
|
|
|
{
|
|
|
|
hsRefCnt_SafeUnRef(fVertexBufferRefs[which]);
|
|
|
|
fVertexBufferRefs[which] = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//// AdjustIndicesInStorage ///////////////////////////////////////////////////
|
|
|
|
// Adjusts indices >= a given threshold by a given delta. Use it to adjust
|
|
|
|
// indices after vertex deletion. Affects only the given buffer.
|
|
|
|
|
|
|
|
void plGBufferGroup::AdjustIndicesInStorage( UInt32 which, UInt16 threshhold, Int16 delta )
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
|
|
for( i = 0; i < fIdxBuffCounts[ which ]; i++ )
|
|
|
|
{
|
|
|
|
if( fIdxBuffStorage[ which ][ i ] >= threshhold )
|
|
|
|
fIdxBuffStorage[ which ][ i ] += delta;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( fIndexBufferRefs.GetCount() > which && fIndexBufferRefs[ which ] != nil )
|
|
|
|
fIndexBufferRefs[ which ]->SetDirty( true );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//// DeleteIndicesFromStorage /////////////////////////////////////////////////
|
|
|
|
// Deletes a span of indices from the index storage. Remember to Prep this
|
|
|
|
// group after doing this!
|
|
|
|
|
|
|
|
void plGBufferGroup::DeleteIndicesFromStorage( UInt32 which, UInt32 start, UInt32 length )
|
|
|
|
{
|
|
|
|
UInt16 *dstPtr, *srcPtr;
|
|
|
|
UInt32 amount;
|
|
|
|
|
|
|
|
|
|
|
|
hsAssert( start + length <= fIdxBuffCounts[ which ], "Illegal range to DeleteIndicesFromStorage()" );
|
|
|
|
|
|
|
|
if( start + length < fIdxBuffCounts[ which ] )
|
|
|
|
{
|
|
|
|
dstPtr = &( fIdxBuffStorage[ which ][ start ] );
|
|
|
|
srcPtr = &( fIdxBuffStorage[ which ][ start + length ] );
|
|
|
|
|
|
|
|
amount = fIdxBuffCounts[ which ] - ( start + length );
|
|
|
|
|
|
|
|
memmove( dstPtr, srcPtr, amount * sizeof( UInt16 ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
fIdxBuffCounts[ which ] -= length;
|
|
|
|
plProfile_DelMem(MemBufGrpIndex, length * sizeof(UInt16));
|
|
|
|
|
|
|
|
if( fIndexBufferRefs.GetCount() > which && fIndexBufferRefs[ which ] != nil )
|
|
|
|
{
|
|
|
|
hsRefCnt_SafeUnRef(fIndexBufferRefs[which]);
|
|
|
|
fIndexBufferRefs[which] = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//// GetNumPrimaryVertsLeft ///////////////////////////////////////////////////
|
|
|
|
// Base on the cells, so we can take instanced cells into account
|
|
|
|
|
|
|
|
UInt32 plGBufferGroup::GetNumPrimaryVertsLeft( void ) const
|
|
|
|
{
|
|
|
|
return GetNumVertsLeft( 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
//// GetNumVertsLeft //////////////////////////////////////////////////////////
|
|
|
|
// Base on the cells, so we can take instanced cells into account
|
|
|
|
|
|
|
|
UInt32 plGBufferGroup::GetNumVertsLeft( UInt32 idx ) const
|
|
|
|
{
|
|
|
|
if( idx >= fCells.GetCount() )
|
|
|
|
return kMaxNumVertsPerBuffer;
|
|
|
|
|
|
|
|
UInt32 i, total = kMaxNumVertsPerBuffer;
|
|
|
|
|
|
|
|
|
|
|
|
for( i = 0; i < fCells[ idx ]->GetCount(); i++ )
|
|
|
|
total -= (*fCells[ idx ])[ i ].fLength;
|
|
|
|
|
|
|
|
return total;
|
|
|
|
}
|
|
|
|
|
|
|
|
//// IMakeCell ////////////////////////////////////////////////////////////////
|
|
|
|
// Get a cell from the given cell array.
|
|
|
|
|
|
|
|
UInt32 plGBufferGroup::IMakeCell( UInt32 vbIndex, UInt8 flags, UInt32 vStart, UInt32 cStart, UInt32 len, UInt32 *offset )
|
|
|
|
{
|
|
|
|
hsTArray<plGBufferCell> *cells = fCells[ vbIndex ];
|
|
|
|
|
|
|
|
|
|
|
|
if( !(flags & kReserveInterleaved) )
|
|
|
|
{
|
|
|
|
/// Note that there are THREE types of cells: interleaved (colorStart == -1),
|
|
|
|
/// first of an instance group (colorStart != -1 && vStart != -1) and
|
|
|
|
/// an instance (colorStart != -1 && vStart == -1 ). To simplify things,
|
|
|
|
/// we never merge any separated cells
|
|
|
|
|
|
|
|
if( flags & kReserveSeparated )
|
|
|
|
cells->Append( plGBufferCell( vStart, cStart, len ) );
|
|
|
|
else
|
|
|
|
cells->Append( plGBufferCell( (UInt32)-1, cStart, len ) );
|
|
|
|
*offset = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/// Merge if the last cell was an interleaved cell
|
|
|
|
if( cells->GetCount() > 0 && (*cells)[ cells->GetCount() - 1 ].fColorStart == (UInt32)-1 )
|
|
|
|
{
|
|
|
|
*offset = (*cells)[ cells->GetCount() - 1 ].fLength;
|
|
|
|
(*cells)[ cells->GetCount() - 1 ].fLength += len;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cells->Append( plGBufferCell( vStart, (UInt32)-1, len ) );
|
|
|
|
*offset = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return cells->GetCount() - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
//// ReserveVertStorage ///////////////////////////////////////////////////////
|
|
|
|
// Takes a length to reserve in a vertex buffer and returns the buffer index
|
|
|
|
// and starting position. Basically does what AppendToVertStorage() used to
|
|
|
|
// do except it doesn't actually copy any data into the space reserved.
|
|
|
|
|
|
|
|
hsBool plGBufferGroup::ReserveVertStorage( UInt32 numVerts, UInt32 *vbIndex, UInt32 *cell, UInt32 *offset, UInt8 flags )
|
|
|
|
{
|
|
|
|
UInt8 *storagePtr = nil;
|
|
|
|
UInt32 cStartIdx = 0, vStartIdx = 0;
|
|
|
|
plGBufferColor *cStoragePtr = nil;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
|
|
if( numVerts >= kMaxNumVertsPerBuffer )
|
|
|
|
{
|
|
|
|
hsAssert( false, "Egad, why on earth are you adding that many verts???" );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Find a spot
|
|
|
|
if( !(flags & kReserveIsolate) )
|
|
|
|
{
|
|
|
|
for( i = 0; i < fVertBuffStorage.GetCount(); i++ )
|
|
|
|
{
|
|
|
|
if( GetNumVertsLeft( i ) >= numVerts )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
i = fVertBuffStorage.GetCount();
|
|
|
|
}
|
|
|
|
if( i == fVertBuffStorage.GetCount() )
|
|
|
|
{
|
|
|
|
if( (flags & kReserveInterleaved) || (flags & kReserveSeparated) )
|
|
|
|
{
|
|
|
|
fVertBuffStorage.Append( nil );
|
|
|
|
fVertBuffSizes.Append( 0 );
|
|
|
|
}
|
|
|
|
fVertBuffStarts.Append(0);
|
|
|
|
fVertBuffEnds.Append(-1);
|
|
|
|
|
|
|
|
fColorBuffStorage.Append( nil );
|
|
|
|
fColorBuffCounts.Append( 0 );
|
|
|
|
|
|
|
|
fCells.Append( TRACKED_NEW hsTArray<plGBufferCell> );
|
|
|
|
}
|
|
|
|
|
|
|
|
*vbIndex = i;
|
|
|
|
|
|
|
|
if( !(flags & kReserveInterleaved) )
|
|
|
|
{
|
|
|
|
// Splitting the data into vertex and color storage
|
|
|
|
if( flags & kReserveSeparated )
|
|
|
|
{
|
|
|
|
/// Increase the storage size
|
|
|
|
vStartIdx = fVertBuffSizes[ i ];
|
|
|
|
storagePtr = TRACKED_NEW UInt8[ fVertBuffSizes[ i ] + numVerts * fLiteStride ];
|
|
|
|
if( fVertBuffSizes[ i ] > 0 )
|
|
|
|
memcpy( storagePtr, fVertBuffStorage[ i ], fVertBuffSizes[ i ] );
|
|
|
|
fVertBuffSizes[ i ] += numVerts * fLiteStride;
|
|
|
|
plProfile_NewMem(MemBufGrpVertex, numVerts * fLiteStride);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Color too
|
|
|
|
cStartIdx = fColorBuffCounts[ i ];
|
|
|
|
cStoragePtr = TRACKED_NEW plGBufferColor[ fColorBuffCounts[ i ] + numVerts ];
|
|
|
|
if( fColorBuffCounts[ i ] > 0 )
|
|
|
|
memcpy( cStoragePtr, fColorBuffStorage[ i ], fColorBuffCounts[ i ] * sizeof( plGBufferColor ) );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Interleaved
|
|
|
|
|
|
|
|
/// Increase the storage size
|
|
|
|
vStartIdx = fVertBuffSizes[ i ];
|
|
|
|
storagePtr = TRACKED_NEW UInt8[ fVertBuffSizes[ i ] + numVerts * fStride ];
|
|
|
|
if( fVertBuffSizes[ i ] > 0 )
|
|
|
|
memcpy( storagePtr, fVertBuffStorage[ i ], fVertBuffSizes[ i ] );
|
|
|
|
fVertBuffSizes[ i ] += numVerts * fStride;
|
|
|
|
plProfile_NewMem(MemBufGrpVertex, numVerts * fStride);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Switch over
|
|
|
|
if( storagePtr != nil )
|
|
|
|
{
|
|
|
|
if( fVertBuffStorage[ i ] != nil )
|
|
|
|
delete [] fVertBuffStorage[ i ];
|
|
|
|
fVertBuffStorage[ i ] = storagePtr;
|
|
|
|
}
|
|
|
|
if( cStoragePtr != nil )
|
|
|
|
{
|
|
|
|
if( fColorBuffStorage[ i ] != nil )
|
|
|
|
delete [] fColorBuffStorage[ i ];
|
|
|
|
fColorBuffStorage[ i ] = cStoragePtr;
|
|
|
|
fColorBuffCounts[ i ] += numVerts;
|
|
|
|
plProfile_NewMem(MemBufGrpVertex, numVerts * sizeof(plGBufferColor));
|
|
|
|
}
|
|
|
|
|
|
|
|
if( fVertexBufferRefs.GetCount() > i && fVertexBufferRefs[ i ] != nil )
|
|
|
|
{
|
|
|
|
hsRefCnt_SafeUnRef(fVertexBufferRefs[i]);
|
|
|
|
fVertexBufferRefs[i] = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Append a cell entry
|
|
|
|
*cell = IMakeCell( i, flags, vStartIdx, cStartIdx, numVerts, offset );
|
|
|
|
|
|
|
|
/// All done!
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//// AppendToVertStorage //////////////////////////////////////////////////////
|
|
|
|
// Given an opaque array of vertex data, puts it into the first available spot
|
|
|
|
// in fVertStorage. If there is no array on fVertStorage that can hold them,
|
|
|
|
// we create a new one. Returns the index of the storage array and the
|
|
|
|
// starting index into the array. Note that we basically stick it wherever
|
|
|
|
// we can, instead of at the end.
|
|
|
|
// Updated 4.30.2001 mcn to take in a plGeometrySpan as a source rather than
|
|
|
|
// raw data, since the plGeometrySpan no longer stores data in exactly the
|
|
|
|
// same format.
|
|
|
|
// Updated 6.15.2001 mcn to use ReserveVertStorage().
|
|
|
|
|
|
|
|
void plGBufferGroup::AppendToVertStorage( plGeometrySpan *srcSpan, UInt32 *vbIndex, UInt32 *cell, UInt32 *offset )
|
|
|
|
{
|
|
|
|
if( !ReserveVertStorage( srcSpan->fNumVerts, vbIndex, cell, offset, kReserveInterleaved ) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
StuffToVertStorage( srcSpan, *vbIndex, *cell, *offset, kReserveInterleaved );
|
|
|
|
}
|
|
|
|
|
|
|
|
//// AppendToVertAndColorStorage //////////////////////////////////////////////
|
|
|
|
// Same as AppendToVertStorage(), but writes only the verts to the vertex
|
|
|
|
// storage and the colors to the separate color storage.
|
|
|
|
|
|
|
|
void plGBufferGroup::AppendToVertAndColorStorage( plGeometrySpan *srcSpan, UInt32 *vbIndex, UInt32 *cell, UInt32 *offset )
|
|
|
|
{
|
|
|
|
if( !ReserveVertStorage( srcSpan->fNumVerts, vbIndex, cell, offset, kReserveSeparated ) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
StuffToVertStorage( srcSpan, *vbIndex, *cell, *offset, kReserveSeparated );
|
|
|
|
}
|
|
|
|
|
|
|
|
//// AppendToColorStorage /////////////////////////////////////////////////////
|
|
|
|
// Same as AppendToVertStorage(), but writes JUST to color storage.
|
|
|
|
|
|
|
|
void plGBufferGroup::AppendToColorStorage( plGeometrySpan *srcSpan, UInt32 *vbIndex, UInt32 *cell, UInt32 *offset, UInt32 origCell )
|
|
|
|
{
|
|
|
|
if( !ReserveVertStorage( srcSpan->fNumVerts, vbIndex, cell, offset, kReserveColors ) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
(*fCells[ *vbIndex ])[ *cell ].fVtxStart = (*fCells[ *vbIndex ])[ origCell ].fVtxStart;
|
|
|
|
|
|
|
|
StuffToVertStorage( srcSpan, *vbIndex, *cell, *offset, kReserveColors );
|
|
|
|
}
|
|
|
|
|
|
|
|
//// IGetStartVtxPointer //////////////////////////////////////////////////////
|
|
|
|
// Get the start vertex and color buffer pointers for a given cell and offset
|
|
|
|
|
|
|
|
void plGBufferGroup::IGetStartVtxPointer( UInt32 vbIndex, UInt32 cell, UInt32 offset, UInt8 *&tempPtr, plGBufferColor *&cPtr )
|
|
|
|
{
|
|
|
|
hsAssert( vbIndex < fVertBuffStorage.GetCount(), "Invalid vbIndex in StuffToVertStorage()" );
|
|
|
|
hsAssert( cell < fCells[ vbIndex ]->GetCount(), "Invalid cell in StuffToVertStorage()" );
|
|
|
|
|
|
|
|
tempPtr = fVertBuffStorage[ vbIndex ];
|
|
|
|
cPtr = fColorBuffStorage[ vbIndex ];
|
|
|
|
|
|
|
|
tempPtr += (*fCells[ vbIndex ])[ cell ].fVtxStart;
|
|
|
|
cPtr += (*fCells[ vbIndex ])[ cell ].fColorStart;
|
|
|
|
|
|
|
|
if( offset > 0 )
|
|
|
|
{
|
|
|
|
tempPtr += offset * ( ( (*fCells[ vbIndex ])[ cell ].fColorStart == (UInt32)-1 ) ? fStride : fLiteStride );
|
|
|
|
cPtr += offset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//// GetVertBufferCount ///////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
UInt32 plGBufferGroup::GetVertBufferCount( UInt32 idx ) const
|
|
|
|
{
|
|
|
|
return GetVertStartFromCell( idx, fCells[ idx ]->GetCount(), 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
//// GetVertStartFromCell /////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
UInt32 plGBufferGroup::GetVertStartFromCell( UInt32 vbIndex, UInt32 cell, UInt32 offset ) const
|
|
|
|
{
|
|
|
|
UInt32 i, numVerts;
|
|
|
|
|
|
|
|
|
|
|
|
hsAssert( vbIndex < fVertBuffStorage.GetCount(), "Invalid vbIndex in StuffToVertStorage()" );
|
|
|
|
hsAssert( cell <= fCells[ vbIndex ]->GetCount(), "Invalid cell in StuffToVertStorage()" );
|
|
|
|
|
|
|
|
numVerts = 0;
|
|
|
|
for( i = 0; i < cell; i++ )
|
|
|
|
numVerts += (*fCells[ vbIndex ])[ i ].fLength;
|
|
|
|
|
|
|
|
numVerts += offset;
|
|
|
|
|
|
|
|
return numVerts;
|
|
|
|
}
|
|
|
|
|
|
|
|
//// StuffToVertStorage ///////////////////////////////////////////////////////
|
|
|
|
// Stuffs data from a plGeometrySpan into the specified location in the
|
|
|
|
// specified vertex buffer.
|
|
|
|
|
|
|
|
void plGBufferGroup::StuffToVertStorage( plGeometrySpan *srcSpan, UInt32 vbIndex, UInt32 cell, UInt32 offset, UInt8 flags )
|
|
|
|
{
|
|
|
|
UInt8 *tempPtr, stride;
|
|
|
|
plGBufferColor *cPtr;
|
|
|
|
int i, j, numVerts;
|
|
|
|
plGBufferCell *cellPtr;
|
|
|
|
|
|
|
|
|
|
|
|
hsAssert( vbIndex < fVertBuffStorage.GetCount(), "Invalid vbIndex in StuffToVertStorage()" );
|
|
|
|
hsAssert( cell < fCells[ vbIndex ]->GetCount(), "Invalid cell in StuffToVertStorage()" );
|
|
|
|
|
|
|
|
IGetStartVtxPointer( vbIndex, cell, offset, tempPtr, cPtr );
|
|
|
|
cellPtr = &(*fCells[ vbIndex ])[ cell ];
|
|
|
|
stride = ( cellPtr->fColorStart != (UInt32)-1 ) ? fLiteStride : fStride;
|
|
|
|
|
|
|
|
numVerts = srcSpan->fNumVerts;
|
|
|
|
|
|
|
|
/// Copy the data over
|
|
|
|
for( i = 0; i < numVerts; i++ )
|
|
|
|
{
|
|
|
|
hsPoint3 pos;
|
|
|
|
float weights[ 3 ];
|
|
|
|
UInt32 weightIndices;
|
|
|
|
hsVector3 norm;
|
|
|
|
UInt32 color, specColor;
|
|
|
|
hsPoint3 uvs[ plGeometrySpan::kMaxNumUVChannels ];
|
|
|
|
float *fPtr;
|
|
|
|
UInt32 *dPtr;
|
|
|
|
|
|
|
|
|
|
|
|
// Gotta swap the data around, since plGeometrySpans store the data slightly differently
|
|
|
|
if( flags & kReserveColors )
|
|
|
|
{
|
|
|
|
/// Just do colors
|
|
|
|
srcSpan->ExtractVertex( i, &pos, &norm, &color, &specColor );
|
|
|
|
|
|
|
|
cPtr->fDiffuse = color;
|
|
|
|
cPtr->fSpecular = specColor;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/// Do verts, possibly colors as well
|
|
|
|
srcSpan->ExtractVertex( i, &pos, &norm, &color, &specColor );
|
|
|
|
if( ( fFormat & kSkinWeightMask ) != kSkinNoWeights )
|
|
|
|
srcSpan->ExtractWeights( i, weights, &weightIndices );
|
|
|
|
for( j = 0; j < GetNumUVs(); j++ )
|
|
|
|
srcSpan->ExtractUv( i, j, &uvs[ j ] );
|
|
|
|
|
|
|
|
// Stuff it in now
|
|
|
|
fPtr = (float *)tempPtr;
|
|
|
|
fPtr[ 0 ] = pos.fX;
|
|
|
|
fPtr[ 1 ] = pos.fY;
|
|
|
|
fPtr[ 2 ] = pos.fZ;
|
|
|
|
fPtr += 3;
|
|
|
|
|
|
|
|
if( fNumSkinWeights > 0 )
|
|
|
|
{
|
|
|
|
for( j = 0; j < fNumSkinWeights; j++ )
|
|
|
|
{
|
|
|
|
*fPtr = weights[ j ];
|
|
|
|
fPtr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( fNumSkinWeights > 1 )
|
|
|
|
{
|
|
|
|
dPtr = (UInt32 *)fPtr;
|
|
|
|
*dPtr = weightIndices;
|
|
|
|
|
|
|
|
dPtr++;
|
|
|
|
fPtr = (float *)dPtr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fPtr[ 0 ] = norm.fX;
|
|
|
|
fPtr[ 1 ] = norm.fY;
|
|
|
|
fPtr[ 2 ] = norm.fZ;
|
|
|
|
fPtr += 3;
|
|
|
|
|
|
|
|
if( flags & kReserveInterleaved )
|
|
|
|
{
|
|
|
|
dPtr = (UInt32 *)fPtr;
|
|
|
|
dPtr[ 0 ] = color;
|
|
|
|
dPtr[ 1 ] = specColor;
|
|
|
|
dPtr += 2;
|
|
|
|
fPtr = (float *)dPtr;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cPtr->fDiffuse = color;
|
|
|
|
cPtr->fSpecular = specColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
for( j = 0; j < GetNumUVs(); j++ )
|
|
|
|
{
|
|
|
|
fPtr[ 0 ] = uvs[ j ].fX;
|
|
|
|
fPtr[ 1 ] = uvs[ j ].fY;
|
|
|
|
fPtr[ 2 ] = uvs[ j ].fZ;
|
|
|
|
fPtr += 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tempPtr += stride;
|
|
|
|
cPtr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( ( vbIndex < fVertexBufferRefs.GetCount() ) && fVertexBufferRefs[ vbIndex ] )
|
|
|
|
fVertexBufferRefs[ vbIndex ]->SetDirty( true );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//// ReserveIndexStorage //////////////////////////////////////////////////////
|
|
|
|
// Same as ReserveVertStorage(), only for indices :)
|
|
|
|
|
|
|
|
hsBool plGBufferGroup::ReserveIndexStorage( UInt32 numIndices, UInt32 *ibIndex, UInt32 *ibStart, UInt16 **dataPtr )
|
|
|
|
{
|
|
|
|
UInt16 *storagePtr;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
|
|
if( numIndices >= kMaxNumIndicesPerBuffer )
|
|
|
|
{
|
|
|
|
hsAssert( false, "Egad, why on earth are you adding that many indices???" );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Find a spot
|
|
|
|
for( i = 0; i < fIdxBuffStorage.GetCount(); i++ )
|
|
|
|
{
|
|
|
|
|
|
|
|
if( fIdxBuffCounts[ i ] + numIndices < kMaxNumIndicesPerBuffer )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if( i == fIdxBuffStorage.GetCount() )
|
|
|
|
{
|
|
|
|
fIdxBuffStorage.Append( nil );
|
|
|
|
fIdxBuffCounts.Append( 0 );
|
|
|
|
|
|
|
|
fIdxBuffStarts.Append(0);
|
|
|
|
fIdxBuffEnds.Append(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
*ibIndex = i;
|
|
|
|
*ibStart = fIdxBuffCounts[ i ];
|
|
|
|
|
|
|
|
/// Increase the storage size
|
|
|
|
storagePtr = TRACKED_NEW UInt16[ fIdxBuffCounts[ i ] + numIndices ];
|
|
|
|
if( fIdxBuffCounts[ i ] > 0 )
|
|
|
|
memcpy( storagePtr, fIdxBuffStorage[ i ], fIdxBuffCounts[ i ] * sizeof( UInt16 ) );
|
|
|
|
|
|
|
|
if( dataPtr != nil )
|
|
|
|
*dataPtr = storagePtr + fIdxBuffCounts[ i ];
|
|
|
|
|
|
|
|
/// Switch over
|
|
|
|
i = *ibIndex;
|
|
|
|
if( fIdxBuffStorage[ i ] != nil )
|
|
|
|
delete [] fIdxBuffStorage[ i ];
|
|
|
|
fIdxBuffStorage[ i ] = storagePtr;
|
|
|
|
fIdxBuffCounts[ i ] += numIndices;
|
|
|
|
plProfile_NewMem(MemBufGrpIndex, numIndices * sizeof(UInt16));
|
|
|
|
|
|
|
|
/// All done!
|
|
|
|
if( fIndexBufferRefs.GetCount() > i && fIndexBufferRefs[ i ] != nil )
|
|
|
|
{
|
|
|
|
hsRefCnt_SafeUnRef(fIndexBufferRefs[i]);
|
|
|
|
fIndexBufferRefs[i] = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//// AppendToIndexStorage /////////////////////////////////////////////////////
|
|
|
|
// Same as AppendToVertStorage, only for the index buffers and indices. Duh :)
|
|
|
|
|
|
|
|
void plGBufferGroup::AppendToIndexStorage( UInt32 numIndices, UInt16 *data, UInt32 addToAll,
|
|
|
|
UInt32 *ibIndex, UInt32 *ibStart )
|
|
|
|
{
|
|
|
|
UInt16 *tempPtr;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
|
|
if( !ReserveIndexStorage( numIndices, ibIndex, ibStart, &tempPtr ) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
/// Copy new indices over, offsetting them as we were told to
|
|
|
|
for( i = 0; i < numIndices; i++ )
|
|
|
|
tempPtr[ i ] = data[ i ] + (UInt16)addToAll;
|
|
|
|
|
|
|
|
/// All done!
|
|
|
|
}
|
|
|
|
|
|
|
|
//// ConvertToTriList /////////////////////////////////////////////////////////
|
|
|
|
// Returns an array of plGBufferTriangles representing the span of indices
|
|
|
|
// specified.
|
|
|
|
|
|
|
|
plGBufferTriangle *plGBufferGroup::ConvertToTriList( Int16 spanIndex, UInt32 whichIdx, UInt32 whichVtx, UInt32 whichCell, UInt32 start, UInt32 numTriangles )
|
|
|
|
{
|
|
|
|
plGBufferTriangle *array;
|
|
|
|
UInt16 *storagePtr;
|
|
|
|
UInt8 *vertStgPtr, stride;
|
|
|
|
float *vertPtr;
|
|
|
|
int i, j;
|
|
|
|
hsPoint3 center;
|
|
|
|
UInt32 offsetBy;
|
|
|
|
plGBufferColor *wastePtr;
|
|
|
|
|
|
|
|
|
|
|
|
/// Sanity checks
|
|
|
|
hsAssert( whichIdx < fIdxBuffStorage.GetCount(), "Invalid index buffer ID to ConvertToTriList()" );
|
|
|
|
hsAssert( whichVtx < fVertBuffStorage.GetCount(), "Invalid vertex buffer ID to ConvertToTriList()" );
|
|
|
|
hsAssert( start < fIdxBuffCounts[ whichIdx ], "Invalid start index to ConvertToTriList()" );
|
|
|
|
hsAssert( start + numTriangles * 3 <= fIdxBuffCounts[ whichIdx ], "Invalid count to ConvertToTriList()" );
|
|
|
|
hsAssert( whichCell < fCells[ whichVtx ]->GetCount(), "Invalid cell to ConvertToTriList()" );
|
|
|
|
|
|
|
|
/// Create the array and fill it
|
|
|
|
array = TRACKED_NEW plGBufferTriangle[ numTriangles ];
|
|
|
|
hsAssert( array != nil, "Not enough memory to create triangle data in ConvertToTriList()" );
|
|
|
|
|
|
|
|
storagePtr = fIdxBuffStorage[ whichIdx ];
|
|
|
|
IGetStartVtxPointer( whichVtx, whichCell, 0, vertStgPtr, wastePtr );
|
|
|
|
offsetBy = GetVertStartFromCell( whichVtx, whichCell, 0 );
|
|
|
|
stride = ( (*fCells[ whichVtx ])[ whichCell ].fColorStart == (UInt32)-1 ) ? fStride : fLiteStride;
|
|
|
|
|
|
|
|
for( i = 0, j = 0; i < numTriangles; i++, j += 3 )
|
|
|
|
{
|
|
|
|
center.fX = center.fY = center.fZ = 0;
|
|
|
|
|
|
|
|
vertPtr = (float *)( vertStgPtr + stride * ( storagePtr[ start + j + 0 ] - offsetBy ) );
|
|
|
|
|
|
|
|
center.fX += vertPtr[ 0 ];
|
|
|
|
center.fY += vertPtr[ 1 ];
|
|
|
|
center.fZ += vertPtr[ 2 ];
|
|
|
|
|
|
|
|
vertPtr = (float *)( vertStgPtr + stride * ( storagePtr[ start + j + 1 ] - offsetBy ) );
|
|
|
|
|
|
|
|
center.fX += vertPtr[ 0 ];
|
|
|
|
center.fY += vertPtr[ 1 ];
|
|
|
|
center.fZ += vertPtr[ 2 ];
|
|
|
|
|
|
|
|
vertPtr = (float *)( vertStgPtr + stride * ( storagePtr[ start + j + 2 ] - offsetBy ) );
|
|
|
|
|
|
|
|
center.fX += vertPtr[ 0 ];
|
|
|
|
center.fY += vertPtr[ 1 ];
|
|
|
|
center.fZ += vertPtr[ 2 ];
|
|
|
|
|
|
|
|
center.fX /= 3.0f;
|
|
|
|
center.fY /= 3.0f;
|
|
|
|
center.fZ /= 3.0f;
|
|
|
|
|
|
|
|
array[ i ].fSpanIndex = spanIndex;
|
|
|
|
array[ i ].fIndex1 = storagePtr[ start + j + 0 ];
|
|
|
|
array[ i ].fIndex2 = storagePtr[ start + j + 1 ];
|
|
|
|
array[ i ].fIndex3 = storagePtr[ start + j + 2 ];
|
|
|
|
array[ i ].fCenter = center;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// All done!
|
|
|
|
return array;
|
|
|
|
}
|
|
|
|
|
|
|
|
//// StuffFromTriList /////////////////////////////////////////////////////////
|
|
|
|
// Stuffs the indices from an array of plGBufferTriangles into the index
|
|
|
|
// storage.
|
|
|
|
|
|
|
|
void plGBufferGroup::StuffFromTriList( UInt32 which, UInt32 start, UInt32 numTriangles, UInt16 *data )
|
|
|
|
{
|
|
|
|
UInt16 *storagePtr;
|
|
|
|
|
|
|
|
|
|
|
|
/// Sanity checks
|
|
|
|
hsAssert( which < fIdxBuffStorage.GetCount(), "Invalid index buffer ID to StuffFromTriList()" );
|
|
|
|
hsAssert( start < fIdxBuffCounts[ which ], "Invalid start index to StuffFromTriList()" );
|
|
|
|
hsAssert( start + numTriangles * 3 <= fIdxBuffCounts[ which ], "Invalid count to StuffFromTriList()" );
|
|
|
|
|
|
|
|
|
|
|
|
/// This is easy--just stuff!
|
|
|
|
storagePtr = fIdxBuffStorage[ which ];
|
|
|
|
#define MF_SPEED_THIS_UP
|
|
|
|
#ifndef MF_SPEED_THIS_UP
|
|
|
|
int i, j;
|
|
|
|
for( i = 0, j = 0; i < numTriangles; i++, j += 3 )
|
|
|
|
{
|
|
|
|
storagePtr[ start + j ] = data[ i ].fIndex1;
|
|
|
|
storagePtr[ start + j + 1 ] = data[ i ].fIndex2;
|
|
|
|
storagePtr[ start + j + 2 ] = data[ i ].fIndex3;
|
|
|
|
}
|
|
|
|
#else // MF_SPEED_THIS_UP
|
|
|
|
memcpy( storagePtr + start, data, numTriangles * 3 * sizeof(*data) );
|
|
|
|
#endif // MF_SPEED_THIS_UP
|
|
|
|
|
|
|
|
/// All done! Just make sure we refresh before we render...
|
|
|
|
if( fIndexBufferRefs.GetCount() > which && fIndexBufferRefs[ which ] != nil )
|
|
|
|
fIndexBufferRefs[ which ]->SetDirty( true );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//// StuffTri /////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void plGBufferGroup::StuffTri( UInt32 iBuff, UInt32 iTri, UInt16 idx0, UInt16 idx1, UInt16 idx2 )
|
|
|
|
{
|
|
|
|
/// Sanity checks
|
|
|
|
hsAssert( iBuff < fIdxBuffStorage.GetCount(), "Invalid index buffer ID to StuffFromTriList()" );
|
|
|
|
hsAssert( iTri < fIdxBuffCounts[ iBuff ], "Invalid start index to StuffFromTriList()" );
|
|
|
|
|
|
|
|
fIdxBuffStorage[ iBuff ][ iTri + 0 ] = idx0;
|
|
|
|
fIdxBuffStorage[ iBuff ][ iTri + 1 ] = idx1;
|
|
|
|
fIdxBuffStorage[ iBuff ][ iTri + 2 ] = idx2;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//// Accessor Functions ///////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
hsPoint3 &plGBufferGroup::Position( int iBuff, UInt32 cell, int iVtx )
|
|
|
|
{
|
|
|
|
UInt8 *vertStgPtr;
|
|
|
|
plGBufferColor *cPtr;
|
|
|
|
|
|
|
|
IGetStartVtxPointer( iBuff, cell, iVtx, vertStgPtr, cPtr );
|
|
|
|
|
|
|
|
return *(hsPoint3 *)( vertStgPtr + 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
hsVector3 &plGBufferGroup::Normal( int iBuff, UInt32 cell, int iVtx )
|
|
|
|
{
|
|
|
|
UInt8 *vertStgPtr;
|
|
|
|
plGBufferColor *cPtr;
|
|
|
|
|
|
|
|
IGetStartVtxPointer( iBuff, cell, iVtx, vertStgPtr, cPtr );
|
|
|
|
|
|
|
|
return *(hsVector3 *)( vertStgPtr + sizeof( hsPoint3 ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
UInt32 &plGBufferGroup::Color( int iBuff, UInt32 cell, int iVtx )
|
|
|
|
{
|
|
|
|
UInt8 *vertStgPtr;
|
|
|
|
plGBufferColor *cPtr;
|
|
|
|
|
|
|
|
IGetStartVtxPointer( iBuff, cell, iVtx, vertStgPtr, cPtr );
|
|
|
|
|
|
|
|
if( (*fCells[ iBuff ])[ cell ].fColorStart != (UInt32)-1 )
|
|
|
|
return *(UInt32 *)( &cPtr->fDiffuse );
|
|
|
|
else
|
|
|
|
return *(UInt32 *)( vertStgPtr + 2 * sizeof( hsPoint3 ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
UInt32 &plGBufferGroup::Specular( int iBuff, UInt32 cell, int iVtx )
|
|
|
|
{
|
|
|
|
UInt8 *vertStgPtr;
|
|
|
|
plGBufferColor *cPtr;
|
|
|
|
|
|
|
|
IGetStartVtxPointer( iBuff, cell, iVtx, vertStgPtr, cPtr );
|
|
|
|
|
|
|
|
if( (*fCells[ iBuff ])[ cell ].fColorStart != (UInt32)-1 )
|
|
|
|
return *(UInt32 *)( &cPtr->fSpecular );
|
|
|
|
else
|
|
|
|
return *(UInt32 *)( vertStgPtr + 2 * sizeof( hsPoint3 ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
hsPoint3 &plGBufferGroup::UV( int iBuff, UInt32 cell, int iVtx, int channel )
|
|
|
|
{
|
|
|
|
UInt8 *vertStgPtr;
|
|
|
|
plGBufferColor *cPtr;
|
|
|
|
|
|
|
|
IGetStartVtxPointer( iBuff, cell, iVtx, vertStgPtr, cPtr );
|
|
|
|
|
|
|
|
vertStgPtr += 2 * sizeof( hsPoint3 ) + channel * sizeof( hsPoint3 );
|
|
|
|
|
|
|
|
if( (*fCells[ iBuff ])[ cell ].fColorStart != (UInt32)-1 )
|
|
|
|
return *(hsPoint3 *)( vertStgPtr );
|
|
|
|
else
|
|
|
|
return *(hsPoint3 *)( vertStgPtr + 2 * sizeof( UInt32 ) );
|
|
|
|
}
|