This commit is contained in:
nephacks
2025-06-04 03:22:50 +02:00
parent f234f23848
commit f12416cffd
14243 changed files with 6446499 additions and 26 deletions
@@ -0,0 +1,40 @@
// ----------------------------------------- //
// File generated by VPC //
// ----------------------------------------- //
Source file: F:\csgo_64\cstrike15_src\common\debug_dll_check.cpp
Debug output file: F:\csgo_64\cstrike15_src\common\debug_dll_check.cpp
Release output file: F:\csgo_64\cstrike15_src\common\debug_dll_check.cpp
Containing unity file:
PCH file:
Source file: F:\csgo_64\cstrike15_src\mdllib\mdllib.cpp
Debug output file: F:\csgo_64\cstrike15_src\mdllib\mdllib.cpp
Release output file: F:\csgo_64\cstrike15_src\mdllib\mdllib.cpp
Containing unity file:
PCH file:
Source file: F:\csgo_64\cstrike15_src\mdllib\mdllib_stripinfo.cpp
Debug output file: F:\csgo_64\cstrike15_src\mdllib\mdllib_stripinfo.cpp
Release output file: F:\csgo_64\cstrike15_src\mdllib\mdllib_stripinfo.cpp
Containing unity file:
PCH file:
Source file: F:\csgo_64\cstrike15_src\mdllib\mdllib_stripmodel.cpp
Debug output file: F:\csgo_64\cstrike15_src\mdllib\mdllib_stripmodel.cpp
Release output file: F:\csgo_64\cstrike15_src\mdllib\mdllib_stripmodel.cpp
Containing unity file:
PCH file:
Source file: F:\csgo_64\cstrike15_src\mdllib\mdllib_utils.cpp
Debug output file: F:\csgo_64\cstrike15_src\mdllib\mdllib_utils.cpp
Release output file: F:\csgo_64\cstrike15_src\mdllib\mdllib_utils.cpp
Containing unity file:
PCH file:
Source file: F:\csgo_64\cstrike15_src\public\tier0\memoverride.cpp
Debug output file: F:\csgo_64\cstrike15_src\public\tier0\memoverride.cpp
Release output file: F:\csgo_64\cstrike15_src\public\tier0\memoverride.cpp
Containing unity file:
PCH file:
+72
View File
@@ -0,0 +1,72 @@
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
//
// Purpose:
//
//=============================================================================
#include "mdllib_common.h"
#include "tier3/tier3.h"
//-----------------------------------------------------------------------------
// Global instance
//-----------------------------------------------------------------------------
CMdlLib s_Mdllib;
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CMdlLib, IMdlLib, MDLLIB_INTERFACE_VERSION, s_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 );
}
+45
View File
@@ -0,0 +1,45 @@
//-----------------------------------------------------------------------------
// MDLLIB.VPC
//
// Project Script
//-----------------------------------------------------------------------------
$Macro SRCDIR ".."
$Macro OUTBINDIR "$SRCDIR\..\game\bin"
$Include "$SRCDIR\vpc_scripts\source_dll_win32_base.vpc"
$Configuration
{
$Compiler
{
$AdditionalIncludeDirectories "$BASE,$SRCDIR\ps3sdk\cell\host-common\include,$SRCDIR\ps3sdk\cell\target\common\include" [$PS3SDKINSTALLED]
}
$Linker
{
$AdditionalDependencies "$BASE libedgegeomtool.Release.Win32.vs8.lib" [$PS3SDKINSTALLED]
$AdditionalLibraryDirectories "$BASE;$(XEDK)\lib\win32\vs2010"
$AdditionalLibraryDirectories "$BASE;$SRCDIR\ps3sdk\cell\host-win32\lib" [$PS3SDKINSTALLED]
}
}
$Project "mdllib"
{
$Folder "Source Files"
{
$File "mdllib.cpp"
$File "mdllib_stripinfo.cpp"
$File "mdllib_stripmodel.cpp"
$File "mdllib_preparemodelps3.cpp" [$PS3SDKINSTALLED]
$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"
}
}
+13
View File
@@ -0,0 +1,13 @@
"vpc_cache"
{
"CacheVersion" "1"
"win32"
{
"CRCFile" "mdllib.vcxproj.vpc_crc"
"OutputFiles"
{
"0" "mdllib.vcxproj"
"1" "mdllib.vcxproj.filters"
}
}
}
+94
View File
@@ -0,0 +1,94 @@
//====== Copyright © 1996-2007, 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 )
DECLARE_LOGGING_CHANNEL( LOG_ModelLib );
//-----------------------------------------------------------------------------
// 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 );
//
// ParseMdlMesh
// The main function that parses the mesh buffers
// mdlBuffer - mdl buffer
// vvdBuffer - vvd buffer
// vtxBuffer - vtx buffer
// mesh - on return will be filled with the mesh info
//
virtual bool ParseMdlMesh( CUtlBuffer &mdlBuffer, CUtlBuffer &vvdBuffer, CUtlBuffer &vtxBuffer, MdlLib::MdlMesh &mesh );
//
// PrepareModelForPs3
// The main function that strips the model buffers
// mdlBuffer - mdl buffer, updated, size possibly increased
// vvdBuffer - vvd buffer, updated, size possibly increased
// vtxBuffer - vtx buffer, updated, size possibly increased
// ppStripInfo - if nonzero on return will be filled with the stripping info
//
virtual bool PrepareModelForPs3( CUtlBuffer &mdlBuffer, CUtlBuffer &vvdBuffer, CUtlBuffer &vtxBuffer, IMdlStripInfo **ppStripInfo )
#if defined( PS3SDK_INSTALLED )
;
#else
{
return false;
}
#endif
};
#endif // #ifndef MDLLIB_COMMON_H
File diff suppressed because it is too large Load Diff
+874
View File
@@ -0,0 +1,874 @@
//====== Copyright c 1996-2007, 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:
case MODE_PS3_FORMAT_BASIC:
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;
case MODE_PS3_PARTITIONS:
bufStorage.PutInt( m_lChecksumOld );
bufStorage.PutInt( m_lChecksumNew );
bufStorage.PutUnsignedInt( m_ps3studioBatches.Count() );
for ( int k = 0; k < m_ps3studioBatches.Count(); ++ k )
{
Ps3studioBatch_t &batch = *m_ps3studioBatches[k];
bufStorage.PutUnsignedInt( batch.m_arrPartitions.Count() );
for ( int j = 0; j < batch.m_arrPartitions.Count(); ++ j )
{
Ps3studioPartition_t &partition = *batch.m_arrPartitions[j];
bufStorage.PutUnsignedInt( partition.m_arrLocalIndices.Count() );
for ( int nn = 0; nn < partition.m_arrLocalIndices.Count(); ++ nn )
{
bufStorage.PutUnsignedShort( partition.m_arrLocalIndices[nn] );
}
bufStorage.PutUnsignedInt( partition.m_arrVertOriginalIndices.Count() );
for ( int nn = 0; nn < partition.m_arrVertOriginalIndices.Count(); ++ nn )
{
bufStorage.PutUnsignedInt( partition.m_arrVertOriginalIndices[nn] );
}
bufStorage.PutUnsignedInt( partition.m_arrStripLocalOriginalIndices.Count() );
for ( int nn = 0; nn < partition.m_arrStripLocalOriginalIndices.Count(); ++ nn )
{
bufStorage.PutUnsignedInt( partition.m_arrStripLocalOriginalIndices[nn] );
}
bufStorage.PutUnsignedInt( partition.m_nIoBufferSize );
}
bufStorage.PutUnsignedInt( batch.m_uiModelIndexOffset );
bufStorage.PutUnsignedInt( batch.m_uiVhvIndexOffset );
}
bufStorage.PutUnsignedInt( m_ps3studioStripGroupHeaderBatchOffset.Count() );
for ( int k = 0; k < m_ps3studioStripGroupHeaderBatchOffset.Count(); ++ k )
{
bufStorage.PutUnsignedInt( m_ps3studioStripGroupHeaderBatchOffset[k] );
}
return true;
}
}
bool CMdlStripInfo::UnSerialize( CUtlBuffer &bufData )
{
char chHeader[ 4 ];
bufData.Get( chHeader, sizeof( chHeader ) );
if ( memcmp( chHeader, "MAP", 3 ) )
return false;
m_eMode = chHeader[3];
switch ( chHeader[3] )
{
default:
return false;
case MODE_UNINITIALIZED:
m_lChecksumOld = 0;
m_lChecksumNew = 0;
return true;
case MODE_NO_CHANGE:
case MODE_PS3_FORMAT_BASIC:
m_lChecksumOld = bufData.GetInt();
m_lChecksumNew = bufData.GetInt();
return true;
case 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;
case MODE_PS3_PARTITIONS:
m_lChecksumOld = bufData.GetInt();
m_lChecksumNew = bufData.GetInt();
m_ps3studioBatches.SetCount( bufData.GetUnsignedInt() );
for ( int k = 0; k < m_ps3studioBatches.Count(); ++ k )
{
m_ps3studioBatches[k] = new Ps3studioBatch_t;
Ps3studioBatch_t &batch = *m_ps3studioBatches[k];
batch.m_arrPartitions.SetCount( bufData.GetUnsignedInt() );
for ( int j = 0; j < batch.m_arrPartitions.Count(); ++ j )
{
batch.m_arrPartitions[j] = new Ps3studioPartition_t;
Ps3studioPartition_t &partition = *batch.m_arrPartitions[j];
partition.m_arrLocalIndices.SetCount( bufData.GetUnsignedInt() );
for ( int nn = 0; nn < partition.m_arrLocalIndices.Count(); ++ nn )
{
partition.m_arrLocalIndices[nn] = bufData.GetUnsignedShort();
}
partition.m_arrVertOriginalIndices.SetCount( bufData.GetUnsignedInt() );
for ( int nn = 0; nn < partition.m_arrVertOriginalIndices.Count(); ++ nn )
{
partition.m_arrVertOriginalIndices[nn] = bufData.GetUnsignedInt();
}
partition.m_arrStripLocalOriginalIndices.SetCount( bufData.GetUnsignedInt() );
for ( int nn = 0; nn < partition.m_arrStripLocalOriginalIndices.Count(); ++ nn )
{
partition.m_arrStripLocalOriginalIndices[nn] = bufData.GetUnsignedInt();
}
partition.m_nIoBufferSize = bufData.GetUnsignedInt();
}
batch.m_uiModelIndexOffset = bufData.GetUnsignedInt();
batch.m_uiVhvIndexOffset = bufData.GetUnsignedInt();
}
m_ps3studioStripGroupHeaderBatchOffset.SetCount( bufData.GetUnsignedInt() );
for ( int k = 0; k < m_ps3studioStripGroupHeaderBatchOffset.Count(); ++ k )
{
m_ps3studioStripGroupHeaderBatchOffset[k] = bufData.GetUnsignedInt();
}
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;
}
static inline uint32 Helper_SwapVhvColorForPs3( uint32 uiColor )
{
// Swapping R and B channels
return
( ( ( uiColor >> 0 ) & 0xFF ) << 16 ) |
( ( ( uiColor >> 8 ) & 0xFF ) << 8 ) |
( ( ( uiColor >> 16 ) & 0xFF ) << 0 ) |
( ( ( uiColor >> 24 ) & 0xFF ) << 24 );
}
//
// 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 )
{
Log_Msg( LOG_ModelLib, "ERROR: [StripHardwareVertsBuffer] checksum mismatch!\n" );
return false;
}
vhvHdr->m_nChecksum = m_lChecksumNew;
// No remapping required
if ( m_eMode == MODE_NO_CHANGE )
return true;
// Basic PS3 remapping required
if ( m_eMode == MODE_PS3_FORMAT_BASIC )
{
DECLARE_PTR( uint32, pVertDataSrc, BYTE_OFF_PTR( vhvHdr, AlignValue( sizeof( *vhvHdr ) + vhvHdr->m_nMeshes * sizeof( HardwareVerts::MeshHeader_t ), 512 ) ) );
DECLARE_PTR( uint32, pVertDataEnd, BYTE_OFF_PTR( vhvHdr, vhvLength ) );
while ( pVertDataSrc + 1 <= pVertDataEnd )
{
* ( pVertDataSrc ++ ) = Helper_SwapVhvColorForPs3( *pVertDataSrc );
}
return true;
}
if ( m_eMode == MODE_STRIP_LOD_1N )
{
//
// Now reconstruct the vhv structures to do the mapping
//
CMemoryMovingTracker vhvRemove( CMemoryMovingTracker::MEMORY_REMOVE );
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.RegisterBytes( BYTE_OFF_PTR( vhvHdr, vhvMesh->m_nOffset ), vhvMesh->m_nVertexes * vhvHdr->m_nVertexSize );
vhvRemove.RegisterElements( vhvMesh );
numVertsRemoved += vhvMesh->m_nVertexes;
++ numMeshesRemoved;
ITERATE_END
vhvRemove.RegisterBytes( BYTE_OFF_PTR( vhvHdr, vhvEndMeshOffset ), vhvVertOffset - vhvEndMeshOffset ); // Padding
vhvRemove.RegisterBytes( BYTE_OFF_PTR( vhvHdr, vhvVertOffset + vhvHdr->m_nVertexes * vhvHdr->m_nVertexSize ), vhvLength - ( vhvVertOffset + vhvHdr->m_nVertexes * vhvHdr->m_nVertexSize ) );
vhvRemove.Finalize();
Log_Msg( LOG_ModelLib, " Stripped %d vhv bytes.\n", vhvRemove.GetNumBytesRegistered() );
// 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();
Log_Msg( LOG_ModelLib, " 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() );
Log_Msg( LOG_ModelLib, " Reduced vhv buffer by %d bytes.\n", vhvRemove.GetNumBytesRegistered() - vhvInsertPadding.GetNumBytesInserted() );
return true;
}
if ( m_eMode == MODE_PS3_PARTITIONS )
{
//
// Complex partitions processing
//
// Expect number of meshes in VHV header to match
if ( !vhvHdr->m_nMeshes || vhvHdr->m_nMeshes != m_ps3studioStripGroupHeaderBatchOffset.Count() )
{
Log_Msg( LOG_ModelLib, " Mismatching vhv buffer mesh count( vhv=%d, vsi=%d ).\n", vhvHdr->m_nMeshes, m_ps3studioStripGroupHeaderBatchOffset.Count() );
return false;
}
// Count total number of vertices
uint32 uiTotalVerts = 0;
for ( int k = 0; k < m_ps3studioBatches.Count(); ++ k )
for ( int j = 0; j < m_ps3studioBatches[k]->m_arrPartitions.Count(); ++ j )
uiTotalVerts += m_ps3studioBatches[k]->m_arrPartitions[j]->m_arrVertOriginalIndices.Count();
// Now allocate enough target buffer space to fit all the verts
uint32 uiRequiredBufferSize = sizeof( HardwareVerts::FileHeader_t ) + vhvHdr->m_nMeshes*sizeof( HardwareVerts::MeshHeader_t );
uiRequiredBufferSize = AlignValue( uiRequiredBufferSize, 512 ); // start actual data stream on 512-boundary
uint32 uiTotalBufferSize = AlignValue( uiRequiredBufferSize + 4 * uiTotalVerts, 512 );
// Copy off the source buffer
CUtlBuffer bufSrcCopy;
bufSrcCopy.EnsureCapacity( MAX( uiTotalBufferSize, vhvLength ) );
V_memcpy( bufSrcCopy.Base(), vhvHdr, vhvLength );
// We know where the first mesh's vertices should start
if ( vhvHdr->pMesh(0)->m_nOffset != uiRequiredBufferSize || uiTotalBufferSize < vhvLength )
{
Log_Msg( LOG_ModelLib, " Unexpected vhv buffer mesh offset.\n" );
return false;
}
vhvBuffer.EnsureCapacity( vhvBuffer.TellGet() + uiTotalBufferSize );
vhvBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, uiTotalBufferSize - vhvLength );
DECLARE_UPDATE_PTR( HardwareVerts::FileHeader_t, vhvHdr, BYTE_OFF_PTR( vhvBuffer.Base(), vhvBuffer.TellGet() ) );
DECLARE_PTR( HardwareVerts::FileHeader_t, vhvHdrSrc, bufSrcCopy.Base() );
//
// === update the actual VHV vertices
//
DECLARE_PTR( uint32, pVertDataSrc, BYTE_OFF_PTR( vhvHdrSrc, uiRequiredBufferSize ) );
DECLARE_PTR( uint32, pVertDataDst, BYTE_OFF_PTR( vhvHdr, uiRequiredBufferSize ) );
#ifdef _DEBUG
// Keep track of which verts got touched
CGrowableBitVec arrTouchedOriginalVerts;
uint32 uiDebugOriginalVertsPresent = 0;
for ( uint32 iDebugMesh = 0; iDebugMesh < vhvHdr->m_nMeshes; ++ iDebugMesh )
uiDebugOriginalVertsPresent += vhvHdr->pMesh(iDebugMesh)->m_nVertexes;
#endif
for ( uint32 iMesh = 0, iBatch = 0; iMesh < m_ps3studioStripGroupHeaderBatchOffset.Count(); ++ iMesh )
{
uint32 numVerts = 0;
vhvHdr->pMesh(iMesh)->m_nOffset = BYTE_DIFF_PTR( vhvHdr, pVertDataDst );
uint32 iBatchEnd = ( iMesh < m_ps3studioStripGroupHeaderBatchOffset.Count() - 1 )
? m_ps3studioStripGroupHeaderBatchOffset[iMesh+1] : m_ps3studioBatches.Count();
iBatchEnd = MIN( iBatchEnd, m_ps3studioBatches.Count() );
for ( ; iBatch < iBatchEnd; ++ iBatch )
{
Ps3studioBatch_t &batch = *m_ps3studioBatches[iBatch];
// uint32 arrForcedColors[] = { 0xFF200000, 0xFFFF0000, 0xFFFFFF00, 0xFF002000, 0xFF00FF00, 0xFF00FFFF, 0xFF000020, 0xFF0000FF, 0xFFFF00FF };
for ( uint32 iPartition = 0; iPartition < batch.m_arrPartitions.Count(); ++ iPartition )
{
Ps3studioPartition_t &partition = *batch.m_arrPartitions[iPartition];
numVerts += partition.m_arrVertOriginalIndices.Count();
for ( uint32 iVertIndex = 0; iVertIndex < partition.m_arrVertOriginalIndices.Count(); ++ iVertIndex )
{
// uint32 uiOrigVertIndex = partition.m_arrVertOriginalIndices[iVertIndex];
uint32 uiOrigVertIndex = partition.m_arrStripLocalOriginalIndices[iVertIndex];
uiOrigVertIndex += batch.m_uiVhvIndexOffset;
uint32 uiColor = pVertDataSrc[uiOrigVertIndex];
Assert( BYTE_DIFF_PTR( vhvHdrSrc, pVertDataSrc[uiOrigVertIndex] ) < vhvLength );
// uiColor = arrForcedColors[iPartition%ARRAYSIZE(arrForcedColors)];
*( pVertDataDst ++ ) = Helper_SwapVhvColorForPs3( uiColor );
Assert( BYTE_DIFF_PTR( vhvHdr, pVertDataDst ) <= uiTotalBufferSize );
#ifdef _DEBUG
arrTouchedOriginalVerts.GrowSetBit( uiOrigVertIndex );
#endif
}
}
}
vhvHdr->pMesh(iMesh)->m_nVertexes = numVerts;
}
#ifdef _DEBUG
{
uint32 uiDebugTouchedOriginalVerts = arrTouchedOriginalVerts.GetNumBits();
for ( uint32 iDebugOrigVert = 0; iDebugOrigVert < uiDebugOriginalVertsPresent; ++ iDebugOrigVert )
{
Assert( arrTouchedOriginalVerts.IsBitSet( iDebugOrigVert ) );
}
Assert( uiDebugTouchedOriginalVerts == uiDebugOriginalVertsPresent );
}
#endif
return true;
}
// Done
return false;
}
//
// 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 )
{
Log_Msg( LOG_ModelLib, "ERROR: [StripModelBuffer] checksum mismatch!\n" );
return false;
}
mdlHdr->checksum = m_lChecksumNew;
// No remapping required
if ( m_eMode == MODE_NO_CHANGE )
return true;
if ( m_eMode != MODE_STRIP_LOD_1N )
return false;
//
// 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 )
Log_Msg( LOG_ModelLib, " 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( const mstudiobone_t, mdlBone, mdlHdr, pBone, numbones )
((mstudiobone_t *)mdlBone)->flags &= ( BONE_USED_BY_VERTEX_LOD0 | ~BONE_USED_BY_VERTEX_MASK );
ITERATE_END
Log_Msg( LOG_ModelLib, " 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 )
{
Log_Msg( LOG_ModelLib, "ERROR: [StripVertexDataBuffer] checksum mismatch!\n" );
return false;
}
vvdHdr->checksum = m_lChecksumNew;
// No remapping required
if ( m_eMode == MODE_NO_CHANGE )
return true;
if ( m_eMode != MODE_STRIP_LOD_1N )
return false;
//
// 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() );
Log_Msg( LOG_ModelLib, " 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 )
{
Log_Msg( LOG_ModelLib, "ERROR: [StripOptimizedModelBuffer] checksum mismatch!\n" );
return false;
}
vtxHdr->checkSum = m_lChecksumNew;
// No remapping required
if ( m_eMode == MODE_NO_CHANGE )
return true;
if ( m_eMode != MODE_STRIP_LOD_1N )
return false;
//
// 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;
CMemoryMovingTracker vtxRemove( CMemoryMovingTracker::MEMORY_REMOVE );
CUtlVector< size_t > vtxOffIndex;
CUtlVector< size_t > vtxOffVertex;
vtxRemove.RegisterElements( CHILD_AT( vtxHdr, pMaterialReplacementList, 1 ), vtxHdr->numLODs - 1 );
ITERATE_CHILDREN( OptimizedModel::MaterialReplacementListHeader_t, vtxMatList, vtxHdr, pMaterialReplacementList, numLODs )
if ( !vtxMatList_idx ) continue;
vtxRemove.RegisterElements( CHILD_AT( vtxMatList, pMaterialReplacement, 0 ), vtxMatList->numReplacements );
ITERATE_CHILDREN( OptimizedModel::MaterialReplacementHeader_t, vtxMat, vtxMatList, pMaterialReplacement, numReplacements )
char const *szName = vtxMat->pMaterialReplacementName();
vtxRemove.RegisterElements( 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.RegisterElements( 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.RegisterElements( CHILD_AT( vtxLod, pMesh, 0 ), vtxLod->numMeshes );
ITERATE_CHILDREN( OptimizedModel::MeshHeader_t, vtxMesh, vtxLod, pMesh, numMeshes )
vtxRemove.RegisterElements( CHILD_AT( vtxMesh, pStripGroup, 0 ), vtxMesh->numStripGroups );
ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
vtxRemove.RegisterElements( CHILD_AT( vtxStripGroup, pStrip, 0 ), vtxStripGroup->numStrips );
ITERATE_CHILDREN( OptimizedModel::StripHeader_t, vtxStrip, vtxStripGroup, pStrip, numStrips )
vtxRemove.RegisterElements( 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.RegisterElements( 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.RegisterElements( vtxIndexElement );
}
else
{
// Index is in use and must be remapped
*vtxIndexElement -= vtxIndexDeltas[ *vtxIndexElement ];
}
}
// By now should have scheduled all removal information
vtxRemove.Finalize();
Log_Msg( LOG_ModelLib, " Stripped %d vtx bytes.\n", vtxRemove.GetNumBytesRegistered() );
//
// 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();
m_ps3studioBatches.PurgeAndDeleteElements();
}
+165
View File
@@ -0,0 +1,165 @@
//====== Copyright c 1996-2007, 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();
~CMdlStripInfo() { m_ps3studioBatches.PurgeAndDeleteElements(); }
//
// 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,
MODE_PS3_PARTITIONS = 3,
MODE_PS3_FORMAT_BASIC = 4,
};
//
// 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;
//
// PS3 partitioning data
//
public:
struct Ps3studioPartition_t
{
CUtlVector< uint16 > m_arrLocalIndices;
CUtlVector< uint32 > m_arrVertOriginalIndices;
CUtlVector< uint32 > m_arrStripLocalOriginalIndices;
uint32 m_nIoBufferSize;
// -- not serialized in .vsi --
uint32 m_nEdgeDmaInputIdx;
uint32 m_nEdgeDmaInputVtx;
uint32 m_nEdgeDmaInputEnd;
// compressed idx information
uint8 *m_pEdgeCompressedIdx;
uint16 m_uiEdgeCompressedIdxDmaTagSize[2];
// compressed vtx information
uint8 *m_pEdgeCompressedVtx;
uint32 *m_pEdgeCompressedVtxFixedOffsets;
uint16 m_uiEdgeCompressedVtxDmaTagSize[3];
uint32 m_uiEdgeCompressedVtxFixedOffsetsSize;
};
struct Ps3studioBatch_t
{
CUtlVector< Ps3studioPartition_t * > m_arrPartitions;
uint32 m_uiModelIndexOffset;
uint32 m_uiVhvIndexOffset;
~Ps3studioBatch_t() { m_arrPartitions.PurgeAndDeleteElements(); }
};
CUtlVector< Ps3studioBatch_t * > m_ps3studioBatches;
CUtlVector< uint32 > m_ps3studioStripGroupHeaderBatchOffset;
//
// 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
+649
View File
@@ -0,0 +1,649 @@
//====== Copyright © 1996-2005, 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"
DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_ModelLib, "ModelLib", 0, LS_ERROR );
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 ) )
{
Log_Msg( LOG_ModelLib, "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 ) )
{
Log_Msg( LOG_ModelLib, "No special stripping - the model is not a static prop.\n" );
pMsi->m_eMode = CMdlStripInfo::MODE_NO_CHANGE;
return true;
}
if ( vvdHdr->numLODs <= 1 )
{
Log_Msg( LOG_ModelLib, "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 )
{
Log_Msg( LOG_ModelLib, "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 )
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 )
Log_Msg( LOG_ModelLib, " Stripped %d lod(s).\n", vvdHdr->numLODs - 1 );
Log_Msg( LOG_ModelLib, " 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( const mstudiobone_t, mdlBone, mdlHdr, pBone, numbones )
((mstudiobone_t *)mdlBone)->flags &= ( BONE_USED_BY_VERTEX_LOD0 | ~BONE_USED_BY_VERTEX_MASK );
ITERATE_END
Log_Msg( LOG_ModelLib, " 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 );
}
Log_Msg( LOG_ModelLib, " 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;
CMemoryMovingTracker vtxRemove( CMemoryMovingTracker::MEMORY_REMOVE );
CUtlVector< size_t > vtxOffIndex;
CUtlVector< size_t > vtxOffVertex;
vtxRemove.RegisterElements( CHILD_AT( vtxHdr, pMaterialReplacementList, 1 ), vtxHdr->numLODs - 1 );
ITERATE_CHILDREN( OptimizedModel::MaterialReplacementListHeader_t, vtxMatList, vtxHdr, pMaterialReplacementList, numLODs )
if ( !vtxMatList_idx ) continue;
vtxRemove.RegisterElements( CHILD_AT( vtxMatList, pMaterialReplacement, 0 ), vtxMatList->numReplacements );
ITERATE_CHILDREN( OptimizedModel::MaterialReplacementHeader_t, vtxMat, vtxMatList, pMaterialReplacement, numReplacements )
char const *szName = vtxMat->pMaterialReplacementName();
vtxRemove.RegisterElements( 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.RegisterElements( 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.RegisterElements( CHILD_AT( vtxLod, pMesh, 0 ), vtxLod->numMeshes );
ITERATE_CHILDREN( OptimizedModel::MeshHeader_t, vtxMesh, vtxLod, pMesh, numMeshes )
vtxRemove.RegisterElements( CHILD_AT( vtxMesh, pStripGroup, 0 ), vtxMesh->numStripGroups );
ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
vtxRemove.RegisterElements( CHILD_AT( vtxStripGroup, pStrip, 0 ), vtxStripGroup->numStrips );
ITERATE_CHILDREN( OptimizedModel::StripHeader_t, vtxStrip, vtxStripGroup, pStrip, numStrips )
vtxRemove.RegisterElements( 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.RegisterElements( 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.RegisterElements( vtxIndexElement );
}
else
{
// Index is in use and must be remapped
*vtxIndexElement -= vtxIndexDeltas[ *vtxIndexElement ];
}
}
// By now should have scheduled all removal information
vtxRemove.Finalize();
Log_Msg( LOG_ModelLib, " Stripped %d vtx bytes.\n", vtxRemove.GetNumBytesRegistered() );
//
// 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() );
Log_Msg( LOG_ModelLib, " Reduced model buffers by %d bytes.\n", vtxRemove.GetNumBytesRegistered() + ( vvdLengthOld - vvdLength ) );
// Done
return true;
}
//
// ParseMdlMesh
// The main function that parses the mesh buffers
// mdlBuffer - mdl buffer
// vvdBuffer - vvd buffer
// vtxBuffer - vtx buffer
// mesh - on return will be filled with the mesh info
//
bool CMdlLib::ParseMdlMesh( CUtlBuffer &mdlBuffer, CUtlBuffer &vvdBuffer, CUtlBuffer &vtxBuffer, MdlLib::MdlMesh &mesh )
{
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();
DECLARE_PTR( studiohdr_t, mdlHdr, mdl );
DECLARE_PTR( vertexFileHeader_t, vvdHdr, vvd );
DECLARE_PTR( OptimizedModel::FileHeader_t, vtxHdr, vtx );
// Don't do anything if the checksums don't match
if ( ( mdlHdr->checksum != vvdHdr->checksum ) ||
( mdlHdr->checksum != vtxHdr->checkSum ) )
{
Log_Msg( LOG_ModelLib, "ERROR: [ParseMdlMesh] checksum mismatch!\n" );
return false;
}
//
// Early outs
//
if ( vvdHdr->numLODs != 1 )
{
Log_Msg( LOG_ModelLib, "ERROR: [ParseMdlMesh] the model has %d lod(s).\n", vvdHdr->numLODs );
return false;
}
//
// ===================
// =================== Process MDL file
// ===================
//
mesh.checksum = mdlHdr->checksum;
int mdlNumVertices = 0;
ITERATE_CHILDREN( mstudiobodyparts_t, mdlBodyPart, mdlHdr, pBodypart, numbodyparts )
ITERATE_CHILDREN( mstudiomodel_t, mdlModel, mdlBodyPart, pModel, nummodels )
mdlNumVertices = mdlModel->numvertices;
ITERATE_END
ITERATE_END
//
// ===================
// =================== Build out table of indices
// ===================
//
mesh.ib.RemoveAll();
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 )
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;
mesh.ib.AddToTail( usIdx );
}
ITERATE_END
ITERATE_END
ITERATE_END
ITERATE_END
ITERATE_END
//
// ===================
// =================== Build out table of vertices
// ===================
//
mesh.vb.RemoveAll();
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 ), mdlNumVertices * sizeof( *vvdVertexSrc ) ) : 0;
vvdTangentSrc ? memcpy( vvdTangentSrc, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->tangentDataStart ), mdlNumVertices * sizeof( *vvdTangentSrc ) ) : 0;
}
for ( mstudiovertex_t *pSrc = vvdVertexSrc, *pEnd = pSrc + mdlNumVertices;
pSrc < pEnd; ++ pSrc )
{
MdlLib::MdlVertex vert = {0};
vert.position[0] = pSrc->m_vecPosition.x;
vert.position[1] = pSrc->m_vecPosition.y;
vert.position[2] = pSrc->m_vecPosition.z;
vert.normal[0] = pSrc->m_vecNormal.x;
vert.normal[1] = pSrc->m_vecNormal.y;
vert.normal[2] = pSrc->m_vecNormal.z;
vert.texcoord[0] = pSrc->m_vecTexCoord.x;
vert.texcoord[1] = pSrc->m_vecTexCoord.y;
mesh.vb.AddToTail( vert );
}
return true;
}
+277
View File
@@ -0,0 +1,277 @@
//====== Copyright © 1996-2007, 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 );
}
//////////////////////////////////////////////////////////////////////////
//
// CMemoryMovingTracker implementation
//
//////////////////////////////////////////////////////////////////////////
void CMemoryMovingTracker::RegisterBytes( void *pos, int length )
{
if ( length <= 0 && m_ePolicy != MEMORY_MODIFY )
return;
// -- hint
if ( m_map.Count() && m_ePolicy == MEMORY_REMOVE )
{
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 CMemoryMovingTracker::GetNumBytesRegistered() const
{
int iRegistered = 0;
for ( Map::IndexType_t idx = m_map.FirstInorder();
idx != m_map.InvalidIndex(); idx = m_map.NextInorder( idx ) )
{
int numBytes = m_map.Element( idx );
if ( m_ePolicy == MEMORY_MODIFY && numBytes <= 0 )
continue;
iRegistered += numBytes;
}
return iRegistered;
}
void CMemoryMovingTracker::RegisterBaseDelta( void *pOldBase, void *pNewBase )
{
for ( Map::IndexType_t idx = m_map.FirstInorder();
idx != m_map.InvalidIndex(); idx = m_map.NextInorder( idx ) )
{
m_map.Key( idx ) = BYTE_OFF_PTR( m_map.Key( idx ), BYTE_DIFF_PTR( pOldBase, pNewBase ) );
}
m_hint.ptr = BYTE_OFF_PTR( m_hint.ptr, BYTE_DIFF_PTR( pOldBase, pNewBase ) );
}
void CMemoryMovingTracker::Finalize()
{
// Iterate the map and find all the adjacent removal data blocks
// TODO:
}
void CMemoryMovingTracker::MemMove( void *ptrBase, int &length ) const
{
if ( m_ePolicy == MEMORY_REMOVE )
{
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 );
int numBytes = m_map.Element( idx );
byte *ptrDest = BYTE_OFF_PTR( ptr, - iRemoved );
memmove( ptrDest, BYTE_OFF_PTR( ptrDest, numBytes ), BYTE_DIFF_PTR( BYTE_OFF_PTR( ptr, numBytes ), BYTE_OFF_PTR( ptrBase, length ) ) );
iRemoved += numBytes;
}
length -= iRemoved;
}
if ( m_ePolicy == MEMORY_INSERT )
{
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 );
byte *ptrDest = BYTE_OFF_PTR( ptr, numBytes );
memmove( ptrDest, ptr, BYTE_DIFF_PTR( ptr, BYTE_OFF_PTR( ptrBase, length ) ) );
length += numBytes;
}
}
if ( m_ePolicy == MEMORY_MODIFY )
{
// Perform insertions first:
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 );
if ( numBytes <= 0 )
continue; // this is removal
byte *ptrDest = BYTE_OFF_PTR( ptr, numBytes );
memmove( ptrDest, ptr, BYTE_DIFF_PTR( ptr, BYTE_OFF_PTR( ptrBase, length ) ) );
length += numBytes;
}
// Now perform removals accounting for all insertions
// that has happened up to the moment
int numInsertedToPoint = 0;
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 );
int numBytes = m_map.Element( idx );
if ( numBytes >= 0 )
{
numInsertedToPoint += numBytes;
continue; // this is insertion that already happened
}
numBytes = -numBytes;
ptr = BYTE_OFF_PTR( ptr, numInsertedToPoint );
byte *ptrDest = BYTE_OFF_PTR( ptr, - iRemoved );
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 CMemoryMovingTracker::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 * CMemoryMovingTracker::ComputePointer( void *ptrNothingRemoved ) const
{
int iAffected = 0;
// Iterate the map and find all the data that would be removed/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 ) < ptrNothingRemoved )
iAffected += m_map.Element( idx );
else
break;
}
if ( m_ePolicy == MEMORY_REMOVE )
return BYTE_OFF_PTR( ptrNothingRemoved, - iAffected );
if ( m_ePolicy == MEMORY_INSERT || m_ePolicy == MEMORY_MODIFY )
return BYTE_OFF_PTR( ptrNothingRemoved, iAffected );
return ptrNothingRemoved;
}
+212
View File
@@ -0,0 +1,212 @@
//====== Copyright © 1996-2007, 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 )
#define DECLARE_UPDATE_PTR( type, name, initval ) 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
};
//
// CMemoryMovingTracker
// Class that is tracking removals that are scheduled to happen at given points.
// Use policy:
// RegisterBytes / RegisterElements[*] -- schedule moving
// Finalize -- finalize moving information
// ComputePointer / ComputeOffset [*] -- compute new pointers/offsets that will happen after moving
// MemMove -- perform memory moves to apply
//
class CMemoryMovingTracker
{
public:
enum MemoryMovingPolicy_t
{
MEMORY_REMOVE,
MEMORY_INSERT,
MEMORY_MODIFY,
};
explicit CMemoryMovingTracker( MemoryMovingPolicy_t ePolicy ) : m_map( DefLessFunc( byte * ) ), m_ePolicy( ePolicy ) {}
// Schedules a piece of memory for removal
public:
void RegisterBytes( void *pos, int length );
template< typename T >
void RegisterElements( T *ptr, int count = 1 ) { RegisterBytes( ( byte * ) ptr, count * sizeof( T ) ); }
int GetNumBytesRegistered() const;
// Finalizes the removal information
public:
void RegisterBaseDelta( void *pOldBase, void *pNewBase );
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;
MemoryMovingPolicy_t m_ePolicy;
};
//
// 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 CLargeVarBitVec
{
public:
void GrowSetBit( int iBit )
{
if ( iBit >= GetNumBits() )
Resize( iBit + 1, false );
Set( iBit );
}
bool IsBitSet( int bitNum ) const
{
return ( bitNum < GetNumBits() ) && CLargeVarBitVec::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