1
This commit is contained in:
70
mdllib/mdllib.cpp
Normal file
70
mdllib/mdllib.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "mdllib_common.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Global instance
|
||||
//-----------------------------------------------------------------------------
|
||||
CMdlLib mdllib;
|
||||
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CMdlLib, IMdlLib, MDLLIB_INTERFACE_VERSION, mdllib );
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CMdlLib::~CMdlLib()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Connect, disconnect
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CMdlLib::Connect( CreateInterfaceFn factory )
|
||||
{
|
||||
// g_pFileSystem = (IFileSystem*)factory( FILESYSTEM_INTERFACE_VERSION, NULL );
|
||||
// return ( g_pFileSystem != NULL );
|
||||
return true;
|
||||
}
|
||||
|
||||
void CMdlLib::Disconnect()
|
||||
{
|
||||
// g_pFileSystem = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Startup
|
||||
//-----------------------------------------------------------------------------
|
||||
InitReturnVal_t CMdlLib::Init()
|
||||
{
|
||||
return INIT_OK;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Cleanup
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMdlLib::Shutdown()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Query interface
|
||||
//-----------------------------------------------------------------------------
|
||||
void *CMdlLib::QueryInterface( const char *pInterfaceName )
|
||||
{
|
||||
return Sys_GetFactoryThis()( pInterfaceName, NULL );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
44
mdllib/mdllib.vpc
Normal file
44
mdllib/mdllib.vpc
Normal file
@ -0,0 +1,44 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// MDLLIB.VPC
|
||||
//
|
||||
// Project Script
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
$Macro SRCDIR ".."
|
||||
$Macro OUTBINDIR "$SRCDIR\..\game\bin"
|
||||
|
||||
$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
|
||||
|
||||
$Configuration
|
||||
{
|
||||
$Compiler
|
||||
{
|
||||
}
|
||||
|
||||
$Linker
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
$Project "mdllib"
|
||||
{
|
||||
$Folder "Source Files"
|
||||
{
|
||||
$File "mdllib.cpp"
|
||||
$File "mdllib_stripinfo.cpp"
|
||||
$File "mdllib_stripmodel.cpp"
|
||||
$File "mdllib_utils.cpp"
|
||||
}
|
||||
|
||||
$Folder "Header Files"
|
||||
{
|
||||
$File "$SRCDIR\public\mdllib\mdllib.h"
|
||||
$File "mdllib_common.h"
|
||||
$File "mdllib_stripinfo.h"
|
||||
$File "mdllib_utils.h"
|
||||
}
|
||||
|
||||
$Folder "Link Libraries"
|
||||
{
|
||||
}
|
||||
}
|
67
mdllib/mdllib_common.h
Normal file
67
mdllib/mdllib_common.h
Normal file
@ -0,0 +1,67 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef MDLLIB_COMMON_H
|
||||
#define MDLLIB_COMMON_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "mdllib/mdllib.h"
|
||||
|
||||
#include "platform.h"
|
||||
#pragma warning( disable : 4018 )
|
||||
#pragma warning( disable : 4389 )
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Interface to accessing P4 commands
|
||||
//-----------------------------------------------------------------------------
|
||||
class CMdlLib : public CBaseAppSystem< IMdlLib >
|
||||
{
|
||||
public:
|
||||
// Destructor
|
||||
virtual ~CMdlLib();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Methods of IAppSystem
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
public:
|
||||
virtual bool Connect( CreateInterfaceFn factory );
|
||||
virtual InitReturnVal_t Init();
|
||||
virtual void *QueryInterface( const char *pInterfaceName );
|
||||
virtual void Shutdown();
|
||||
virtual void Disconnect();
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Methods of IMdlLib
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
public:
|
||||
//
|
||||
// StripModelBuffers
|
||||
// The main function that strips the model buffers
|
||||
// mdlBuffer - mdl buffer, updated, no size change
|
||||
// vvdBuffer - vvd buffer, updated, size reduced
|
||||
// vtxBuffer - vtx buffer, updated, size reduced
|
||||
// ppStripInfo - if nonzero on return will be filled with the stripping info
|
||||
//
|
||||
virtual bool StripModelBuffers( CUtlBuffer &mdlBuffer, CUtlBuffer &vvdBuffer, CUtlBuffer &vtxBuffer, IMdlStripInfo **ppStripInfo );
|
||||
|
||||
//
|
||||
// CreateNewStripInfo
|
||||
// Creates an empty strip info so that it can be reused.
|
||||
//
|
||||
virtual bool CreateNewStripInfo( IMdlStripInfo **ppStripInfo );
|
||||
};
|
||||
|
||||
#endif // #ifndef MDLLIB_COMMON_H
|
671
mdllib/mdllib_stripinfo.cpp
Normal file
671
mdllib/mdllib_stripinfo.cpp
Normal file
@ -0,0 +1,671 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "mdllib_common.h"
|
||||
#include "mdllib_stripinfo.h"
|
||||
#include "mdllib_utils.h"
|
||||
|
||||
#include "studio.h"
|
||||
#include "optimize.h"
|
||||
|
||||
#include "materialsystem/imaterial.h"
|
||||
#include "materialsystem/hardwareverts.h"
|
||||
|
||||
#include "smartptr.h"
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CMdlStripInfo implementation
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
CMdlStripInfo::CMdlStripInfo() :
|
||||
m_eMode( MODE_UNINITIALIZED ),
|
||||
m_lChecksumOld( 0 ),
|
||||
m_lChecksumNew( 0 )
|
||||
{
|
||||
NULL;
|
||||
}
|
||||
|
||||
|
||||
bool CMdlStripInfo::Serialize( CUtlBuffer &bufStorage ) const
|
||||
{
|
||||
char chHeader[ 4 ] = { 'M', 'A', 'P', m_eMode };
|
||||
bufStorage.Put( chHeader, sizeof( chHeader ) );
|
||||
|
||||
switch ( m_eMode )
|
||||
{
|
||||
default:
|
||||
case MODE_UNINITIALIZED:
|
||||
return true;
|
||||
|
||||
case MODE_NO_CHANGE:
|
||||
bufStorage.PutInt( m_lChecksumOld );
|
||||
bufStorage.PutInt( m_lChecksumNew );
|
||||
return true;
|
||||
|
||||
case MODE_STRIP_LOD_1N:
|
||||
bufStorage.PutInt( m_lChecksumOld );
|
||||
bufStorage.PutInt( m_lChecksumNew );
|
||||
|
||||
bufStorage.PutInt( m_vtxVerts.GetNumBits() );
|
||||
for ( uint32 const *pdwBase = m_vtxVerts.Base(), *pdwEnd = pdwBase + m_vtxVerts.GetNumDWords();
|
||||
pdwBase < pdwEnd; ++ pdwBase )
|
||||
bufStorage.PutUnsignedInt( *pdwBase );
|
||||
|
||||
bufStorage.PutInt( m_vtxIndices.Count() );
|
||||
for ( unsigned short const *pusBase = m_vtxIndices.Base(), *pusEnd = pusBase + m_vtxIndices.Count();
|
||||
pusBase < pusEnd; ++ pusBase )
|
||||
bufStorage.PutUnsignedShort( *pusBase );
|
||||
|
||||
bufStorage.PutInt( m_vtxMdlOffsets.Count() );
|
||||
for ( MdlRangeItem const *pmri = m_vtxMdlOffsets.Base(), *pmriEnd = pmri + m_vtxMdlOffsets.Count();
|
||||
pmri < pmriEnd; ++ pmri )
|
||||
bufStorage.PutInt( pmri->m_offOld ),
|
||||
bufStorage.PutInt( pmri->m_offNew ),
|
||||
bufStorage.PutInt( pmri->m_numOld ),
|
||||
bufStorage.PutInt( pmri->m_numNew );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool CMdlStripInfo::UnSerialize( CUtlBuffer &bufData )
|
||||
{
|
||||
char chHeader[ 4 ];
|
||||
bufData.Get( chHeader, sizeof( chHeader ) );
|
||||
|
||||
if ( memcmp( chHeader, "MAP", 3 ) )
|
||||
return false;
|
||||
|
||||
switch ( chHeader[3] )
|
||||
{
|
||||
default:
|
||||
return false;
|
||||
|
||||
case MODE_UNINITIALIZED:
|
||||
m_eMode = MODE_UNINITIALIZED;
|
||||
m_lChecksumOld = 0;
|
||||
m_lChecksumNew = 0;
|
||||
return true;
|
||||
|
||||
case MODE_NO_CHANGE:
|
||||
m_eMode = MODE_NO_CHANGE;
|
||||
m_lChecksumOld = bufData.GetInt();
|
||||
m_lChecksumNew = bufData.GetInt();
|
||||
return true;
|
||||
|
||||
case MODE_STRIP_LOD_1N:
|
||||
m_eMode = MODE_STRIP_LOD_1N;
|
||||
m_lChecksumOld = bufData.GetInt();
|
||||
m_lChecksumNew = bufData.GetInt();
|
||||
|
||||
m_vtxVerts.Resize( bufData.GetInt(), true );
|
||||
for ( uint32 *pdwBase = m_vtxVerts.Base(), *pdwEnd = pdwBase + m_vtxVerts.GetNumDWords();
|
||||
pdwBase < pdwEnd; ++ pdwBase )
|
||||
*pdwBase = bufData.GetUnsignedInt();
|
||||
|
||||
m_vtxIndices.SetCount( bufData.GetInt() );
|
||||
for ( unsigned short *pusBase = m_vtxIndices.Base(), *pusEnd = pusBase + m_vtxIndices.Count();
|
||||
pusBase < pusEnd; ++ pusBase )
|
||||
*pusBase = bufData.GetUnsignedShort();
|
||||
|
||||
m_vtxMdlOffsets.SetCount( bufData.GetInt() );
|
||||
for ( MdlRangeItem *pmri = m_vtxMdlOffsets.Base(), *pmriEnd = pmri + m_vtxMdlOffsets.Count();
|
||||
pmri < pmriEnd; ++ pmri )
|
||||
pmri->m_offOld = bufData.GetInt(),
|
||||
pmri->m_offNew = bufData.GetInt(),
|
||||
pmri->m_numOld = bufData.GetInt(),
|
||||
pmri->m_numNew = bufData.GetInt();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Returns the checksums that the stripping info was generated for:
|
||||
// plChecksumOriginal if non-NULL will hold the checksum of the original model submitted for stripping
|
||||
// plChecksumStripped if non-NULL will hold the resulting checksum of the stripped model
|
||||
bool CMdlStripInfo::GetCheckSum( long *plChecksumOriginal, long *plChecksumStripped ) const
|
||||
{
|
||||
if ( m_eMode == MODE_UNINITIALIZED )
|
||||
return false;
|
||||
|
||||
if ( plChecksumOriginal )
|
||||
*plChecksumOriginal = m_lChecksumOld;
|
||||
|
||||
if ( plChecksumStripped )
|
||||
*plChecksumStripped = m_lChecksumNew;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// StripHardwareVertsBuffer
|
||||
// The main function that strips the vhv buffer
|
||||
// vhvBuffer - vhv buffer, updated, size reduced
|
||||
//
|
||||
bool CMdlStripInfo::StripHardwareVertsBuffer( CUtlBuffer &vhvBuffer )
|
||||
{
|
||||
if ( m_eMode == MODE_UNINITIALIZED )
|
||||
return false;
|
||||
|
||||
//
|
||||
// Recover vhv header
|
||||
//
|
||||
DECLARE_PTR( HardwareVerts::FileHeader_t, vhvHdr, BYTE_OFF_PTR( vhvBuffer.Base(), vhvBuffer.TellGet() ) );
|
||||
int vhvLength = vhvBuffer.TellPut() - vhvBuffer.TellGet();
|
||||
|
||||
if ( vhvHdr->m_nChecksum != m_lChecksumOld )
|
||||
{
|
||||
DLog( "mdllib", 1, "ERROR: [StripHardwareVertsBuffer] checksum mismatch!\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
vhvHdr->m_nChecksum = m_lChecksumNew;
|
||||
|
||||
|
||||
// No remapping required
|
||||
if ( m_eMode == MODE_NO_CHANGE )
|
||||
return true;
|
||||
|
||||
|
||||
Assert( m_eMode == MODE_STRIP_LOD_1N );
|
||||
|
||||
//
|
||||
// Now reconstruct the vhv structures to do the mapping
|
||||
//
|
||||
|
||||
CRemoveTracker vhvRemove;
|
||||
size_t vhvVertOffset = ~size_t( 0 ), vhvEndMeshOffset = sizeof( HardwareVerts::FileHeader_t );
|
||||
int numMeshesRemoved = 0, numVertsRemoved = 0;
|
||||
|
||||
ITERATE_CHILDREN( HardwareVerts::MeshHeader_t, vhvMesh, vhvHdr, pMesh, m_nMeshes )
|
||||
if ( vhvMesh->m_nOffset < vhvVertOffset )
|
||||
vhvVertOffset = vhvMesh->m_nOffset;
|
||||
if ( BYTE_DIFF_PTR( vhvHdr, vhvMesh + 1 ) > vhvEndMeshOffset )
|
||||
vhvEndMeshOffset = BYTE_DIFF_PTR( vhvHdr, vhvMesh + 1 );
|
||||
if ( !vhvMesh->m_nLod )
|
||||
continue;
|
||||
vhvRemove.RemoveBytes( BYTE_OFF_PTR( vhvHdr, vhvMesh->m_nOffset ), vhvMesh->m_nVertexes * vhvHdr->m_nVertexSize );
|
||||
vhvRemove.RemoveElements( vhvMesh );
|
||||
numVertsRemoved += vhvMesh->m_nVertexes;
|
||||
++ numMeshesRemoved;
|
||||
ITERATE_END
|
||||
vhvRemove.RemoveBytes( BYTE_OFF_PTR( vhvHdr, vhvEndMeshOffset ), vhvVertOffset - vhvEndMeshOffset ); // Padding
|
||||
vhvRemove.RemoveBytes( BYTE_OFF_PTR( vhvHdr, vhvVertOffset + vhvHdr->m_nVertexes * vhvHdr->m_nVertexSize ), vhvLength - ( vhvVertOffset + vhvHdr->m_nVertexes * vhvHdr->m_nVertexSize ) );
|
||||
|
||||
vhvRemove.Finalize();
|
||||
DLog( "mdllib", 3, " Stripped %d vhv bytes.\n", vhvRemove.GetNumBytesRemoved() );
|
||||
|
||||
// Verts must be aligned from hdr, length must be aligned from hdr
|
||||
size_t vhvNewVertOffset = vhvRemove.ComputeOffset( vhvHdr, vhvVertOffset );
|
||||
size_t vhvAlignedVertOffset = ALIGN_VALUE( vhvNewVertOffset, 4 );
|
||||
|
||||
ITERATE_CHILDREN( HardwareVerts::MeshHeader_t, vhvMesh, vhvHdr, pMesh, m_nMeshes )
|
||||
vhvMesh->m_nOffset = vhvRemove.ComputeOffset( vhvHdr, vhvMesh->m_nOffset ) + vhvAlignedVertOffset - vhvNewVertOffset;
|
||||
ITERATE_END
|
||||
vhvHdr->m_nMeshes -= numMeshesRemoved;
|
||||
vhvHdr->m_nVertexes -= numVertsRemoved;
|
||||
|
||||
// Remove the memory
|
||||
vhvRemove.MemMove( vhvHdr, vhvLength ); // All padding has been removed
|
||||
|
||||
size_t numBytesNewLength = vhvLength + vhvAlignedVertOffset - vhvNewVertOffset;
|
||||
size_t numAlignedNewLength = ALIGN_VALUE( numBytesNewLength, 4 );
|
||||
|
||||
// Now reinsert the padding
|
||||
CInsertionTracker vhvInsertPadding;
|
||||
vhvInsertPadding.InsertBytes( BYTE_OFF_PTR( vhvHdr, vhvNewVertOffset ), vhvAlignedVertOffset - vhvNewVertOffset );
|
||||
vhvInsertPadding.InsertBytes( BYTE_OFF_PTR( vhvHdr, vhvLength ), numAlignedNewLength - numBytesNewLength );
|
||||
|
||||
vhvInsertPadding.Finalize();
|
||||
DLog( "mdllib", 3, " Inserted %d alignment bytes.\n", vhvInsertPadding.GetNumBytesInserted() );
|
||||
|
||||
vhvInsertPadding.MemMove( vhvHdr, vhvLength );
|
||||
|
||||
|
||||
// Update the buffer length
|
||||
vhvBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, vhvBuffer.TellGet() + vhvLength - vhvBuffer.TellPut() );
|
||||
|
||||
DLog( "mdllib", 2, " Reduced vhv buffer by %d bytes.\n", vhvRemove.GetNumBytesRemoved() - vhvInsertPadding.GetNumBytesInserted() );
|
||||
|
||||
// Done
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// StripModelBuffer
|
||||
// The main function that strips the mdl buffer
|
||||
// mdlBuffer - mdl buffer, updated
|
||||
//
|
||||
bool CMdlStripInfo::StripModelBuffer( CUtlBuffer &mdlBuffer )
|
||||
{
|
||||
if ( m_eMode == MODE_UNINITIALIZED )
|
||||
return false;
|
||||
|
||||
//
|
||||
// Recover mdl header
|
||||
//
|
||||
DECLARE_PTR( studiohdr_t, mdlHdr, BYTE_OFF_PTR( mdlBuffer.Base(), mdlBuffer.TellGet() ) );
|
||||
|
||||
if ( mdlHdr->checksum != m_lChecksumOld )
|
||||
{
|
||||
DLog( "mdllib", 1, "ERROR: [StripModelBuffer] checksum mismatch!\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
mdlHdr->checksum = m_lChecksumNew;
|
||||
|
||||
|
||||
// No remapping required
|
||||
if ( m_eMode == MODE_NO_CHANGE )
|
||||
return true;
|
||||
|
||||
|
||||
Assert( m_eMode == MODE_STRIP_LOD_1N );
|
||||
|
||||
|
||||
//
|
||||
// Do the model buffer stripping
|
||||
//
|
||||
|
||||
CUtlSortVector< unsigned short, CLessSimple< unsigned short > > &srcIndices = m_vtxIndices;
|
||||
|
||||
ITERATE_CHILDREN( mstudiobodyparts_t, mdlBodyPart, mdlHdr, pBodypart, numbodyparts )
|
||||
ITERATE_CHILDREN( mstudiomodel_t, mdlModel, mdlBodyPart, pModel, nummodels )
|
||||
|
||||
DLog( "mdllib", 3, " Stripped %d vertexes (was: %d, now: %d).\n", mdlModel->numvertices - srcIndices.Count(), mdlModel->numvertices, srcIndices.Count() );
|
||||
|
||||
mdlModel->numvertices = srcIndices.Count();
|
||||
|
||||
ITERATE_CHILDREN( mstudiomesh_t, mdlMesh, mdlModel, pMesh, nummeshes )
|
||||
|
||||
mdlMesh->numvertices = srcIndices.FindLess( mdlMesh->vertexoffset + mdlMesh->numvertices );
|
||||
mdlMesh->vertexoffset = srcIndices.FindLess( mdlMesh->vertexoffset ) + 1;
|
||||
mdlMesh->numvertices -= mdlMesh->vertexoffset - 1;
|
||||
|
||||
// Truncate the number of vertexes
|
||||
for ( int k = 0; k < ARRAYSIZE( mdlMesh->vertexdata.numLODVertexes ); ++ k )
|
||||
mdlMesh->vertexdata.numLODVertexes[ k ] = mdlMesh->numvertices;
|
||||
|
||||
ITERATE_END
|
||||
ITERATE_END
|
||||
ITERATE_END
|
||||
|
||||
//
|
||||
// Update bones not to mention anything below LOD0
|
||||
//
|
||||
ITERATE_CHILDREN( mstudiobone_t, mdlBone, mdlHdr, pBone, numbones )
|
||||
mdlBone->flags &= ( BONE_USED_BY_VERTEX_LOD0 | ~BONE_USED_BY_VERTEX_MASK );
|
||||
ITERATE_END
|
||||
|
||||
DLog( "mdllib", 3, " Updated %d bone(s).\n", mdlHdr->numbones );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// StripVertexDataBuffer
|
||||
// The main function that strips the vvd buffer
|
||||
// vvdBuffer - vvd buffer, updated, size reduced
|
||||
//
|
||||
bool CMdlStripInfo::StripVertexDataBuffer( CUtlBuffer &vvdBuffer )
|
||||
{
|
||||
if ( m_eMode == MODE_UNINITIALIZED )
|
||||
return false;
|
||||
|
||||
//
|
||||
// Recover vvd header
|
||||
//
|
||||
DECLARE_PTR( vertexFileHeader_t, vvdHdr, BYTE_OFF_PTR( vvdBuffer.Base(), vvdBuffer.TellGet() ) );
|
||||
int vvdLength = vvdBuffer.TellPut() - vvdBuffer.TellGet();
|
||||
|
||||
if ( vvdHdr->checksum != m_lChecksumOld )
|
||||
{
|
||||
DLog( "mdllib", 1, "ERROR: [StripVertexDataBuffer] checksum mismatch!\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
vvdHdr->checksum = m_lChecksumNew;
|
||||
|
||||
|
||||
// No remapping required
|
||||
if ( m_eMode == MODE_NO_CHANGE )
|
||||
return true;
|
||||
|
||||
|
||||
Assert( m_eMode == MODE_STRIP_LOD_1N );
|
||||
|
||||
|
||||
//
|
||||
// Do the vertex data buffer stripping
|
||||
//
|
||||
|
||||
CUtlSortVector< unsigned short, CLessSimple< unsigned short > > &srcIndices = m_vtxIndices;
|
||||
int mdlNumVerticesOld = vvdHdr->numLODVertexes[ 0 ];
|
||||
|
||||
vvdHdr->numLODs = 1;
|
||||
for ( int k = 0; k < ARRAYSIZE( vvdHdr->numLODVertexes ); ++ k )
|
||||
vvdHdr->numLODVertexes[ k ] = srcIndices.Count();
|
||||
|
||||
DECLARE_PTR( mstudiovertex_t, vvdVertexSrc, BYTE_OFF_PTR( vvdHdr, vvdHdr->vertexDataStart ) );
|
||||
DECLARE_PTR( Vector4D, vvdTangentSrc, vvdHdr->tangentDataStart ? BYTE_OFF_PTR( vvdHdr, vvdHdr->tangentDataStart ) : NULL );
|
||||
|
||||
// Apply the fixups first of all
|
||||
if ( vvdHdr->numFixups )
|
||||
{
|
||||
CArrayAutoPtr< byte > memTempVVD( new byte[ vvdLength ] );
|
||||
DECLARE_PTR( mstudiovertex_t, vvdVertexNew, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->vertexDataStart ) );
|
||||
DECLARE_PTR( Vector4D, vvdTangentNew, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->tangentDataStart ) );
|
||||
DECLARE_PTR( vertexFileFixup_t, vvdFixup, BYTE_OFF_PTR( vvdHdr, vvdHdr->fixupTableStart ) );
|
||||
for ( int k = 0; k < vvdHdr->numFixups; ++ k )
|
||||
{
|
||||
memcpy( vvdVertexNew, vvdVertexSrc + vvdFixup[ k ].sourceVertexID, vvdFixup[ k ].numVertexes * sizeof( *vvdVertexNew ) );
|
||||
vvdVertexNew += vvdFixup[ k ].numVertexes;
|
||||
if ( vvdTangentSrc )
|
||||
{
|
||||
memcpy( vvdTangentNew, vvdTangentSrc + vvdFixup[ k ].sourceVertexID, vvdFixup[ k ].numVertexes * sizeof( *vvdTangentNew ) );
|
||||
vvdTangentNew += vvdFixup[ k ].numVertexes;
|
||||
}
|
||||
}
|
||||
|
||||
// Move back the memory after fixups were applied
|
||||
vvdVertexSrc ? memcpy( vvdVertexSrc, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->vertexDataStart ), mdlNumVerticesOld * sizeof( *vvdVertexSrc ) ) : 0;
|
||||
vvdTangentSrc ? memcpy( vvdTangentSrc, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->tangentDataStart ), mdlNumVerticesOld * sizeof( *vvdTangentSrc ) ) : 0;
|
||||
}
|
||||
|
||||
vvdHdr->vertexDataStart -= ALIGN_VALUE( sizeof( vertexFileFixup_t ) * vvdHdr->numFixups, 16 );
|
||||
vvdHdr->numFixups = 0;
|
||||
DECLARE_PTR( mstudiovertex_t, vvdVertexNew, BYTE_OFF_PTR( vvdHdr, vvdHdr->vertexDataStart ) );
|
||||
for ( int k = 0; k < srcIndices.Count(); ++ k )
|
||||
vvdVertexNew[ k ] = vvdVertexSrc[ srcIndices[ k ] ];
|
||||
|
||||
size_t newVertexDataSize = srcIndices.Count() * sizeof( mstudiovertex_t );
|
||||
int vvdLengthOld = vvdLength;
|
||||
vvdLength = vvdHdr->vertexDataStart + newVertexDataSize;
|
||||
|
||||
if ( vvdTangentSrc )
|
||||
{
|
||||
// Move the tangents
|
||||
vvdHdr->tangentDataStart = vvdLength;
|
||||
DECLARE_PTR( Vector4D, vvdTangentNew, BYTE_OFF_PTR( vvdHdr, vvdHdr->tangentDataStart ) );
|
||||
|
||||
for ( int k = 0; k < srcIndices.Count(); ++ k )
|
||||
vvdTangentNew[ k ] = vvdTangentSrc[ srcIndices[ k ] ];
|
||||
|
||||
vvdLength += srcIndices.Count() * sizeof( Vector4D );
|
||||
}
|
||||
|
||||
vvdBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, vvdBuffer.TellGet() + vvdLength - vvdBuffer.TellPut() );
|
||||
|
||||
DLog( "mdllib", 3, " Stripped %d vvd bytes.\n", vvdLengthOld - vvdLength );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// StripOptimizedModelBuffer
|
||||
// The main function that strips the vtx buffer
|
||||
// vtxBuffer - vtx buffer, updated, size reduced
|
||||
//
|
||||
bool CMdlStripInfo::StripOptimizedModelBuffer( CUtlBuffer &vtxBuffer )
|
||||
{
|
||||
if ( m_eMode == MODE_UNINITIALIZED )
|
||||
return false;
|
||||
|
||||
//
|
||||
// Recover vtx header
|
||||
//
|
||||
DECLARE_PTR( OptimizedModel::FileHeader_t, vtxHdr, BYTE_OFF_PTR( vtxBuffer.Base(), vtxBuffer.TellGet() ) );
|
||||
int vtxLength = vtxBuffer.TellPut() - vtxBuffer.TellGet();
|
||||
|
||||
if ( vtxHdr->checkSum != m_lChecksumOld )
|
||||
{
|
||||
DLog( "mdllib", 1, "ERROR: [StripOptimizedModelBuffer] checksum mismatch!\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
vtxHdr->checkSum = m_lChecksumNew;
|
||||
|
||||
// No remapping required
|
||||
if ( m_eMode == MODE_NO_CHANGE )
|
||||
return true;
|
||||
|
||||
Assert( m_eMode == MODE_STRIP_LOD_1N );
|
||||
|
||||
|
||||
//
|
||||
// Do the optimized model buffer stripping
|
||||
//
|
||||
|
||||
CUtlSortVector< unsigned short, CLessSimple< unsigned short > > &srcIndices = m_vtxIndices;
|
||||
CUtlSortVector< CMdlStripInfo::MdlRangeItem, CLessSimple< CMdlStripInfo::MdlRangeItem > > &arrMdlOffsets = m_vtxMdlOffsets;
|
||||
|
||||
size_t vtxOffIndexBuffer = ~size_t(0), vtxOffIndexBufferEnd = 0;
|
||||
size_t vtxOffVertexBuffer = ~size_t(0), vtxOffVertexBufferEnd = 0;
|
||||
CRemoveTracker vtxRemove;
|
||||
CUtlVector< size_t > vtxOffIndex;
|
||||
CUtlVector< size_t > vtxOffVertex;
|
||||
|
||||
vtxRemove.RemoveElements( CHILD_AT( vtxHdr, pMaterialReplacementList, 1 ), vtxHdr->numLODs - 1 );
|
||||
ITERATE_CHILDREN( OptimizedModel::MaterialReplacementListHeader_t, vtxMatList, vtxHdr, pMaterialReplacementList, numLODs )
|
||||
if ( !vtxMatList_idx ) continue;
|
||||
vtxRemove.RemoveElements( CHILD_AT( vtxMatList, pMaterialReplacement, 0 ), vtxMatList->numReplacements );
|
||||
ITERATE_CHILDREN( OptimizedModel::MaterialReplacementHeader_t, vtxMat, vtxMatList, pMaterialReplacement, numReplacements )
|
||||
char const *szName = vtxMat->pMaterialReplacementName();
|
||||
vtxRemove.RemoveElements( szName, szName ? strlen( szName ) + 1 : 0 );
|
||||
ITERATE_END
|
||||
ITERATE_END
|
||||
|
||||
ITERATE_CHILDREN( OptimizedModel::BodyPartHeader_t, vtxBodyPart, vtxHdr, pBodyPart, numBodyParts )
|
||||
ITERATE_CHILDREN( OptimizedModel::ModelHeader_t, vtxModel, vtxBodyPart, pModel, numModels )
|
||||
|
||||
vtxRemove.RemoveElements( CHILD_AT( vtxModel, pLOD, 1 ), vtxModel->numLODs - 1 );
|
||||
ITERATE_CHILDREN( OptimizedModel::ModelLODHeader_t, vtxLod, vtxModel, pLOD, numLODs )
|
||||
if ( !vtxLod_idx ) // Process only lod1-N
|
||||
continue;
|
||||
|
||||
vtxRemove.RemoveElements( CHILD_AT( vtxLod, pMesh, 0 ), vtxLod->numMeshes );
|
||||
ITERATE_CHILDREN( OptimizedModel::MeshHeader_t, vtxMesh, vtxLod, pMesh, numMeshes )
|
||||
vtxRemove.RemoveElements( CHILD_AT( vtxMesh, pStripGroup, 0 ), vtxMesh->numStripGroups );
|
||||
ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
|
||||
vtxRemove.RemoveElements( CHILD_AT( vtxStripGroup, pStrip, 0 ), vtxStripGroup->numStrips );
|
||||
ITERATE_CHILDREN( OptimizedModel::StripHeader_t, vtxStrip, vtxStripGroup, pStrip, numStrips )
|
||||
vtxRemove.RemoveElements( CHILD_AT( vtxStrip, pBoneStateChange, 0 ), vtxStrip->numBoneStateChanges );
|
||||
ITERATE_END
|
||||
ITERATE_END
|
||||
ITERATE_END
|
||||
|
||||
ITERATE_END
|
||||
|
||||
// Use all lods to determine the ranges of vertex and index buffers.
|
||||
// We rely on the fact that vertex and index buffers are laid out as one solid memory block for all lods.
|
||||
ITERATE_CHILDREN( OptimizedModel::ModelLODHeader_t, vtxLod, vtxModel, pLOD, numLODs )
|
||||
ITERATE_CHILDREN( OptimizedModel::MeshHeader_t, vtxMesh, vtxLod, pMesh, numMeshes )
|
||||
ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
|
||||
|
||||
size_t offIndex = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pIndex, 0 ) );
|
||||
size_t offIndexEnd = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pIndex, vtxStripGroup->numIndices ) );
|
||||
size_t offVertex = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pVertex, 0 ) );
|
||||
size_t offVertexEnd = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pVertex, vtxStripGroup->numVerts ) );
|
||||
|
||||
if ( offIndex < vtxOffIndexBuffer )
|
||||
vtxOffIndexBuffer = offIndex;
|
||||
if ( offIndexEnd > vtxOffIndexBufferEnd )
|
||||
vtxOffIndexBufferEnd = offIndexEnd;
|
||||
if ( offVertex < vtxOffVertexBuffer )
|
||||
vtxOffVertexBuffer = offVertex;
|
||||
if ( offVertexEnd > vtxOffVertexBufferEnd )
|
||||
vtxOffVertexBufferEnd = offVertexEnd;
|
||||
|
||||
if ( !vtxLod_idx )
|
||||
{
|
||||
vtxOffIndex.AddToTail( offIndex );
|
||||
vtxOffIndex.AddToTail( offIndexEnd );
|
||||
vtxOffVertex.AddToTail( offVertex );
|
||||
vtxOffVertex.AddToTail( offVertexEnd );
|
||||
}
|
||||
|
||||
ITERATE_END
|
||||
ITERATE_END
|
||||
ITERATE_END
|
||||
|
||||
ITERATE_END
|
||||
ITERATE_END
|
||||
|
||||
// Fixup the vertex buffer
|
||||
DECLARE_PTR( OptimizedModel::Vertex_t, vtxVertexBuffer, BYTE_OFF_PTR( vtxHdr, vtxOffVertexBuffer ) );
|
||||
DECLARE_PTR( OptimizedModel::Vertex_t, vtxVertexBufferEnd, BYTE_OFF_PTR( vtxHdr, vtxOffVertexBufferEnd ) );
|
||||
CUtlVector< int > vtxIndexDeltas;
|
||||
vtxIndexDeltas.EnsureCapacity( vtxVertexBufferEnd - vtxVertexBuffer );
|
||||
int vtxNumVertexRemoved = 0;
|
||||
for ( OptimizedModel::Vertex_t *vtxVertexElement = vtxVertexBuffer; vtxVertexElement < vtxVertexBufferEnd; ++ vtxVertexElement )
|
||||
{
|
||||
size_t const off = BYTE_DIFF_PTR( vtxHdr, vtxVertexElement );
|
||||
bool bUsed = false;
|
||||
for ( int k = 0; k < vtxOffVertex.Count(); k += 2 )
|
||||
{
|
||||
if ( off >= vtxOffVertex[ k ] && off < vtxOffVertex[ k + 1 ] )
|
||||
{
|
||||
bUsed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !bUsed )
|
||||
{
|
||||
// Index is not in use
|
||||
vtxRemove.RemoveElements( vtxVertexElement );
|
||||
vtxIndexDeltas.AddToTail( 0 );
|
||||
vtxNumVertexRemoved ++;
|
||||
}
|
||||
else
|
||||
{ // Index is in use and must be remapped
|
||||
// Find the mesh where this index belongs
|
||||
int iMesh = arrMdlOffsets.FindLessOrEqual( MdlRangeItem( 0, 0, vtxVertexElement - vtxVertexBuffer ) );
|
||||
Assert( iMesh >= 0 && iMesh < arrMdlOffsets.Count() );
|
||||
|
||||
MdlRangeItem &mri = arrMdlOffsets[ iMesh ];
|
||||
Assert( ( vtxVertexElement - vtxVertexBuffer >= mri.m_offNew ) && ( vtxVertexElement - vtxVertexBuffer < mri.m_offNew + mri.m_numNew ) );
|
||||
|
||||
Assert( m_vtxVerts.IsBitSet( vtxVertexElement->origMeshVertID + mri.m_offOld ) );
|
||||
vtxVertexElement->origMeshVertID = srcIndices.Find( vtxVertexElement->origMeshVertID + mri.m_offOld ) - mri.m_offNew;
|
||||
Assert( vtxVertexElement->origMeshVertID < mri.m_numNew );
|
||||
vtxIndexDeltas.AddToTail( vtxNumVertexRemoved );
|
||||
}
|
||||
}
|
||||
|
||||
// Fixup the index buffer
|
||||
DECLARE_PTR( unsigned short, vtxIndexBuffer, BYTE_OFF_PTR( vtxHdr, vtxOffIndexBuffer ) );
|
||||
DECLARE_PTR( unsigned short, vtxIndexBufferEnd, BYTE_OFF_PTR( vtxHdr, vtxOffIndexBufferEnd ) );
|
||||
for ( unsigned short *vtxIndexElement = vtxIndexBuffer; vtxIndexElement < vtxIndexBufferEnd; ++ vtxIndexElement )
|
||||
{
|
||||
size_t const off = BYTE_DIFF_PTR( vtxHdr, vtxIndexElement );
|
||||
bool bUsed = false;
|
||||
for ( int k = 0; k < vtxOffIndex.Count(); k += 2 )
|
||||
{
|
||||
if ( off >= vtxOffIndex[ k ] && off < vtxOffIndex[ k + 1 ] )
|
||||
{
|
||||
bUsed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !bUsed )
|
||||
{
|
||||
// Index is not in use
|
||||
vtxRemove.RemoveElements( vtxIndexElement );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Index is in use and must be remapped
|
||||
*vtxIndexElement -= vtxIndexDeltas[ *vtxIndexElement ];
|
||||
}
|
||||
}
|
||||
|
||||
// By now should have scheduled all removal information
|
||||
vtxRemove.Finalize();
|
||||
DLog( "mdllib", 3, " Stripped %d vtx bytes.\n", vtxRemove.GetNumBytesRemoved() );
|
||||
|
||||
//
|
||||
// Fixup all the offsets
|
||||
//
|
||||
ITERATE_CHILDREN( OptimizedModel::MaterialReplacementListHeader_t, vtxMatList, vtxHdr, pMaterialReplacementList, numLODs )
|
||||
ITERATE_CHILDREN( OptimizedModel::MaterialReplacementHeader_t, vtxMat, vtxMatList, pMaterialReplacement, numReplacements )
|
||||
vtxMat->replacementMaterialNameOffset = vtxRemove.ComputeOffset( vtxMat, vtxMat->replacementMaterialNameOffset );
|
||||
ITERATE_END
|
||||
vtxMatList->replacementOffset = vtxRemove.ComputeOffset( vtxMatList, vtxMatList->replacementOffset );
|
||||
ITERATE_END
|
||||
ITERATE_CHILDREN( OptimizedModel::BodyPartHeader_t, vtxBodyPart, vtxHdr, pBodyPart, numBodyParts )
|
||||
ITERATE_CHILDREN( OptimizedModel::ModelHeader_t, vtxModel, vtxBodyPart, pModel, numModels )
|
||||
ITERATE_CHILDREN( OptimizedModel::ModelLODHeader_t, vtxLod, vtxModel, pLOD, numLODs )
|
||||
ITERATE_CHILDREN( OptimizedModel::MeshHeader_t, vtxMesh, vtxLod, pMesh, numMeshes )
|
||||
ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
|
||||
|
||||
ITERATE_CHILDREN( OptimizedModel::StripHeader_t, vtxStrip, vtxStripGroup, pStrip, numStrips )
|
||||
vtxStrip->indexOffset =
|
||||
vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->indexOffset + vtxStrip->indexOffset ) -
|
||||
vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->indexOffset );
|
||||
vtxStrip->vertOffset =
|
||||
vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->vertOffset + vtxStrip->vertOffset ) -
|
||||
vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->vertOffset );
|
||||
vtxStrip->boneStateChangeOffset = vtxRemove.ComputeOffset( vtxStrip, vtxStrip->boneStateChangeOffset );
|
||||
ITERATE_END
|
||||
|
||||
vtxStripGroup->vertOffset = vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->vertOffset );
|
||||
vtxStripGroup->indexOffset = vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->indexOffset );
|
||||
vtxStripGroup->stripOffset = vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->stripOffset );
|
||||
ITERATE_END
|
||||
vtxMesh->stripGroupHeaderOffset = vtxRemove.ComputeOffset( vtxMesh, vtxMesh->stripGroupHeaderOffset );
|
||||
ITERATE_END
|
||||
vtxLod->meshOffset = vtxRemove.ComputeOffset( vtxLod, vtxLod->meshOffset );
|
||||
ITERATE_END
|
||||
vtxModel->lodOffset = vtxRemove.ComputeOffset( vtxModel, vtxModel->lodOffset );
|
||||
vtxModel->numLODs = 1;
|
||||
ITERATE_END
|
||||
vtxBodyPart->modelOffset = vtxRemove.ComputeOffset( vtxBodyPart, vtxBodyPart->modelOffset );
|
||||
ITERATE_END
|
||||
vtxHdr->materialReplacementListOffset = vtxRemove.ComputeOffset( vtxHdr, vtxHdr->materialReplacementListOffset );
|
||||
vtxHdr->bodyPartOffset = vtxRemove.ComputeOffset( vtxHdr, vtxHdr->bodyPartOffset );
|
||||
vtxHdr->numLODs = 1;
|
||||
|
||||
// Perform final memory move
|
||||
vtxRemove.MemMove( vtxHdr, vtxLength );
|
||||
|
||||
vtxBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, vtxBuffer.TellGet() + vtxLength - vtxBuffer.TellPut() );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Auxilliary methods
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CMdlStripInfo::DeleteThis()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
void CMdlStripInfo::Reset()
|
||||
{
|
||||
m_eMode = MODE_UNINITIALIZED;
|
||||
m_lChecksumOld = 0;
|
||||
m_lChecksumNew = 0;
|
||||
|
||||
m_vtxVerts.Resize( 0 );
|
||||
m_vtxIndices.RemoveAll();
|
||||
}
|
||||
|
127
mdllib/mdllib_stripinfo.h
Normal file
127
mdllib/mdllib_stripinfo.h
Normal file
@ -0,0 +1,127 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef MDLLIB_STRIPINFO_H
|
||||
#define MDLLIB_STRIPINFO_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "mdllib/mdllib.h"
|
||||
#include "mdllib_utils.h"
|
||||
#include "UtlSortVector.h"
|
||||
|
||||
|
||||
//
|
||||
// CMdlStripInfo
|
||||
// Implementation of IMdlStripInfo interface
|
||||
//
|
||||
class CMdlStripInfo : public IMdlStripInfo
|
||||
{
|
||||
public:
|
||||
CMdlStripInfo();
|
||||
|
||||
//
|
||||
// Serialization
|
||||
//
|
||||
public:
|
||||
// Save the strip info to the buffer (appends to the end)
|
||||
virtual bool Serialize( CUtlBuffer &bufStorage ) const;
|
||||
|
||||
// Load the strip info from the buffer (reads from the current position as much as needed)
|
||||
virtual bool UnSerialize( CUtlBuffer &bufData );
|
||||
|
||||
//
|
||||
// Stripping info state
|
||||
//
|
||||
public:
|
||||
// Returns the checksums that the stripping info was generated for:
|
||||
// plChecksumOriginal if non-NULL will hold the checksum of the original model submitted for stripping
|
||||
// plChecksumStripped if non-NULL will hold the resulting checksum of the stripped model
|
||||
virtual bool GetCheckSum( long *plChecksumOriginal, long *plChecksumStripped ) const;
|
||||
|
||||
//
|
||||
// Stripping
|
||||
//
|
||||
public:
|
||||
|
||||
//
|
||||
// StripHardwareVertsBuffer
|
||||
// The main function that strips the vhv buffer
|
||||
// vhvBuffer - vhv buffer, updated, size reduced
|
||||
//
|
||||
virtual bool StripHardwareVertsBuffer( CUtlBuffer &vhvBuffer );
|
||||
|
||||
//
|
||||
// StripModelBuffer
|
||||
// The main function that strips the mdl buffer
|
||||
// mdlBuffer - mdl buffer, updated
|
||||
//
|
||||
virtual bool StripModelBuffer( CUtlBuffer &mdlBuffer );
|
||||
|
||||
//
|
||||
// StripVertexDataBuffer
|
||||
// The main function that strips the vvd buffer
|
||||
// vvdBuffer - vvd buffer, updated, size reduced
|
||||
//
|
||||
virtual bool StripVertexDataBuffer( CUtlBuffer &vvdBuffer );
|
||||
|
||||
//
|
||||
// StripOptimizedModelBuffer
|
||||
// The main function that strips the vtx buffer
|
||||
// vtxBuffer - vtx buffer, updated, size reduced
|
||||
//
|
||||
virtual bool StripOptimizedModelBuffer( CUtlBuffer &vtxBuffer );
|
||||
|
||||
//
|
||||
// Release the object with "delete this"
|
||||
//
|
||||
public:
|
||||
virtual void DeleteThis();
|
||||
|
||||
|
||||
|
||||
public:
|
||||
void Reset();
|
||||
|
||||
|
||||
public:
|
||||
enum Mode
|
||||
{
|
||||
MODE_UNINITIALIZED = 0,
|
||||
MODE_NO_CHANGE = 1,
|
||||
MODE_STRIP_LOD_1N = 2,
|
||||
};
|
||||
|
||||
//
|
||||
// Internal data used for stripping
|
||||
//
|
||||
public:
|
||||
int m_eMode;
|
||||
long m_lChecksumOld, m_lChecksumNew;
|
||||
CGrowableBitVec m_vtxVerts;
|
||||
CUtlSortVector< unsigned short, CLessSimple< unsigned short > > m_vtxIndices;
|
||||
|
||||
//
|
||||
// Mesh ranges fixup
|
||||
//
|
||||
public:
|
||||
struct MdlRangeItem
|
||||
{
|
||||
/* implicit */ MdlRangeItem( int offOld = 0, int numOld = 0, int offNew = 0, int numNew = 0 ) :
|
||||
m_offOld( offOld ), m_offNew( offNew ), m_numOld( numOld ), m_numNew( numNew ) {}
|
||||
|
||||
int m_offOld, m_offNew;
|
||||
int m_numOld, m_numNew;
|
||||
|
||||
bool operator < ( MdlRangeItem const &x ) const { return m_offNew < x.m_offNew; }
|
||||
};
|
||||
CUtlSortVector< CMdlStripInfo::MdlRangeItem, CLessSimple< CMdlStripInfo::MdlRangeItem > > m_vtxMdlOffsets;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // #ifndef MDLLIB_STRIPINFO_H
|
504
mdllib/mdllib_stripmodel.cpp
Normal file
504
mdllib/mdllib_stripmodel.cpp
Normal file
@ -0,0 +1,504 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "mdllib_common.h"
|
||||
#include "mdllib_stripinfo.h"
|
||||
#include "mdllib_utils.h"
|
||||
|
||||
#include "studio.h"
|
||||
#include "optimize.h"
|
||||
|
||||
#include "smartptr.h"
|
||||
|
||||
|
||||
bool CMdlLib::CreateNewStripInfo( IMdlStripInfo **ppStripInfo )
|
||||
{
|
||||
if ( !ppStripInfo )
|
||||
return false;
|
||||
|
||||
if ( *ppStripInfo )
|
||||
{
|
||||
CMdlStripInfo *pMdlStripInfo = ( CMdlStripInfo * ) ( *ppStripInfo );
|
||||
pMdlStripInfo->Reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
*ppStripInfo = new CMdlStripInfo;
|
||||
return ( NULL != *ppStripInfo );
|
||||
}
|
||||
|
||||
//
|
||||
// StripModelBuffers
|
||||
// The main function that strips the model buffers
|
||||
// mdlBuffer - mdl buffer, updated, no size change
|
||||
// vvdBuffer - vvd buffer, updated, size reduced
|
||||
// vtxBuffer - vtx buffer, updated, size reduced
|
||||
// ppStripInfo - if nonzero on return will be filled with the stripping info
|
||||
//
|
||||
bool CMdlLib::StripModelBuffers( CUtlBuffer &mdlBuffer, CUtlBuffer &vvdBuffer, CUtlBuffer &vtxBuffer, IMdlStripInfo **ppStripInfo )
|
||||
{
|
||||
DECLARE_PTR( byte, mdl, BYTE_OFF_PTR( mdlBuffer.Base(), mdlBuffer.TellGet() ) );
|
||||
DECLARE_PTR( byte, vvd, BYTE_OFF_PTR( vvdBuffer.Base(), vvdBuffer.TellGet() ) );
|
||||
DECLARE_PTR( byte, vtx, BYTE_OFF_PTR( vtxBuffer.Base(), vtxBuffer.TellGet() ) );
|
||||
|
||||
int vvdLength = vvdBuffer.TellPut() - vvdBuffer.TellGet();
|
||||
int vtxLength = vtxBuffer.TellPut() - vtxBuffer.TellGet();
|
||||
|
||||
//
|
||||
// ===================
|
||||
// =================== Modify the checksum and check if further processing is needed
|
||||
// ===================
|
||||
//
|
||||
|
||||
DECLARE_PTR( studiohdr_t, mdlHdr, mdl );
|
||||
DECLARE_PTR( vertexFileHeader_t, vvdHdr, vvd );
|
||||
DECLARE_PTR( OptimizedModel::FileHeader_t, vtxHdr, vtx );
|
||||
|
||||
long checksumOld = mdlHdr->checksum;
|
||||
|
||||
// Don't do anything if the checksums don't match
|
||||
if ( ( mdlHdr->checksum != vvdHdr->checksum ) ||
|
||||
( mdlHdr->checksum != vtxHdr->checkSum ) )
|
||||
{
|
||||
DLog( "mdllib", 1, "ERROR: [StripModelBuffers] checksum mismatch!\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Modify the checksums
|
||||
mdlHdr->checksum ^= ( mdlHdr->checksum * 123457 );
|
||||
vvdHdr->checksum ^= ( vvdHdr->checksum * 123457 );
|
||||
vtxHdr->checkSum ^= ( vtxHdr->checkSum * 123457 );
|
||||
|
||||
long checksumNew = mdlHdr->checksum;
|
||||
|
||||
// Allocate the model stripping info
|
||||
CMdlStripInfo msi;
|
||||
CMdlStripInfo *pMsi;
|
||||
|
||||
if ( ppStripInfo )
|
||||
{
|
||||
if ( *ppStripInfo )
|
||||
{
|
||||
pMsi = ( CMdlStripInfo * ) ( *ppStripInfo );
|
||||
pMsi->Reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppStripInfo = pMsi = new CMdlStripInfo;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pMsi = &msi;
|
||||
}
|
||||
|
||||
// Set the basic stripping info settings
|
||||
pMsi->m_lChecksumOld = checksumOld;
|
||||
pMsi->m_lChecksumNew = checksumNew;
|
||||
|
||||
//
|
||||
// Early outs
|
||||
//
|
||||
|
||||
if ( !( mdlHdr->flags & STUDIOHDR_FLAGS_STATIC_PROP ) )
|
||||
{
|
||||
DLog( "mdllib", 2, "No special stripping - the model is not a static prop.\n" );
|
||||
pMsi->m_eMode = CMdlStripInfo::MODE_NO_CHANGE;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( vvdHdr->numLODs <= 1 )
|
||||
{
|
||||
DLog( "mdllib", 2, "No special stripping - the model has only %d lod(s).\n", vvdHdr->numLODs );
|
||||
pMsi->m_eMode = CMdlStripInfo::MODE_NO_CHANGE;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( mdlHdr->numbones != 1 )
|
||||
{
|
||||
DLog( "mdllib", 2, "No special stripping - the model has %d bone(s).\n", mdlHdr->numbones );
|
||||
pMsi->m_eMode = CMdlStripInfo::MODE_NO_CHANGE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise do stripping
|
||||
pMsi->m_eMode = CMdlStripInfo::MODE_STRIP_LOD_1N;
|
||||
|
||||
|
||||
//
|
||||
// ===================
|
||||
// =================== Build out table of LOD0 vertexes
|
||||
// ===================
|
||||
//
|
||||
|
||||
CGrowableBitVec &mapVtxIndex = pMsi->m_vtxVerts;
|
||||
ITERATE_CHILDREN2( OptimizedModel::BodyPartHeader_t, mstudiobodyparts_t, vtxBodyPart, mdlBodyPart, vtxHdr, mdlHdr, pBodyPart, pBodypart, numBodyParts )
|
||||
ITERATE_CHILDREN2( OptimizedModel::ModelHeader_t, mstudiomodel_t, vtxModel, mdlModel, vtxBodyPart, mdlBodyPart, pModel, pModel, numModels )
|
||||
|
||||
OptimizedModel::ModelLODHeader_t *vtxLod = CHILD_AT( vtxModel, pLOD, 0 );
|
||||
ITERATE_CHILDREN2( OptimizedModel::MeshHeader_t, mstudiomesh_t, vtxMesh, mdlMesh, vtxLod, mdlModel, pMesh, pMesh, numMeshes )
|
||||
ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
|
||||
ITERATE_CHILDREN( OptimizedModel::StripHeader_t, vtxStrip, vtxStripGroup, pStrip, numStrips )
|
||||
|
||||
if ( !( vtxStrip->flags & OptimizedModel::STRIP_IS_TRILIST ) )
|
||||
continue;
|
||||
for ( int i = 0; i < vtxStrip->numIndices; ++ i )
|
||||
{
|
||||
unsigned short *vtxIdx = CHILD_AT( vtxStripGroup, pIndex, vtxStrip->indexOffset + i );
|
||||
OptimizedModel::Vertex_t *vtxVertex = CHILD_AT( vtxStripGroup, pVertex, *vtxIdx );
|
||||
|
||||
unsigned short usIdx = vtxVertex->origMeshVertID + mdlMesh->vertexoffset;
|
||||
mapVtxIndex.GrowSetBit( usIdx );
|
||||
}
|
||||
|
||||
ITERATE_END
|
||||
ITERATE_END
|
||||
ITERATE_END
|
||||
|
||||
ITERATE_END
|
||||
ITERATE_END
|
||||
|
||||
//
|
||||
// Now having the table of which vertexes to keep we will construct a remapping table
|
||||
//
|
||||
CUtlSortVector< unsigned short, CLessSimple< unsigned short > > &srcIndices = pMsi->m_vtxIndices;
|
||||
srcIndices.EnsureCapacity( mapVtxIndex.GetNumBits() );
|
||||
for ( int iBit = -1; ( iBit = mapVtxIndex.FindNextSetBit( iBit + 1 ) ) >= 0; )
|
||||
srcIndices.InsertNoSort( ( unsigned short ) ( unsigned int ) iBit );
|
||||
srcIndices.RedoSort(); // - doesn't do anything, just validates the vector
|
||||
|
||||
// Now we have the following questions answered:
|
||||
// - for every index we know if it belongs to lod0 "mapVtxIndex.IsBitSet( oldVertIdx )"
|
||||
// - for every new vertex we know its old index "srcIndices[ newVertIdx ]"
|
||||
// - for every old vertex if it's in lod0 we know its new index "srcIndices.Find( oldVertIdx )"
|
||||
|
||||
|
||||
//
|
||||
// ===================
|
||||
// =================== Process MDL file
|
||||
// ===================
|
||||
//
|
||||
|
||||
//
|
||||
// Update vertex counts
|
||||
//
|
||||
int mdlNumVerticesOld = 0;
|
||||
CUtlSortVector< CMdlStripInfo::MdlRangeItem, CLessSimple< CMdlStripInfo::MdlRangeItem > > &arrMdlOffsets = pMsi->m_vtxMdlOffsets;
|
||||
ITERATE_CHILDREN( mstudiobodyparts_t, mdlBodyPart, mdlHdr, pBodypart, numbodyparts )
|
||||
ITERATE_CHILDREN( mstudiomodel_t, mdlModel, mdlBodyPart, pModel, nummodels )
|
||||
|
||||
DLog( "mdllib", 3, " Stripped %d lod(s).\n", vvdHdr->numLODs - 1 ),
|
||||
DLog( "mdllib", 3, " Stripped %d vertexes (was: %d, now: %d).\n", mdlModel->numvertices - srcIndices.Count(), mdlModel->numvertices, srcIndices.Count() );
|
||||
|
||||
mdlNumVerticesOld = mdlModel->numvertices;
|
||||
mdlModel->numvertices = srcIndices.Count();
|
||||
|
||||
mdlModel->vertexdata.pVertexData = BYTE_OFF_PTR( vvdHdr, vvdHdr->vertexDataStart );
|
||||
mdlModel->vertexdata.pTangentData = BYTE_OFF_PTR( vvdHdr, vvdHdr->tangentDataStart );
|
||||
|
||||
ITERATE_CHILDREN( mstudiomesh_t, mdlMesh, mdlModel, pMesh, nummeshes )
|
||||
|
||||
CMdlStripInfo::MdlRangeItem mdlRangeItem( mdlMesh->vertexoffset, mdlMesh->numvertices );
|
||||
|
||||
mdlMesh->vertexdata.modelvertexdata = &mdlModel->vertexdata;
|
||||
mdlMesh->numvertices = srcIndices.FindLess( mdlMesh->vertexoffset + mdlMesh->numvertices );
|
||||
mdlMesh->vertexoffset = srcIndices.FindLess( mdlMesh->vertexoffset ) + 1;
|
||||
mdlMesh->numvertices -= mdlMesh->vertexoffset - 1;
|
||||
|
||||
mdlRangeItem.m_offNew = mdlMesh->vertexoffset;
|
||||
mdlRangeItem.m_numNew = mdlMesh->numvertices;
|
||||
arrMdlOffsets.Insert( mdlRangeItem );
|
||||
|
||||
// Truncate the number of vertexes
|
||||
for ( int k = 0; k < ARRAYSIZE( mdlMesh->vertexdata.numLODVertexes ); ++ k )
|
||||
mdlMesh->vertexdata.numLODVertexes[ k ] = mdlMesh->numvertices;
|
||||
|
||||
ITERATE_END
|
||||
ITERATE_END
|
||||
ITERATE_END
|
||||
|
||||
//
|
||||
// Update bones not to mention anything below LOD0
|
||||
//
|
||||
ITERATE_CHILDREN( mstudiobone_t, mdlBone, mdlHdr, pBone, numbones )
|
||||
mdlBone->flags &= ( BONE_USED_BY_VERTEX_LOD0 | ~BONE_USED_BY_VERTEX_MASK );
|
||||
ITERATE_END
|
||||
|
||||
DLog( "mdllib", 3, " Updated %d bone(s).\n", mdlHdr->numbones );
|
||||
|
||||
|
||||
//
|
||||
// ===================
|
||||
// =================== Process VVD file
|
||||
// ===================
|
||||
//
|
||||
|
||||
vvdHdr->numLODs = 1;
|
||||
for ( int k = 0; k < ARRAYSIZE( vvdHdr->numLODVertexes ); ++ k )
|
||||
vvdHdr->numLODVertexes[ k ] = srcIndices.Count();
|
||||
|
||||
DECLARE_PTR( mstudiovertex_t, vvdVertexSrc, BYTE_OFF_PTR( vvdHdr, vvdHdr->vertexDataStart ) );
|
||||
DECLARE_PTR( Vector4D, vvdTangentSrc, vvdHdr->tangentDataStart ? BYTE_OFF_PTR( vvdHdr, vvdHdr->tangentDataStart ) : NULL );
|
||||
|
||||
// Apply the fixups first of all
|
||||
if ( vvdHdr->numFixups )
|
||||
{
|
||||
CArrayAutoPtr< byte > memTempVVD( new byte[ vvdLength ] );
|
||||
DECLARE_PTR( mstudiovertex_t, vvdVertexNew, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->vertexDataStart ) );
|
||||
DECLARE_PTR( Vector4D, vvdTangentNew, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->tangentDataStart ) );
|
||||
DECLARE_PTR( vertexFileFixup_t, vvdFixup, BYTE_OFF_PTR( vvdHdr, vvdHdr->fixupTableStart ) );
|
||||
for ( int k = 0; k < vvdHdr->numFixups; ++ k )
|
||||
{
|
||||
memcpy( vvdVertexNew, vvdVertexSrc + vvdFixup[ k ].sourceVertexID, vvdFixup[ k ].numVertexes * sizeof( *vvdVertexNew ) );
|
||||
vvdVertexNew += vvdFixup[ k ].numVertexes;
|
||||
if ( vvdTangentSrc )
|
||||
{
|
||||
memcpy( vvdTangentNew, vvdTangentSrc + vvdFixup[ k ].sourceVertexID, vvdFixup[ k ].numVertexes * sizeof( *vvdTangentNew ) );
|
||||
vvdTangentNew += vvdFixup[ k ].numVertexes;
|
||||
}
|
||||
}
|
||||
|
||||
// Move back the memory after fixups were applied
|
||||
vvdVertexSrc ? memcpy( vvdVertexSrc, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->vertexDataStart ), mdlNumVerticesOld * sizeof( *vvdVertexSrc ) ) : 0;
|
||||
vvdTangentSrc ? memcpy( vvdTangentSrc, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->tangentDataStart ), mdlNumVerticesOld * sizeof( *vvdTangentSrc ) ) : 0;
|
||||
}
|
||||
|
||||
vvdHdr->vertexDataStart -= ALIGN_VALUE( sizeof( vertexFileFixup_t ) * vvdHdr->numFixups, 16 );
|
||||
vvdHdr->numFixups = 0;
|
||||
DECLARE_PTR( mstudiovertex_t, vvdVertexNew, BYTE_OFF_PTR( vvdHdr, vvdHdr->vertexDataStart ) );
|
||||
for ( int k = 0; k < srcIndices.Count(); ++ k )
|
||||
vvdVertexNew[ k ] = vvdVertexSrc[ srcIndices[ k ] ];
|
||||
|
||||
size_t newVertexDataSize = srcIndices.Count() * sizeof( mstudiovertex_t );
|
||||
int vvdLengthOld = vvdLength;
|
||||
vvdLength = vvdHdr->vertexDataStart + newVertexDataSize;
|
||||
|
||||
if ( vvdTangentSrc )
|
||||
{
|
||||
// Move the tangents
|
||||
vvdHdr->tangentDataStart = vvdLength;
|
||||
DECLARE_PTR( Vector4D, vvdTangentNew, BYTE_OFF_PTR( vvdHdr, vvdHdr->tangentDataStart ) );
|
||||
|
||||
for ( int k = 0; k < srcIndices.Count(); ++ k )
|
||||
vvdTangentNew[ k ] = vvdTangentSrc[ srcIndices[ k ] ];
|
||||
|
||||
vvdLength += srcIndices.Count() * sizeof( Vector4D );
|
||||
}
|
||||
DLog( "mdllib", 3, " Stripped %d vvd bytes.\n", vvdLengthOld - vvdLength );
|
||||
|
||||
|
||||
//
|
||||
// ===================
|
||||
// =================== Process VTX file
|
||||
// ===================
|
||||
//
|
||||
|
||||
size_t vtxOffIndexBuffer = ~size_t(0), vtxOffIndexBufferEnd = 0;
|
||||
size_t vtxOffVertexBuffer = ~size_t(0), vtxOffVertexBufferEnd = 0;
|
||||
CRemoveTracker vtxRemove;
|
||||
CUtlVector< size_t > vtxOffIndex;
|
||||
CUtlVector< size_t > vtxOffVertex;
|
||||
|
||||
vtxRemove.RemoveElements( CHILD_AT( vtxHdr, pMaterialReplacementList, 1 ), vtxHdr->numLODs - 1 );
|
||||
ITERATE_CHILDREN( OptimizedModel::MaterialReplacementListHeader_t, vtxMatList, vtxHdr, pMaterialReplacementList, numLODs )
|
||||
if ( !vtxMatList_idx ) continue;
|
||||
vtxRemove.RemoveElements( CHILD_AT( vtxMatList, pMaterialReplacement, 0 ), vtxMatList->numReplacements );
|
||||
ITERATE_CHILDREN( OptimizedModel::MaterialReplacementHeader_t, vtxMat, vtxMatList, pMaterialReplacement, numReplacements )
|
||||
char const *szName = vtxMat->pMaterialReplacementName();
|
||||
vtxRemove.RemoveElements( szName, szName ? strlen( szName ) + 1 : 0 );
|
||||
ITERATE_END
|
||||
ITERATE_END
|
||||
|
||||
ITERATE_CHILDREN( OptimizedModel::BodyPartHeader_t, vtxBodyPart, vtxHdr, pBodyPart, numBodyParts )
|
||||
ITERATE_CHILDREN( OptimizedModel::ModelHeader_t, vtxModel, vtxBodyPart, pModel, numModels )
|
||||
|
||||
vtxRemove.RemoveElements( CHILD_AT( vtxModel, pLOD, 1 ), vtxModel->numLODs - 1 );
|
||||
ITERATE_CHILDREN( OptimizedModel::ModelLODHeader_t, vtxLod, vtxModel, pLOD, numLODs )
|
||||
if ( !vtxLod_idx ) // Process only lod1-N
|
||||
continue;
|
||||
|
||||
vtxRemove.RemoveElements( CHILD_AT( vtxLod, pMesh, 0 ), vtxLod->numMeshes );
|
||||
ITERATE_CHILDREN( OptimizedModel::MeshHeader_t, vtxMesh, vtxLod, pMesh, numMeshes )
|
||||
vtxRemove.RemoveElements( CHILD_AT( vtxMesh, pStripGroup, 0 ), vtxMesh->numStripGroups );
|
||||
ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
|
||||
vtxRemove.RemoveElements( CHILD_AT( vtxStripGroup, pStrip, 0 ), vtxStripGroup->numStrips );
|
||||
ITERATE_CHILDREN( OptimizedModel::StripHeader_t, vtxStrip, vtxStripGroup, pStrip, numStrips )
|
||||
vtxRemove.RemoveElements( CHILD_AT( vtxStrip, pBoneStateChange, 0 ), vtxStrip->numBoneStateChanges );
|
||||
ITERATE_END
|
||||
ITERATE_END
|
||||
ITERATE_END
|
||||
|
||||
ITERATE_END
|
||||
|
||||
// Use all lods to determine the ranges of vertex and index buffers.
|
||||
// We rely on the fact that vertex and index buffers are laid out as one solid memory block for all lods.
|
||||
ITERATE_CHILDREN( OptimizedModel::ModelLODHeader_t, vtxLod, vtxModel, pLOD, numLODs )
|
||||
ITERATE_CHILDREN( OptimizedModel::MeshHeader_t, vtxMesh, vtxLod, pMesh, numMeshes )
|
||||
ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
|
||||
|
||||
size_t offIndex = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pIndex, 0 ) );
|
||||
size_t offIndexEnd = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pIndex, vtxStripGroup->numIndices ) );
|
||||
size_t offVertex = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pVertex, 0 ) );
|
||||
size_t offVertexEnd = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pVertex, vtxStripGroup->numVerts ) );
|
||||
|
||||
if ( offIndex < vtxOffIndexBuffer )
|
||||
vtxOffIndexBuffer = offIndex;
|
||||
if ( offIndexEnd > vtxOffIndexBufferEnd )
|
||||
vtxOffIndexBufferEnd = offIndexEnd;
|
||||
if ( offVertex < vtxOffVertexBuffer )
|
||||
vtxOffVertexBuffer = offVertex;
|
||||
if ( offVertexEnd > vtxOffVertexBufferEnd )
|
||||
vtxOffVertexBufferEnd = offVertexEnd;
|
||||
|
||||
if ( !vtxLod_idx )
|
||||
{
|
||||
vtxOffIndex.AddToTail( offIndex );
|
||||
vtxOffIndex.AddToTail( offIndexEnd );
|
||||
vtxOffVertex.AddToTail( offVertex );
|
||||
vtxOffVertex.AddToTail( offVertexEnd );
|
||||
}
|
||||
|
||||
ITERATE_END
|
||||
ITERATE_END
|
||||
ITERATE_END
|
||||
|
||||
ITERATE_END
|
||||
ITERATE_END
|
||||
|
||||
// Fixup the vertex buffer
|
||||
DECLARE_PTR( OptimizedModel::Vertex_t, vtxVertexBuffer, BYTE_OFF_PTR( vtxHdr, vtxOffVertexBuffer ) );
|
||||
DECLARE_PTR( OptimizedModel::Vertex_t, vtxVertexBufferEnd, BYTE_OFF_PTR( vtxHdr, vtxOffVertexBufferEnd ) );
|
||||
CUtlVector< int > vtxIndexDeltas;
|
||||
vtxIndexDeltas.EnsureCapacity( vtxVertexBufferEnd - vtxVertexBuffer );
|
||||
int vtxNumVertexRemoved = 0;
|
||||
for ( OptimizedModel::Vertex_t *vtxVertexElement = vtxVertexBuffer; vtxVertexElement < vtxVertexBufferEnd; ++ vtxVertexElement )
|
||||
{
|
||||
size_t const off = BYTE_DIFF_PTR( vtxHdr, vtxVertexElement );
|
||||
bool bUsed = false;
|
||||
for ( int k = 0; k < vtxOffVertex.Count(); k += 2 )
|
||||
{
|
||||
if ( off >= vtxOffVertex[ k ] && off < vtxOffVertex[ k + 1 ] )
|
||||
{
|
||||
bUsed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !bUsed )
|
||||
{
|
||||
// Index is not in use
|
||||
vtxRemove.RemoveElements( vtxVertexElement );
|
||||
vtxIndexDeltas.AddToTail( 0 );
|
||||
vtxNumVertexRemoved ++;
|
||||
}
|
||||
else
|
||||
{ // Index is in use and must be remapped
|
||||
// Find the mesh where this index belongs
|
||||
int iMesh = arrMdlOffsets.FindLessOrEqual( CMdlStripInfo::MdlRangeItem( 0, 0, vtxVertexElement - vtxVertexBuffer ) );
|
||||
Assert( iMesh >= 0 && iMesh < arrMdlOffsets.Count() );
|
||||
|
||||
CMdlStripInfo::MdlRangeItem &mri = arrMdlOffsets[ iMesh ];
|
||||
Assert( ( vtxVertexElement - vtxVertexBuffer >= mri.m_offNew ) && ( vtxVertexElement - vtxVertexBuffer < mri.m_offNew + mri.m_numNew ) );
|
||||
|
||||
Assert( mapVtxIndex.IsBitSet( vtxVertexElement->origMeshVertID + mri.m_offOld ) );
|
||||
vtxVertexElement->origMeshVertID = srcIndices.Find( vtxVertexElement->origMeshVertID + mri.m_offOld ) - mri.m_offNew;
|
||||
Assert( vtxVertexElement->origMeshVertID < mri.m_numNew );
|
||||
vtxIndexDeltas.AddToTail( vtxNumVertexRemoved );
|
||||
}
|
||||
}
|
||||
|
||||
// Fixup the index buffer
|
||||
DECLARE_PTR( unsigned short, vtxIndexBuffer, BYTE_OFF_PTR( vtxHdr, vtxOffIndexBuffer ) );
|
||||
DECLARE_PTR( unsigned short, vtxIndexBufferEnd, BYTE_OFF_PTR( vtxHdr, vtxOffIndexBufferEnd ) );
|
||||
for ( unsigned short *vtxIndexElement = vtxIndexBuffer; vtxIndexElement < vtxIndexBufferEnd; ++ vtxIndexElement )
|
||||
{
|
||||
size_t const off = BYTE_DIFF_PTR( vtxHdr, vtxIndexElement );
|
||||
bool bUsed = false;
|
||||
for ( int k = 0; k < vtxOffIndex.Count(); k += 2 )
|
||||
{
|
||||
if ( off >= vtxOffIndex[ k ] && off < vtxOffIndex[ k + 1 ] )
|
||||
{
|
||||
bUsed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !bUsed )
|
||||
{
|
||||
// Index is not in use
|
||||
vtxRemove.RemoveElements( vtxIndexElement );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Index is in use and must be remapped
|
||||
*vtxIndexElement -= vtxIndexDeltas[ *vtxIndexElement ];
|
||||
}
|
||||
}
|
||||
|
||||
// By now should have scheduled all removal information
|
||||
vtxRemove.Finalize();
|
||||
DLog( "mdllib", 3, " Stripped %d vtx bytes.\n", vtxRemove.GetNumBytesRemoved() );
|
||||
|
||||
//
|
||||
// Fixup all the offsets
|
||||
//
|
||||
ITERATE_CHILDREN( OptimizedModel::MaterialReplacementListHeader_t, vtxMatList, vtxHdr, pMaterialReplacementList, numLODs )
|
||||
ITERATE_CHILDREN( OptimizedModel::MaterialReplacementHeader_t, vtxMat, vtxMatList, pMaterialReplacement, numReplacements )
|
||||
vtxMat->replacementMaterialNameOffset = vtxRemove.ComputeOffset( vtxMat, vtxMat->replacementMaterialNameOffset );
|
||||
ITERATE_END
|
||||
vtxMatList->replacementOffset = vtxRemove.ComputeOffset( vtxMatList, vtxMatList->replacementOffset );
|
||||
ITERATE_END
|
||||
ITERATE_CHILDREN( OptimizedModel::BodyPartHeader_t, vtxBodyPart, vtxHdr, pBodyPart, numBodyParts )
|
||||
ITERATE_CHILDREN( OptimizedModel::ModelHeader_t, vtxModel, vtxBodyPart, pModel, numModels )
|
||||
ITERATE_CHILDREN( OptimizedModel::ModelLODHeader_t, vtxLod, vtxModel, pLOD, numLODs )
|
||||
ITERATE_CHILDREN( OptimizedModel::MeshHeader_t, vtxMesh, vtxLod, pMesh, numMeshes )
|
||||
ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
|
||||
|
||||
ITERATE_CHILDREN( OptimizedModel::StripHeader_t, vtxStrip, vtxStripGroup, pStrip, numStrips )
|
||||
vtxStrip->indexOffset =
|
||||
vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->indexOffset + vtxStrip->indexOffset ) -
|
||||
vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->indexOffset );
|
||||
vtxStrip->vertOffset =
|
||||
vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->vertOffset + vtxStrip->vertOffset ) -
|
||||
vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->vertOffset );
|
||||
vtxStrip->boneStateChangeOffset = vtxRemove.ComputeOffset( vtxStrip, vtxStrip->boneStateChangeOffset );
|
||||
ITERATE_END
|
||||
|
||||
vtxStripGroup->vertOffset = vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->vertOffset );
|
||||
vtxStripGroup->indexOffset = vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->indexOffset );
|
||||
vtxStripGroup->stripOffset = vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->stripOffset );
|
||||
ITERATE_END
|
||||
vtxMesh->stripGroupHeaderOffset = vtxRemove.ComputeOffset( vtxMesh, vtxMesh->stripGroupHeaderOffset );
|
||||
ITERATE_END
|
||||
vtxLod->meshOffset = vtxRemove.ComputeOffset( vtxLod, vtxLod->meshOffset );
|
||||
ITERATE_END
|
||||
vtxModel->lodOffset = vtxRemove.ComputeOffset( vtxModel, vtxModel->lodOffset );
|
||||
vtxModel->numLODs = 1;
|
||||
ITERATE_END
|
||||
vtxBodyPart->modelOffset = vtxRemove.ComputeOffset( vtxBodyPart, vtxBodyPart->modelOffset );
|
||||
ITERATE_END
|
||||
vtxHdr->materialReplacementListOffset = vtxRemove.ComputeOffset( vtxHdr, vtxHdr->materialReplacementListOffset );
|
||||
vtxHdr->bodyPartOffset = vtxRemove.ComputeOffset( vtxHdr, vtxHdr->bodyPartOffset );
|
||||
vtxHdr->numLODs = 1;
|
||||
|
||||
// Perform final memory move
|
||||
vtxRemove.MemMove( vtxHdr, vtxLength );
|
||||
|
||||
|
||||
//
|
||||
// ===================
|
||||
// =================== Truncate buffer sizes
|
||||
// ===================
|
||||
//
|
||||
|
||||
vvdBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, vvdBuffer.TellGet() + vvdLength - vvdBuffer.TellPut() );
|
||||
vtxBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, vtxBuffer.TellGet() + vtxLength - vtxBuffer.TellPut() );
|
||||
|
||||
|
||||
DLog( "mdllib", 2, " Reduced model buffers by %d bytes.\n", vtxRemove.GetNumBytesRemoved() + ( vvdLengthOld - vvdLength ) );
|
||||
|
||||
// Done
|
||||
return true;
|
||||
}
|
||||
|
205
mdllib/mdllib_utils.cpp
Normal file
205
mdllib/mdllib_utils.cpp
Normal file
@ -0,0 +1,205 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
|
||||
#include "mdllib_utils.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CInsertionTracker implementation
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void CInsertionTracker::InsertBytes( void *pos, int length )
|
||||
{
|
||||
if ( length <= 0 )
|
||||
return;
|
||||
|
||||
Assert( m_map.InvalidIndex() == m_map.Find( ( byte * ) pos ) );
|
||||
m_map.InsertOrReplace( ( byte * ) pos, length );
|
||||
}
|
||||
|
||||
int CInsertionTracker::GetNumBytesInserted() const
|
||||
{
|
||||
int iInserted = 0;
|
||||
|
||||
for ( Map::IndexType_t idx = m_map.FirstInorder();
|
||||
idx != m_map.InvalidIndex(); idx = m_map.NextInorder( idx ) )
|
||||
{
|
||||
int numBytes = m_map.Element( idx );
|
||||
iInserted += numBytes;
|
||||
}
|
||||
|
||||
return iInserted;
|
||||
}
|
||||
|
||||
void CInsertionTracker::Finalize()
|
||||
{
|
||||
// Iterate the map and find all the adjacent removal data blocks
|
||||
// TODO:
|
||||
}
|
||||
|
||||
void CInsertionTracker::MemMove( void *ptrBase, int &length ) const
|
||||
{
|
||||
int numBytesInsertReq = GetNumBytesInserted();
|
||||
byte *pbBlockEnd = BYTE_OFF_PTR( ptrBase, length );
|
||||
length += numBytesInsertReq;
|
||||
|
||||
for ( Map::IndexType_t idx = m_map.LastInorder();
|
||||
idx != m_map.InvalidIndex(); idx = m_map.PrevInorder( idx ) )
|
||||
{
|
||||
byte *ptr = m_map.Key( idx );
|
||||
int numBytes = m_map.Element( idx );
|
||||
|
||||
// Move [ptr, pbBlockEnd) ->> + numBytesInsertReq
|
||||
memmove( BYTE_OFF_PTR( ptr, numBytesInsertReq ), ptr, BYTE_DIFF_PTR( ptr, pbBlockEnd ) );
|
||||
|
||||
// Inserted data
|
||||
memset( BYTE_OFF_PTR( ptr, numBytesInsertReq - numBytes ), 0, numBytes );
|
||||
|
||||
numBytesInsertReq -= numBytes;
|
||||
pbBlockEnd = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
int CInsertionTracker::ComputeOffset( void *ptrBase, int off ) const
|
||||
{
|
||||
void *ptrNewBase = ComputePointer( ptrBase );
|
||||
void *ptrNewData = ComputePointer( BYTE_OFF_PTR( ptrBase, off ) );
|
||||
return BYTE_DIFF_PTR( ptrNewBase, ptrNewData );
|
||||
}
|
||||
|
||||
void * CInsertionTracker::ComputePointer( void *ptrNothingInserted ) const
|
||||
{
|
||||
int iInserted = 0;
|
||||
|
||||
// Iterate the map and find all the data that would be inserted before the given pointer
|
||||
for ( Map::IndexType_t idx = m_map.FirstInorder();
|
||||
idx != m_map.InvalidIndex(); idx = m_map.NextInorder( idx ) )
|
||||
{
|
||||
if ( m_map.Key( idx ) < ptrNothingInserted )
|
||||
iInserted += m_map.Element( idx );
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return BYTE_OFF_PTR( ptrNothingInserted, iInserted );
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CRemoveTracker implementation
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void CRemoveTracker::RemoveBytes( void *pos, int length )
|
||||
{
|
||||
if ( length <= 0 )
|
||||
return;
|
||||
|
||||
// -- hint
|
||||
if ( m_map.Count() )
|
||||
{
|
||||
if ( m_hint.ptr < pos )
|
||||
{
|
||||
if ( BYTE_OFF_PTR( m_hint.ptr, m_hint.len ) == pos )
|
||||
{
|
||||
m_hint.len += length;
|
||||
m_map.Element( m_hint.idx ) = m_hint.len;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if ( m_hint.ptr > pos )
|
||||
{
|
||||
if ( BYTE_OFF_PTR( pos, length ) == m_hint.ptr )
|
||||
{
|
||||
m_hint.len += length;
|
||||
m_hint.ptr = BYTE_OFF_PTR( m_hint.ptr, - length );
|
||||
m_map.Key( m_hint.idx ) = m_hint.ptr;
|
||||
m_map.Element( m_hint.idx ) = m_hint.len;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// -- end hint
|
||||
|
||||
// Insert new
|
||||
Assert( m_map.InvalidIndex() == m_map.Find( ( byte * ) pos ) );
|
||||
Map::IndexType_t idx = m_map.InsertOrReplace( ( byte * ) pos, length );
|
||||
|
||||
// New hint
|
||||
m_hint.idx = idx;
|
||||
m_hint.ptr = ( byte * ) pos;
|
||||
m_hint.len = length;
|
||||
}
|
||||
|
||||
int CRemoveTracker::GetNumBytesRemoved() const
|
||||
{
|
||||
int iRemoved = 0;
|
||||
|
||||
for ( Map::IndexType_t idx = m_map.FirstInorder();
|
||||
idx != m_map.InvalidIndex(); idx = m_map.NextInorder( idx ) )
|
||||
{
|
||||
int numBytes = m_map.Element( idx );
|
||||
iRemoved += numBytes;
|
||||
}
|
||||
|
||||
return iRemoved;
|
||||
}
|
||||
|
||||
void CRemoveTracker::Finalize()
|
||||
{
|
||||
// Iterate the map and find all the adjacent removal data blocks
|
||||
// TODO:
|
||||
}
|
||||
|
||||
void CRemoveTracker::MemMove( void *ptrBase, int &length ) const
|
||||
{
|
||||
int iRemoved = 0;
|
||||
|
||||
for ( Map::IndexType_t idx = m_map.FirstInorder();
|
||||
idx != m_map.InvalidIndex(); idx = m_map.NextInorder( idx ) )
|
||||
{
|
||||
byte *ptr = m_map.Key( idx );
|
||||
byte *ptrDest = BYTE_OFF_PTR( ptr, - iRemoved );
|
||||
int numBytes = m_map.Element( idx );
|
||||
memmove( ptrDest, BYTE_OFF_PTR( ptrDest, numBytes ), BYTE_DIFF_PTR( BYTE_OFF_PTR( ptr, numBytes ), BYTE_OFF_PTR( ptrBase, length ) ) );
|
||||
iRemoved += numBytes;
|
||||
}
|
||||
|
||||
length -= iRemoved;
|
||||
}
|
||||
|
||||
int CRemoveTracker::ComputeOffset( void *ptrBase, int off ) const
|
||||
{
|
||||
void *ptrNewBase = ComputePointer( ptrBase );
|
||||
void *ptrNewData = ComputePointer( BYTE_OFF_PTR( ptrBase, off ) );
|
||||
return BYTE_DIFF_PTR( ptrNewBase, ptrNewData );
|
||||
}
|
||||
|
||||
void * CRemoveTracker::ComputePointer( void *ptrNothingRemoved ) const
|
||||
{
|
||||
int iRemoved = 0;
|
||||
|
||||
// Iterate the map and find all the data that would be removed before the given pointer
|
||||
for ( Map::IndexType_t idx = m_map.FirstInorder();
|
||||
idx != m_map.InvalidIndex(); idx = m_map.NextInorder( idx ) )
|
||||
{
|
||||
if ( m_map.Key( idx ) < ptrNothingRemoved )
|
||||
iRemoved += m_map.Element( idx );
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return BYTE_OFF_PTR( ptrNothingRemoved, - iRemoved );
|
||||
}
|
||||
|
||||
|
203
mdllib/mdllib_utils.h
Normal file
203
mdllib/mdllib_utils.h
Normal file
@ -0,0 +1,203 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef MDLLIB_UTILS_H
|
||||
#define MDLLIB_UTILS_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "utlmap.h"
|
||||
#include "utlvector.h"
|
||||
#include "bitvec.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Helper macros
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Declare a pointer and automatically do the cast of initial value to the pointer type
|
||||
#define DECLARE_PTR( type, name, initval ) type *name = ( type * ) ( initval )
|
||||
|
||||
// Compute a pointer that is offset given number of bytes from the base pointer
|
||||
#define BYTE_OFF_PTR( initval, offval ) ( ( ( byte * ) ( initval ) ) + ( offval ) )
|
||||
|
||||
// Compute difference in bytes between two pointers
|
||||
#define BYTE_DIFF_PTR( begin, end ) ( ( ( byte * ) ( end ) ) - ( ( byte * ) ( begin ) ) )
|
||||
|
||||
|
||||
// "for {" to iterate children of a studio container
|
||||
#define ITERATE_CHILDREN( type, name, parent, accessor, count ) \
|
||||
for ( int name##_idx = 0; name##_idx < (parent)->count; ++ name##_idx ) { \
|
||||
type *name = (parent)->accessor( name##_idx );
|
||||
|
||||
// "for {" to jointly iterate children of 2 studio containers of same size
|
||||
#define ITERATE_CHILDREN2( type, type2, name, name2, parent, parent2, accessor, accessor2, count ) \
|
||||
for ( int name##_idx = 0; name##_idx < (parent)->count; ++ name##_idx ) { \
|
||||
type *name = (parent)->accessor( name##_idx ); \
|
||||
type2 *name2 = (parent2)->accessor2( name##_idx );
|
||||
|
||||
// "}" to mark the end of iteration block
|
||||
#define ITERATE_END }
|
||||
|
||||
// Get the child of a container by index
|
||||
#define CHILD_AT( parent, accessor, idx ) ( (parent)->accessor( idx ) )
|
||||
|
||||
|
||||
//
|
||||
// CLessSimple< T >
|
||||
// Comparison policy to use "t1 < t2" comparison rule.
|
||||
//
|
||||
template < typename T >
|
||||
class CLessSimple
|
||||
{
|
||||
public:
|
||||
bool Less( const T& src1, const T& src2, void *pCtx )
|
||||
{
|
||||
pCtx;
|
||||
return ( src1 < src2 );
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// CInsertionTracker
|
||||
// Class that is tracking insertions that are scheduled to happen at given points.
|
||||
// Use policy:
|
||||
// InsertBytes / InsertElements [*] -- schedule insertions
|
||||
// Finalize -- finalize insertion information
|
||||
// ComputePointer / ComputeOffset [*] -- compute new pointers/offsets that will happen after insertions
|
||||
// MemMove -- perform memory moves to apply insertions
|
||||
//
|
||||
class CInsertionTracker
|
||||
{
|
||||
public:
|
||||
CInsertionTracker() : m_map( DefLessFunc( byte * ) ) {}
|
||||
|
||||
// Schedules a piece of memory for insertion
|
||||
public:
|
||||
void InsertBytes( void *pos, int length );
|
||||
|
||||
template< typename T >
|
||||
void InsertElements( T *ptr, int count = 1 ) { InsertBytes( ( byte * ) ptr, count * sizeof( T ) ); }
|
||||
|
||||
int GetNumBytesInserted() const;
|
||||
|
||||
// Finalizes the insertion information
|
||||
public:
|
||||
void Finalize();
|
||||
|
||||
// Computes where the pointer would point after memory insertion occurs
|
||||
public:
|
||||
void * ComputePointer( void *ptrNothingInserted ) const;
|
||||
int ComputeOffset( void *ptrBase, int off ) const;
|
||||
|
||||
// Perform memory moves, the buffer should be large enough to accommodate inserted bytes
|
||||
public:
|
||||
void MemMove( void *ptrBase, int &length ) const;
|
||||
|
||||
protected:
|
||||
typedef CUtlMap< byte *, int, unsigned int > Map;
|
||||
Map m_map; // pos -> length
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// CRemoveTracker
|
||||
// Class that is tracking removals that are scheduled to happen at given points.
|
||||
// Use policy:
|
||||
// RemoveBytes / RemoveElements [*] -- schedule removals
|
||||
// Finalize -- finalize removal information
|
||||
// ComputePointer / ComputeOffset [*] -- compute new pointers/offsets that will happen after removals
|
||||
// MemMove -- perform memory moves to apply removals
|
||||
//
|
||||
class CRemoveTracker
|
||||
{
|
||||
public:
|
||||
CRemoveTracker() : m_map( DefLessFunc( byte * ) ) {}
|
||||
|
||||
// Schedules a piece of memory for removal
|
||||
public:
|
||||
void RemoveBytes( void *pos, int length );
|
||||
|
||||
template< typename T >
|
||||
void RemoveElements( T *ptr, int count = 1 ) { RemoveBytes( ( byte * ) ptr, count * sizeof( T ) ); }
|
||||
|
||||
int GetNumBytesRemoved() const;
|
||||
|
||||
// Finalizes the removal information
|
||||
public:
|
||||
void Finalize();
|
||||
|
||||
// Computes where the pointer would point after memory removal occurs
|
||||
public:
|
||||
void * ComputePointer( void *ptrNothingRemoved ) const;
|
||||
int ComputeOffset( void *ptrBase, int off ) const;
|
||||
|
||||
public:
|
||||
void MemMove( void *ptrBase, int &length ) const;
|
||||
|
||||
protected:
|
||||
typedef CUtlMap< byte *, int, unsigned int > Map;
|
||||
Map m_map; // pos -> length
|
||||
|
||||
struct Item
|
||||
{
|
||||
Map::IndexType_t idx;
|
||||
byte *ptr;
|
||||
int len;
|
||||
};
|
||||
Item m_hint;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// CGrowableBitVec
|
||||
// Serves bit accumulation.
|
||||
// Provides "GrowSetBit" method to automatically grow to the required size
|
||||
// and set the given bit.
|
||||
// Provides safe "IsBitSet" that would return false for missing bits.
|
||||
//
|
||||
class CGrowableBitVec : public CVarBitVec
|
||||
{
|
||||
public:
|
||||
void GrowSetBit( int iBit )
|
||||
{
|
||||
if ( iBit >= GetNumBits() )
|
||||
Resize( iBit + 1, false );
|
||||
Set( iBit );
|
||||
}
|
||||
|
||||
bool IsBitSet( int bitNum ) const
|
||||
{
|
||||
return ( bitNum < GetNumBits() ) && CVarBitVec::IsBitSet( bitNum );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// CGrowableVector
|
||||
// Provides zero-initialization for new elements.
|
||||
//
|
||||
template < typename T >
|
||||
class CGrowableVector : public CUtlVector < T >
|
||||
{
|
||||
public:
|
||||
T & operator[] ( int idx )
|
||||
{
|
||||
while ( idx >= Count() )
|
||||
AddToTail( T() );
|
||||
return CUtlVector < T >::operator []( idx );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // #ifndef MDLLIB_UTILS_H
|
Reference in New Issue
Block a user