mirror of
https://github.com/mapbase-source/source-sdk-2013.git
synced 2025-02-11 06:18:51 +03:00
* Adds support for Visual Studio 2012 and 2013 * VR Mode: . Switches from headtrack.dll to sourcevr.dll . Improved readability of the UI in VR . Removed the IPD calibration tool. TF2 will now obey the Oculus configuration file. Use the Oculus calibration tool in your SDK or install and run "OpenVR" under Tools in Steam to calibrate your IPD. . Added dropdown to enable VR mode in the Video options. Removed the -vr command line option. . Added the ability to switch in and out of VR mode without quitting the game . By default VR mode will run full screen. To switch back to a borderless window set the vr_force_windowed convar. . Added support for VR mode on Linux * Many assorted bug fixes and other changes from Team Fortress in various shared files
3169 lines
108 KiB
C++
3169 lines
108 KiB
C++
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose: Swaps the bytes in all file types generated by studiomdl
|
|
// (.vvd, .vtx, .mdl, .phy, .ani) so the files can be loaded
|
|
// on a big-endian machine, specifically the Xbox360. A new file is generated
|
|
// with an extra extension in the form of <filename>.360.<ext>
|
|
//
|
|
//=============================================================================//
|
|
|
|
#include "studio.h"
|
|
#include "optimize.h"
|
|
#include "phyfile.h"
|
|
#include "studiobyteswap.h"
|
|
#include "vphysics_interface.h"
|
|
|
|
#undef ALIGN4
|
|
#undef ALIGN16
|
|
#undef ALIGN32
|
|
#define ALIGN4( a ) a = (byte *)((int)((byte *)a + 3) & ~ 3)
|
|
#define ALIGN16( a ) a = (byte *)((int)((byte *)a + 15) & ~ 15)
|
|
#define ALIGN32( a ) a = (byte *)((int)((byte *)a + 31) & ~ 31)
|
|
#define ALIGN64( a ) a = (byte *)((int)((byte *)a + 63) & ~ 63)
|
|
|
|
// Fixup macros create variables that may not be referenced
|
|
#pragma warning( push )
|
|
#pragma warning( disable:4189 ) // local variable is initialized but not referenced
|
|
#pragma warning( disable:4366 ) // The result of the unary '&' operator may be unaligned
|
|
|
|
namespace StudioByteSwap
|
|
{
|
|
|
|
static bool g_bVerbose = true;
|
|
static bool g_bNativeSrc;
|
|
static CByteswap g_Swap;
|
|
static IPhysicsCollision *pCollision;
|
|
static CompressFunc_t g_pCompressFunc;
|
|
|
|
void ActivateByteSwapping( bool activate )
|
|
{
|
|
g_Swap.ActivateByteSwapping( activate );
|
|
SourceIsNative( IsPC() );
|
|
}
|
|
|
|
void SourceIsNative( bool bNative )
|
|
{
|
|
g_bNativeSrc = bNative;
|
|
}
|
|
|
|
void SetCollisionInterface( IPhysicsCollision *pPhysicsCollision )
|
|
{
|
|
pCollision = pPhysicsCollision;
|
|
}
|
|
|
|
void SetVerbose( bool bVerbose )
|
|
{
|
|
g_bVerbose = bVerbose;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Helper to write a chunk of objects of the same type, and increment the buffer pointers.
|
|
//----------------------------------------------------------------------
|
|
template<class T> inline void WriteObjects( byte **pOutputBuffer, byte **pBaseData, int objectCount = 1 )
|
|
{
|
|
T tempObject;
|
|
for ( int i = 0; i < objectCount; ++i )
|
|
{
|
|
Q_memcpy( &tempObject, *pBaseData, sizeof(T) );
|
|
g_Swap.SwapFieldsToTargetEndian( &tempObject, &tempObject );
|
|
Q_memcpy( *pOutputBuffer, &tempObject, sizeof(T) );
|
|
*pOutputBuffer += sizeof(T);
|
|
*pBaseData += sizeof(T);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Helper to write a chunk of objects of the same type, and increment the buffer pointers.
|
|
//----------------------------------------------------------------------
|
|
template<class T> inline void WriteObjects( T **pOutputBuffer, T **pBaseData, int objectCount = 1 )
|
|
{
|
|
T tempObject;
|
|
for ( int i = 0; i < objectCount; ++i )
|
|
{
|
|
Q_memcpy( &tempObject, *pBaseData, sizeof(T) );
|
|
g_Swap.SwapFieldsToTargetEndian( &tempObject, &tempObject );
|
|
Q_memcpy( *pOutputBuffer, &tempObject, sizeof(T) );
|
|
++*pOutputBuffer;
|
|
++*pBaseData;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Helper to write a chunk of objects of the same type.
|
|
//----------------------------------------------------------------------
|
|
template<class T> inline void WriteObjects( byte *pOutputBuffer, byte *pBaseData, int objectCount = 1 )
|
|
{
|
|
T tempObject;
|
|
for ( int i = 0; i < objectCount; ++i )
|
|
{
|
|
Q_memcpy( &tempObject, pBaseData, sizeof(T) );
|
|
g_Swap.SwapFieldsToTargetEndian( &tempObject, &tempObject );
|
|
Q_memcpy( pOutputBuffer, &tempObject, sizeof(T) );
|
|
pOutputBuffer += sizeof(T);
|
|
pBaseData += sizeof(T);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Helper to write a chunk of objects of the same type.
|
|
//----------------------------------------------------------------------
|
|
template<class T> inline void WriteObjects( T *pOutputBuffer, T *pBaseData, int objectCount = 1 )
|
|
{
|
|
T tempObject;
|
|
for ( int i = 0; i < objectCount; ++i )
|
|
{
|
|
Q_memcpy( &tempObject, pBaseData, sizeof(T) );
|
|
g_Swap.SwapFieldsToTargetEndian( &tempObject, &tempObject );
|
|
Q_memcpy( pOutputBuffer, &tempObject, sizeof(T) );
|
|
++pOutputBuffer;
|
|
++pBaseData;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Helper to write a buffer of some integral type, and increment the buffer pointers.
|
|
//----------------------------------------------------------------------
|
|
template<class T> inline void WriteBuffer( byte **pOutputBuffer, byte **pBaseData, int objectCount = 1 )
|
|
{
|
|
T tempObject;
|
|
for ( int i = 0; i < objectCount; ++i )
|
|
{
|
|
Q_memcpy( &tempObject, *pBaseData, sizeof(T) );
|
|
g_Swap.SwapBufferToTargetEndian( &tempObject, &tempObject );
|
|
Q_memcpy( *pOutputBuffer, &tempObject, sizeof(T) );
|
|
*pOutputBuffer += sizeof(T);
|
|
*pBaseData += sizeof(T);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Helper to write a buffer of some integral type
|
|
//----------------------------------------------------------------------
|
|
template<class T> inline void WriteBuffer( byte *pOutputBuffer, byte *pBaseData, int objectCount = 1 )
|
|
{
|
|
T tempObject;
|
|
for ( int i = 0; i < objectCount; ++i )
|
|
{
|
|
Q_memcpy( &tempObject, pBaseData, sizeof(T) );
|
|
g_Swap.SwapBufferToTargetEndian( &tempObject, &tempObject );
|
|
Q_memcpy( pOutputBuffer, &tempObject, sizeof(T) );
|
|
pOutputBuffer += sizeof(T);
|
|
pBaseData += sizeof(T);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// For getting values in the correct source/dest endian format
|
|
//----------------------------------------------------------------------
|
|
template< class T >
|
|
T SrcNative( T *idx )
|
|
{
|
|
T ret = *idx;
|
|
if ( !g_bNativeSrc )
|
|
{
|
|
g_Swap.SwapBuffer( &ret, idx );
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
template< class T >
|
|
T DestNative( T *idx )
|
|
{
|
|
T ret = *idx;
|
|
if ( g_bNativeSrc )
|
|
{
|
|
g_Swap.SwapBuffer( &ret, idx );
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Declares objects pointers for src/dest buffer
|
|
//----------------------------------------------------------------------
|
|
#define DECLARE_OBJECT_POINTERS( objPtr, base, type ) \
|
|
type* objPtr##Src = (type*)base##Src; \
|
|
type* objPtr##Dest = (type*)base##Dest; \
|
|
type* objPtr = objPtr##Src;
|
|
|
|
//----------------------------------------------------------------------
|
|
// Declares src/dest byte pointers and sets them to some index offset in the buffers.
|
|
//----------------------------------------------------------------------
|
|
#define DECLARE_INDEX_POINTERS( ptr, base, index ) \
|
|
byte *ptr##Src = (byte*)base##Src + SrcNative( &base##Src->index ); \
|
|
byte *ptr##Dest = (byte*)base##Dest + SrcNative( &base##Src->index );
|
|
|
|
//----------------------------------------------------------------------
|
|
// Declares src/dest byte pointers and sets them to some index offset in the buffers.
|
|
// If src pointer is misaligned, the fixup method is called.
|
|
//----------------------------------------------------------------------
|
|
#define DECLARE_INDEX_POINTERS_FIXUP( ptr, base, index ) \
|
|
byte *ptr##Src = (byte*)base##Src + SrcNative( &base##Src->index ); \
|
|
byte *ptr##Dest = (byte*)base##Dest + SrcNative( &base##Src->index ); \
|
|
FIXUP_OFFSETS( ptr, base, index )
|
|
|
|
//----------------------------------------------------------------------
|
|
// Same as DECLARE_OBJECT_POINTERS, but reuses existing type pointers.
|
|
//----------------------------------------------------------------------
|
|
#define SET_OBJECT_POINTERS( objPtr, base, type ) \
|
|
objPtr##Src = (type*)base##Src; \
|
|
objPtr##Dest = (type*)base##Dest; \
|
|
objPtr = objPtr##Src;
|
|
|
|
//----------------------------------------------------------------------
|
|
// Same as DECLARE_INDEX_POINTERS, but reuses existing byte pointers.
|
|
//----------------------------------------------------------------------
|
|
#define SET_INDEX_POINTERS( ptr, base, index ) \
|
|
ptr##Src = (byte*)base##Src + SrcNative( &base##Src->index ); \
|
|
ptr##Dest = (byte*)base##Dest + SrcNative( &base##Src->index );
|
|
|
|
//----------------------------------------------------------------------
|
|
// Same as DECLARE_INDEX_POINTERS, but reuses existing byte pointers.
|
|
// If src pointer is misaligned, the fixup method is called.
|
|
//----------------------------------------------------------------------
|
|
#define SET_INDEX_POINTERS_FIXUP( ptr, base, index ) \
|
|
ptr##Src = (byte*)base##Src + SrcNative( &base##Src->index ); \
|
|
ptr##Dest = (byte*)base##Dest + SrcNative( &base##Src->index ); \
|
|
FIXUP_OFFSETS( ptr, base, index )
|
|
|
|
//----------------------------------------------------------------------
|
|
// for() loop header, updates all three object pointers (src,dest,native)
|
|
//----------------------------------------------------------------------
|
|
#define ITERATE_BLOCK( objPtr, count ) \
|
|
for ( int objPtr##_idx = 0; objPtr##_idx < SrcNative( &count ); ++objPtr##_idx, ++objPtr, ++objPtr##Src, ++objPtr##Dest )
|
|
|
|
//----------------------------------------------------------------------
|
|
// Checks for misaligned source pointer, then calculates the necessary fixup,
|
|
// calls the fixup function, and sets the src pointer to the new position.
|
|
//----------------------------------------------------------------------
|
|
#define FIXUP_OFFSETS( ptr, base, index ) \
|
|
{ \
|
|
byte *ptr##Fixup = ptr##Src; \
|
|
ALIGN4( ptr##Fixup ); \
|
|
if ( ptr##Fixup != ptr##Src ) \
|
|
{ \
|
|
int nShiftBytes = ptr##Fixup - ptr##Src; \
|
|
if ( g_bVerbose ) \
|
|
Warning( "Shifting misaligned data block by %d bytes at " #base "->" #index "\n", nShiftBytes ); \
|
|
int prevBytes = (byte*)ptr##Src - (byte*)g_pDataSrcBase; \
|
|
Q_memmove( (byte*)ptr##Src + nShiftBytes, ptr##Src, fixedFileSize - prevBytes ); \
|
|
g_pFixPoint = ptr##Src; \
|
|
g_nFixupBytes = nShiftBytes; \
|
|
fixedFileSize += nShiftBytes; \
|
|
if ( fixedFileSize > fileSize + BYTESWAP_ALIGNMENT_PADDING ) \
|
|
{ \
|
|
Error( "Byteswap buffer overrun - increase BYTESWAP_ALIGNMENT_PADDING!\n" ); \
|
|
return 0; \
|
|
} \
|
|
g_pfnFileProcessFunc( pHdrSrc, UpdateSrcIndexFields ); \
|
|
g_pFixPoint = NULL; \
|
|
g_nFixupBytes = 0; \
|
|
ptr##Src = ptr##Fixup; \
|
|
} \
|
|
}
|
|
|
|
|
|
typedef void ( *datadescProcessFunc_t)( void *pBase, void *pData, typedescription_t *pFields );
|
|
typedef void ( *pfnFixupFunc_t )( void *pDestBase, datadescProcessFunc_t );
|
|
|
|
static pfnFixupFunc_t g_pfnFileProcessFunc;
|
|
static studiohdr_t *g_pHdr;
|
|
static const void *g_pDataSrcBase;
|
|
static void *g_pFixPoint;
|
|
static int g_nFixupBytes;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
bool UpdateIndex( void *pBase, int *indexMember )
|
|
{
|
|
bool bUpdateIndex = false;
|
|
int idx = *indexMember;
|
|
|
|
// Update the index fields
|
|
if ( pBase < g_pFixPoint )
|
|
{
|
|
if ( (byte*)pBase + idx >= g_pFixPoint )
|
|
{
|
|
bUpdateIndex = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( (byte*)pBase + idx < g_pFixPoint )
|
|
{
|
|
bUpdateIndex = true;
|
|
}
|
|
}
|
|
|
|
// Update the member offset by the global fixup
|
|
if ( bUpdateIndex && *indexMember )
|
|
{
|
|
*indexMember = idx + g_nFixupBytes * Sign(idx);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
int GetIntegerFromField( void *pData, int fieldType )
|
|
{
|
|
if ( fieldType == FIELD_INTEGER )
|
|
{
|
|
return SrcNative( (int*)pData );
|
|
}
|
|
else if ( fieldType == FIELD_SHORT )
|
|
{
|
|
return SrcNative( (short*)pData );
|
|
}
|
|
Error( "Byteswap macro DEFINE_INDEX using unsupported fieldType %d\n", fieldType );
|
|
return 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void PutIntegerInField( void *pData, int index, int fieldType )
|
|
{
|
|
if ( fieldType == FIELD_INTEGER )
|
|
{
|
|
*(int*)pData = SrcNative( &index );
|
|
}
|
|
else if ( fieldType == FIELD_SHORT )
|
|
{
|
|
*(short*)pData = SrcNative( &index );
|
|
}
|
|
else
|
|
{
|
|
Error( "Byteswap macro DEFINE_INDEX using unsupported fieldType %d\n", fieldType );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void UpdateSrcIndexFields( void *pBase, void *pData, typedescription_t *pField )
|
|
{
|
|
if ( pField->flags & FTYPEDESC_INDEX )
|
|
{
|
|
int index = GetIntegerFromField( pData, pField->fieldType );
|
|
if ( UpdateIndex( pBase, &index ) )
|
|
{
|
|
PutIntegerInField( pData, index, pField->fieldType );
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Pass a datadesc field to a processing function
|
|
//-----------------------------------------------------------------------------
|
|
void ProcessField( void *pBase, void *pData, typedescription_t *pField, datadescProcessFunc_t pfn )
|
|
{
|
|
if ( pfn )
|
|
{
|
|
pfn( pBase, pData, pField );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Process the fields of a datadesc.
|
|
//-----------------------------------------------------------------------------
|
|
void ProcessFields( void *pBaseAddress, void *pData, datamap_t *pDataMap, datadescProcessFunc_t pfnProcessFunc )
|
|
{
|
|
// deal with base class first
|
|
if ( pDataMap->baseMap )
|
|
{
|
|
ProcessFields( pBaseAddress, pData, pDataMap->baseMap, pfnProcessFunc );
|
|
}
|
|
|
|
typedescription_t *pFields = pDataMap->dataDesc;
|
|
int fieldCount = pDataMap->dataNumFields;
|
|
for ( int i = 0; i < fieldCount; ++i )
|
|
{
|
|
typedescription_t *pField = &pFields[i];
|
|
ProcessField( pBaseAddress, (BYTE*)pData + pField->fieldOffset[ TD_OFFSET_NORMAL ], pField, pfnProcessFunc );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Process the fields of a datadesc.
|
|
//-----------------------------------------------------------------------------
|
|
void ProcessFields( void *pData, datamap_t *pDataMap, datadescProcessFunc_t pfnProcessFunc )
|
|
{
|
|
ProcessFields( pData, pData, pDataMap, pfnProcessFunc );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Process a datadesc field by name
|
|
//-----------------------------------------------------------------------------
|
|
void ProcessFieldByName( void *pBaseAddress, void *pData, datamap_t *pDataMap, const char *pName, datadescProcessFunc_t pfnProcessFunc )
|
|
{
|
|
// deal with base class first
|
|
if ( pDataMap->baseMap )
|
|
{
|
|
ProcessFieldByName( pBaseAddress, pData, pDataMap->baseMap, pName, pfnProcessFunc );
|
|
}
|
|
|
|
typedescription_t *pFields = pDataMap->dataDesc;
|
|
int fieldCount = pDataMap->dataNumFields;
|
|
for ( int i = 0; i < fieldCount; ++i )
|
|
{
|
|
typedescription_t *pField = &pFields[i];
|
|
if ( !Q_stricmp( pField->fieldName, pName ) )
|
|
{
|
|
ProcessField( pBaseAddress, (BYTE*)pData + pField->fieldOffset[ TD_OFFSET_NORMAL ], pField, pfnProcessFunc );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Process a datadesc field by name.
|
|
//-----------------------------------------------------------------------------
|
|
void ProcessFieldByName( void *pData, datamap_t *pDataMap, const char *pName, datadescProcessFunc_t pfnProcessFunc )
|
|
{
|
|
ProcessFieldByName( pData, pData, pDataMap, pName, pfnProcessFunc );
|
|
}
|
|
|
|
void ProcessANIFields( void *pDataBase, datadescProcessFunc_t pfnProcessFunc );
|
|
void ProcessMDLFields( void *pDataBase, datadescProcessFunc_t pfnProcessFunc );
|
|
|
|
// Fake header declaration for easier phy swapping
|
|
struct swapcompactsurfaceheader_t
|
|
{
|
|
DECLARE_BYTESWAP_DATADESC();
|
|
int size;
|
|
int vphysicsID;
|
|
short version;
|
|
short modelType;
|
|
int surfaceSize;
|
|
Vector dragAxisAreas;
|
|
int axisMapSize;
|
|
};
|
|
|
|
BEGIN_BYTESWAP_DATADESC( swapcompactsurfaceheader_t )
|
|
DEFINE_FIELD( size, FIELD_INTEGER ),
|
|
DEFINE_FIELD( vphysicsID, FIELD_INTEGER ),
|
|
DEFINE_FIELD( version, FIELD_SHORT ),
|
|
DEFINE_FIELD( modelType, FIELD_SHORT ),
|
|
DEFINE_FIELD( surfaceSize, FIELD_INTEGER ),
|
|
DEFINE_FIELD( dragAxisAreas, FIELD_VECTOR ),
|
|
DEFINE_FIELD( axisMapSize, FIELD_INTEGER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
// Fake header declaration for old style phy format
|
|
#if defined( _X360 )
|
|
#pragma bitfield_order( push, lsb_to_msb )
|
|
#endif
|
|
struct legacysurfaceheader_t
|
|
{
|
|
DECLARE_BYTESWAP_DATADESC();
|
|
int size;
|
|
float mass_center[3];
|
|
float rotation_inertia[3];
|
|
float upper_limit_radius;
|
|
BEGIN_BITFIELD( bf )
|
|
int max_deviation : 8;
|
|
int byte_size : 24;
|
|
END_BITFIELD()
|
|
int offset_ledgetree_root;
|
|
int dummy[3];
|
|
};
|
|
#if defined( _X360 )
|
|
#pragma bitfield_order( pop )
|
|
#endif
|
|
|
|
BEGIN_BYTESWAP_DATADESC( legacysurfaceheader_t )
|
|
DEFINE_FIELD( size, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( mass_center, FIELD_FLOAT, 3 ),
|
|
DEFINE_ARRAY( rotation_inertia, FIELD_FLOAT, 3 ),
|
|
DEFINE_FIELD( upper_limit_radius, FIELD_FLOAT ),
|
|
DEFINE_BITFIELD( bf, FIELD_INTEGER, 32 ),
|
|
DEFINE_FIELD( offset_ledgetree_root, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( dummy, FIELD_INTEGER, 3 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
//----------------------------------------------------------------------
|
|
// Swap a .phy file
|
|
// Fixes alignment errors
|
|
//----------------------------------------------------------------------
|
|
int ByteswapPHY( void *pDestBase, const void *pSrcBase, const int fileSize )
|
|
{
|
|
Assert( pCollision );
|
|
if ( !pCollision )
|
|
return 0;
|
|
|
|
Q_memset( pDestBase, 0, fileSize );
|
|
|
|
byte *pSrc = (byte*)pSrcBase;
|
|
byte *pDest = (byte*)pDestBase;
|
|
vcollide_t collide = {0};
|
|
|
|
// file header
|
|
phyheader_t *pHdr = (phyheader_t*)( g_bNativeSrc ? pSrc : pDest );
|
|
WriteObjects<phyheader_t>( &pDest, &pSrc );
|
|
|
|
if ( g_bNativeSrc )
|
|
{
|
|
// Reset the pointers and let ivp swap the binary physics data
|
|
pSrc = (byte*)pSrcBase + pHdr->size;
|
|
pDest = (byte*)pDestBase + pHdr->size;
|
|
|
|
int bufSize = fileSize - pHdr->size;
|
|
pCollision->VCollideLoad( &collide, pHdr->solidCount, (const char *)pSrc, bufSize, false );
|
|
}
|
|
|
|
// Swap the collision data headers
|
|
for ( int i = 0; i < pHdr->solidCount; ++i )
|
|
{
|
|
swapcompactsurfaceheader_t *baseHdr = (swapcompactsurfaceheader_t*)( g_bNativeSrc ? pSrc : pDest );
|
|
WriteObjects<swapcompactsurfaceheader_t>( pDest, pSrc );
|
|
|
|
int srcIncrement = baseHdr->surfaceSize + sizeof(swapcompactsurfaceheader_t);
|
|
int destIncrement = srcIncrement;
|
|
bool bCopyToSrc = !g_bNativeSrc;
|
|
|
|
if ( baseHdr->vphysicsID != MAKEID('V','P','H','Y') )
|
|
{
|
|
// May be old phy format
|
|
legacysurfaceheader_t *legacyHdr = (legacysurfaceheader_t*)( g_bNativeSrc ? pSrc : pDest );
|
|
WriteObjects<legacysurfaceheader_t>( pDest, pSrc );
|
|
if ( legacyHdr->dummy[2] == MAKEID('I','V','P','S') || legacyHdr->dummy[2] == 0 )
|
|
{
|
|
srcIncrement = legacyHdr->byte_size + sizeof(int);
|
|
destIncrement = legacyHdr->byte_size + sizeof(swapcompactsurfaceheader_t);
|
|
bCopyToSrc = false;
|
|
|
|
if ( !g_bNativeSrc )
|
|
{
|
|
// src needs the size member to be native to load vcollides
|
|
Q_memcpy( pSrc, pDest, sizeof(int) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Not recognized
|
|
Assert(0);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if ( bCopyToSrc )
|
|
{
|
|
// src needs the native header data to load the vcollides
|
|
Q_memcpy( pSrc, pDest, sizeof(swapcompactsurfaceheader_t) );
|
|
}
|
|
|
|
pSrc += srcIncrement;
|
|
pDest += destIncrement;
|
|
}
|
|
|
|
// the rest of the file is text
|
|
int currPos = pSrc - (byte*)pSrcBase;
|
|
int remainingBytes = fileSize - currPos;
|
|
WriteBuffer<char>( &pDest, &pSrc, remainingBytes );
|
|
|
|
if ( !g_bNativeSrc )
|
|
{
|
|
// let ivp swap the ledge tree
|
|
pSrc = (byte*)pSrcBase + pHdr->size;
|
|
int bufSize = fileSize - pHdr->size;
|
|
pCollision->VCollideLoad( &collide, pHdr->solidCount, (const char *)pSrc, bufSize, true );
|
|
}
|
|
|
|
// Write out the ledge tree data
|
|
pDest = (byte*)pDestBase + pHdr->size;
|
|
for ( int i = 0; i < collide.solidCount; ++i )
|
|
{
|
|
// skip over the size
|
|
pDest += sizeof(int);
|
|
int offset = pCollision->CollideWrite( (char*)pDest, collide.solids[i], g_bNativeSrc );
|
|
int destSize = g_bNativeSrc ? SwapLong( offset ) : offset;
|
|
Q_memcpy( pDest - sizeof(int), &destSize, sizeof(int) );
|
|
pDest += offset;
|
|
}
|
|
|
|
// Free the memory
|
|
pCollision->VCollideUnload( &collide );
|
|
|
|
int newFileSize = pDest - (byte*)pDestBase + remainingBytes;
|
|
|
|
if ( g_pCompressFunc )
|
|
{
|
|
// compress entire swapped PHY
|
|
void *pInput = pDestBase;
|
|
int inputSize = newFileSize;
|
|
void *pOutput;
|
|
int outputSize;
|
|
if ( g_pCompressFunc( pInput, inputSize, &pOutput, &outputSize ) )
|
|
{
|
|
// put the compressed version in its place
|
|
V_memcpy( pDestBase, pOutput, outputSize );
|
|
free( pOutput );
|
|
newFileSize = outputSize;
|
|
}
|
|
}
|
|
|
|
return newFileSize;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Swap a .vvd file
|
|
// Doesn't do any alignment fixups
|
|
//----------------------------------------------------------------------
|
|
int ByteswapVVD( void *pDestBase, const void *pSrcBase, const int fileSize )
|
|
{
|
|
Q_memset( pDestBase, 0, fileSize );
|
|
|
|
byte *pDataSrc = (byte*)pSrcBase;
|
|
byte *pDataDest = (byte*)pDestBase;
|
|
|
|
/** FILE HEADER **/
|
|
|
|
DECLARE_OBJECT_POINTERS( pHdr, pData, vertexFileHeader_t )
|
|
WriteObjects<vertexFileHeader_t>( &pDataDest, &pDataSrc );
|
|
|
|
/** FIXUP TABLE **/
|
|
|
|
SET_INDEX_POINTERS( pData, pHdr, fixupTableStart )
|
|
WriteObjects<vertexFileFixup_t>( &pDataDest, &pDataSrc, SrcNative( &pHdr->numFixups ) );
|
|
|
|
/** VERTEX DATA **/
|
|
|
|
SET_INDEX_POINTERS( pData, pHdr, vertexDataStart )
|
|
WriteObjects<mstudiovertex_t>( &pDataDest, &pDataSrc, SrcNative( &pHdr->numLODVertexes[0] ) );
|
|
|
|
/** TANGENT DATA **/
|
|
|
|
if ( pHdr->tangentDataStart != 0 )
|
|
{
|
|
SET_INDEX_POINTERS( pData, pHdr, tangentDataStart )
|
|
WriteBuffer<float>( &pDataDest, &pDataSrc, 4 * SrcNative( &pHdr->numLODVertexes[0] ) );
|
|
}
|
|
|
|
int newFileSize = pDataDest - (byte*)pDestBase;
|
|
|
|
if ( g_pCompressFunc )
|
|
{
|
|
void *pInput = (byte*)pDestBase + sizeof( vertexFileHeader_t );
|
|
int inputSize = newFileSize - sizeof( vertexFileHeader_t );
|
|
void *pOutput;
|
|
int outputSize;
|
|
if ( g_pCompressFunc( pInput, inputSize, &pOutput, &outputSize ) )
|
|
{
|
|
// place the compressed data after the header
|
|
V_memcpy( pInput, pOutput, outputSize );
|
|
free( pOutput );
|
|
newFileSize = sizeof( vertexFileHeader_t ) + outputSize;
|
|
}
|
|
}
|
|
|
|
return newFileSize;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// Swap a .vtx file
|
|
// Doesn't do any alignment fixups
|
|
//----------------------------------------------------------------------
|
|
int ByteswapVTX( void *pDestBase, const void *pSrcBase, const int fileSize )
|
|
{
|
|
Q_memset( pDestBase, 0, fileSize );
|
|
|
|
// Do a straight copy first so the string table is transferred
|
|
memcpy( pDestBase, pSrcBase, fileSize );
|
|
|
|
// Start writing the file
|
|
byte *pDataSrc = (byte*)pSrcBase;
|
|
byte *pDataDest = (byte*)pDestBase;
|
|
|
|
DECLARE_OBJECT_POINTERS( pVtxHeader, pData, OptimizedModel::FileHeader_t )
|
|
WriteObjects( pVtxHeaderDest, pVtxHeaderSrc );
|
|
|
|
/** BODY PARTS **/
|
|
|
|
SET_INDEX_POINTERS( pData, pVtxHeader, bodyPartOffset )
|
|
DECLARE_OBJECT_POINTERS( pBodyPartHeader, pData, OptimizedModel::BodyPartHeader_t )
|
|
ITERATE_BLOCK( pBodyPartHeader, pVtxHeader->numBodyParts )
|
|
{
|
|
WriteObjects( pBodyPartHeaderDest, pBodyPartHeaderSrc );
|
|
|
|
/** MODELS **/
|
|
|
|
SET_INDEX_POINTERS( pData, pBodyPartHeader, modelOffset )
|
|
DECLARE_OBJECT_POINTERS( pModelHeader, pData, OptimizedModel::ModelHeader_t )
|
|
ITERATE_BLOCK( pModelHeader, pBodyPartHeader->numModels )
|
|
{
|
|
WriteObjects( pModelHeaderDest, pModelHeaderSrc );
|
|
|
|
/** MODEL LODS **/
|
|
|
|
unsigned int meshOffset = 0;
|
|
SET_INDEX_POINTERS( pData, pModelHeader, lodOffset )
|
|
DECLARE_OBJECT_POINTERS( pModelLODHeader, pData, OptimizedModel::ModelLODHeader_t )
|
|
ITERATE_BLOCK( pModelLODHeader, pModelHeader->numLODs )
|
|
{
|
|
WriteObjects( pModelLODHeaderDest, pModelLODHeaderSrc );
|
|
|
|
/** MESHES **/
|
|
|
|
unsigned int prevOffset = meshOffset;
|
|
meshOffset = SrcNative( &pModelLODHeader->meshOffset );
|
|
if ( prevOffset - sizeof(OptimizedModel::ModelLODHeader_t) == meshOffset )
|
|
{
|
|
// This LOD shares data with the previous LOD - don't reswap.
|
|
continue;
|
|
}
|
|
|
|
SET_INDEX_POINTERS( pData, pModelLODHeader, meshOffset )
|
|
DECLARE_OBJECT_POINTERS( pMeshHeader, pData, OptimizedModel::MeshHeader_t )
|
|
ITERATE_BLOCK( pMeshHeader, pModelLODHeader->numMeshes )
|
|
{
|
|
WriteObjects( pMeshHeaderDest, pMeshHeaderSrc );
|
|
|
|
/** STRIP GROUPS **/
|
|
|
|
SET_INDEX_POINTERS( pData, pMeshHeader, stripGroupHeaderOffset )
|
|
DECLARE_OBJECT_POINTERS( pStripGroupHeader, pData, OptimizedModel::StripGroupHeader_t )
|
|
ITERATE_BLOCK( pStripGroupHeader, pMeshHeader->numStripGroups )
|
|
{
|
|
WriteObjects( pStripGroupHeaderDest, pStripGroupHeaderSrc );
|
|
|
|
/** STRIP VERTS **/
|
|
|
|
SET_INDEX_POINTERS( pData, pStripGroupHeader, vertOffset )
|
|
WriteObjects<OptimizedModel::Vertex_t>( pDataDest, pDataSrc, SrcNative( &pStripGroupHeader->numVerts ) );
|
|
|
|
/** VERT INDICES **/
|
|
|
|
SET_INDEX_POINTERS( pData, pStripGroupHeader, indexOffset )
|
|
WriteBuffer<short>( pDataDest, pDataSrc, SrcNative( &pStripGroupHeader->numIndices ) );
|
|
|
|
/** STRIPS **/
|
|
|
|
SET_INDEX_POINTERS( pData, pStripGroupHeader, stripOffset )
|
|
DECLARE_OBJECT_POINTERS( pStripHeader, pData, OptimizedModel::StripHeader_t )
|
|
ITERATE_BLOCK( pStripHeader, pStripGroupHeader->numStrips )
|
|
{
|
|
WriteObjects( pStripHeaderDest, pStripHeaderSrc );
|
|
|
|
/** BONE STATE CHANGES **/
|
|
|
|
SET_INDEX_POINTERS( pData, pStripHeader, boneStateChangeOffset )
|
|
WriteObjects<OptimizedModel::BoneStateChangeHeader_t>( pDataDest, pDataSrc, SrcNative( &pStripHeader->numBoneStateChanges ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** MATERIAL REPLACEMENT HEADERS **/
|
|
|
|
SET_INDEX_POINTERS( pData, pVtxHeader, materialReplacementListOffset )
|
|
DECLARE_OBJECT_POINTERS( pMatRepListHeader, pData, OptimizedModel::MaterialReplacementListHeader_t )
|
|
ITERATE_BLOCK( pMatRepListHeader, pVtxHeader->numLODs )
|
|
{
|
|
WriteObjects( pMatRepListHeaderDest, pMatRepListHeaderSrc );
|
|
|
|
/** MATERIAL REPLACEMENTS **/
|
|
|
|
SET_INDEX_POINTERS( pData, pMatRepListHeader, replacementOffset )
|
|
WriteObjects<OptimizedModel::MaterialReplacementHeader_t>( &pDataDest, &pDataSrc, SrcNative( &pMatRepListHeader->numReplacements ) );
|
|
}
|
|
|
|
int newFileSize = fileSize;
|
|
|
|
if ( g_pCompressFunc )
|
|
{
|
|
void *pInput = (byte*)pDestBase + sizeof( OptimizedModel::FileHeader_t );
|
|
int inputSize = fileSize - sizeof( OptimizedModel::FileHeader_t );
|
|
void *pOutput;
|
|
int outputSize;
|
|
if ( g_pCompressFunc( pInput, inputSize, &pOutput, &outputSize ) )
|
|
{
|
|
// place the compressed data after the header
|
|
V_memcpy( pInput, pOutput, outputSize );
|
|
free( pOutput );
|
|
newFileSize = sizeof( OptimizedModel::FileHeader_t ) + outputSize;
|
|
}
|
|
}
|
|
|
|
return newFileSize;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Swap animation data
|
|
// Fixes alignment errors
|
|
//----------------------------------------------------------------------
|
|
|
|
void ByteswapAnimData( mstudioanimdesc_t *pAnimDesc, int section, byte *&pDataSrc, byte *&pDataDest )
|
|
{
|
|
/** ANIMATIONS **/
|
|
DECLARE_OBJECT_POINTERS( pAnimation, pData, mstudioanim_t )
|
|
WriteObjects( pAnimationDest, pAnimationSrc );
|
|
if ( pAnimation->bone == 255 )
|
|
{
|
|
// No animation data
|
|
pAnimation = 0;
|
|
}
|
|
|
|
while( pAnimation )
|
|
{
|
|
if ( pAnimation->flags & ( STUDIO_ANIM_RAWROT | STUDIO_ANIM_RAWPOS | STUDIO_ANIM_RAWROT2 ) )
|
|
{
|
|
if ( pAnimation->flags & STUDIO_ANIM_RAWROT )
|
|
{
|
|
int offset = (byte*)pAnimation->pQuat48() - (byte*)pAnimation;
|
|
pDataSrc = (byte*)pAnimationSrc + offset;
|
|
pDataDest = (byte*)pAnimationDest + offset;
|
|
|
|
// Write the quaternion (bit fields contained in 3 unsigned shorts)
|
|
WriteBuffer<short>( &pDataDest, &pDataSrc, 3 );
|
|
}
|
|
|
|
if ( pAnimation->flags & STUDIO_ANIM_RAWROT2 )
|
|
{
|
|
int offset = (byte*)pAnimation->pQuat64() - (byte*)pAnimation;
|
|
pDataSrc = (byte*)pAnimationSrc + offset;
|
|
pDataDest = (byte*)pAnimationDest + offset;
|
|
|
|
// Write the quaternion (bit fields contained in 1 64 bit int
|
|
WriteBuffer<int64>( &pDataDest, &pDataSrc, 1 );
|
|
}
|
|
|
|
if ( pAnimation->flags & STUDIO_ANIM_RAWPOS )
|
|
{
|
|
int offset = (byte*)pAnimation->pPos() - (byte*)pAnimation;
|
|
pDataSrc = (byte*)pAnimationSrc + offset;
|
|
pDataDest = (byte*)pAnimationDest + offset;
|
|
|
|
// Write the vector (3 float16)
|
|
WriteBuffer<short>( &pDataDest, &pDataSrc, 3 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int offset = (byte*)pAnimation->pRotV() - (byte*)pAnimation;
|
|
pDataSrc = (byte*)pAnimationSrc + offset;
|
|
pDataDest = (byte*)pAnimationDest + offset;
|
|
|
|
mstudioanim_valueptr_t *rotvptr = (mstudioanim_valueptr_t*)pDataSrc;
|
|
WriteObjects<mstudioanim_valueptr_t>( &pDataDest, &pDataSrc );
|
|
|
|
int animValueCt = 0;
|
|
for ( int idx = 0; idx < 3; ++idx )
|
|
{
|
|
animValueCt += rotvptr->offset[idx] ? 1 : 0;
|
|
}
|
|
|
|
if ( pAnimation->flags & STUDIO_ANIM_ANIMPOS )
|
|
{
|
|
int offset = (byte*)pAnimation->pPosV() - (byte*)pAnimation;
|
|
pDataSrc = (byte*)pAnimationSrc + offset;
|
|
pDataDest = (byte*)pAnimationDest + offset;
|
|
|
|
mstudioanim_valueptr_t *posvptr = (mstudioanim_valueptr_t*)pDataSrc;
|
|
WriteObjects<mstudioanim_valueptr_t>( &pDataDest, &pDataSrc );
|
|
|
|
for ( int idx = 0; idx < 3; ++idx )
|
|
{
|
|
animValueCt += posvptr->offset[idx] ? 1 : 0;
|
|
}
|
|
}
|
|
|
|
// Write position and rotation animations
|
|
|
|
// Note: destanimvalue_t is a union that can be either two bytes or a short.
|
|
// This structure is used to compress animation data using RLE.
|
|
// The first object of a chunk acts as the header, and uses the two bytes to
|
|
// store how many objects follow, and how many frames are encoded by them.
|
|
// The objects that follow use the short to store a value.
|
|
// The total number of chunks has been determined by counting the number of valid (non-zero) offsets.
|
|
for ( int animValue = 0; animValue < animValueCt; ++animValue )
|
|
{
|
|
int encodedFrames = 0;
|
|
int totalFrames = SrcNative( &pAnimDesc->numframes );
|
|
int sectionFrames = SrcNative( &pAnimDesc->sectionframes );
|
|
if ( sectionFrames )
|
|
{
|
|
int iStartFrame = section * sectionFrames;
|
|
int iEndFrame = (section + 1) * sectionFrames;
|
|
|
|
iStartFrame = min( iStartFrame, totalFrames - 1 );
|
|
iEndFrame = min( iEndFrame, totalFrames - 1 );
|
|
|
|
totalFrames = iEndFrame - iStartFrame + 1;
|
|
}
|
|
|
|
while ( encodedFrames < totalFrames )
|
|
{
|
|
// Write the first animation value (struct of 2 bytes)
|
|
mstudioanimvalue_t *pDestAnimvalue = (mstudioanimvalue_t*)( g_bNativeSrc ? pDataSrc : pDataDest );
|
|
WriteBuffer<char>( &pDataDest, &pDataSrc, 2 );
|
|
|
|
// Write the remaining animation values from this group (shorts)
|
|
WriteBuffer<short>( &pDataDest, &pDataSrc, pDestAnimvalue->num.valid );
|
|
|
|
encodedFrames += pDestAnimvalue->num.total;
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODOKD: Could add a fixup here with some more work, hasn't been necessary yet
|
|
if ( pAnimation->nextoffset )
|
|
{
|
|
// Set pointers to the next animation
|
|
pAnimationSrc = (mstudioanim_t*)( (byte*)pAnimationSrc + SrcNative( &pAnimation->nextoffset ) );
|
|
pAnimationDest = (mstudioanim_t*)( (byte*)pAnimationDest + SrcNative( &pAnimation->nextoffset ) );
|
|
pAnimation = pAnimationSrc;
|
|
|
|
// Swap the next animation
|
|
WriteObjects( pAnimationDest, pAnimationSrc );
|
|
}
|
|
else
|
|
{
|
|
pAnimation = 0;
|
|
pDataSrc += sizeof( mstudioanim_t );
|
|
pDataDest += sizeof( mstudioanim_t );
|
|
}
|
|
}
|
|
|
|
ALIGN4( pDataSrc );
|
|
ALIGN4( pDataDest );
|
|
}
|
|
|
|
|
|
int ByteswapIKRules( studiohdr_t *&pHdrSrc, int numikrules, int numFrames, byte *&pDataSrc, byte *&pDataDest, int &fixedFileSize, const int fileSize )
|
|
{
|
|
DECLARE_OBJECT_POINTERS( pIKRule, pData, mstudioikrule_t )
|
|
|
|
ITERATE_BLOCK( pIKRule, numikrules )
|
|
{
|
|
WriteObjects<mstudioikrule_t>( pIKRuleDest, pIKRuleSrc );
|
|
|
|
/** IK ERROR KEYS **/
|
|
|
|
// Calculate the number of ikerrors by converting the ikerror start and end float values to
|
|
// frame numbers. (See the generation of these values in simplify.cpp: ProcessIKRules()).
|
|
float start = floorf( SrcNative( &pIKRule->start ) * (numFrames - 1) + 0.5f );
|
|
float end = floorf( SrcNative( &pIKRule->end ) * (numFrames - 1) + 0.5f );
|
|
int totalerror = (int)( end - start + 1 );
|
|
if ( end >= numFrames )
|
|
totalerror += 2;
|
|
|
|
// Uncompressed - only found in some older models (shipped hl2)
|
|
if ( pIKRule->ikerrorindex )
|
|
{
|
|
SET_INDEX_POINTERS_FIXUP( pData, pIKRule, ikerrorindex )
|
|
WriteObjects<mstudioikerror_t>( pDataDest, pDataSrc, totalerror );
|
|
}
|
|
|
|
// Compressed - all models since hl2
|
|
if ( pIKRule->compressedikerrorindex )
|
|
{
|
|
SET_INDEX_POINTERS_FIXUP( pData, pIKRule, compressedikerrorindex )
|
|
WriteObjects<mstudiocompressedikerror_t>( pDataDest, pDataSrc );
|
|
|
|
mstudiocompressedikerror_t *pCompressed = (mstudiocompressedikerror_t *)pDataSrc;
|
|
|
|
// Write the animvalues.
|
|
for ( int idx = 0; idx < 6; ++idx )
|
|
{
|
|
if ( pCompressed->offset[idx] )
|
|
{
|
|
byte *pAnimvalueSrc = pDataSrc + SrcNative( &pCompressed->offset[idx] );
|
|
byte *pAnimvalueDest = pDataDest + SrcNative( &pCompressed->offset[idx] );
|
|
|
|
int numerror = 0;
|
|
while ( numerror < totalerror )
|
|
{
|
|
// Write the first animation value (struct of 2 bytes)
|
|
mstudioanimvalue_t *pDestAnimvalue = (mstudioanimvalue_t*)( g_bNativeSrc ? pAnimvalueSrc : pAnimvalueDest );
|
|
WriteBuffer<char>( &pAnimvalueDest, &pAnimvalueSrc, 2 );
|
|
|
|
// Write the remaining animation values from this group (shorts)
|
|
WriteBuffer<short>( &pAnimvalueDest, &pAnimvalueSrc, pDestAnimvalue->num.valid );
|
|
|
|
numerror += pDestAnimvalue->num.total;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( pIKRule->szattachmentindex )
|
|
{
|
|
SET_INDEX_POINTERS( pData, pIKRule, szattachmentindex )
|
|
int size = strlen( (char*)pDataSrc ) + 1;
|
|
WriteBuffer<char>( pDataDest, pDataSrc, size );
|
|
}
|
|
}
|
|
}
|
|
return fixedFileSize;
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// Swap an .ani file
|
|
// Fixes alignment errors
|
|
//----------------------------------------------------------------------
|
|
int ByteswapANIFile( studiohdr_t* pHdr, void *pDestBase, const void *pSrcBase, const int fileSize )
|
|
{
|
|
// Note, pHdr came from a native .mdl -
|
|
// so the header, animdescs and animblocks are already in native format.
|
|
Assert( pHdr );
|
|
if ( !pHdr )
|
|
return false;
|
|
|
|
Q_memset( pDestBase, 0, fileSize );
|
|
|
|
// swap file header
|
|
{
|
|
byte *pHeaderSrc = (byte *)pSrcBase;
|
|
byte *pHeaderDest = (byte *)pDestBase;
|
|
DECLARE_OBJECT_POINTERS( pAniHeader, pHeader, studiohdr_t )
|
|
WriteObjects( pAniHeaderDest, pAniHeaderSrc );
|
|
}
|
|
|
|
// for fixup functions
|
|
int fixedFileSize = fileSize;
|
|
g_pfnFileProcessFunc = ProcessANIFields;
|
|
g_pDataSrcBase = pSrcBase;
|
|
g_pHdr = pHdr;
|
|
studiohdr_t *pHdrSrc = pHdr;
|
|
|
|
// The animdesc_t header is always contained in the mdl file, but its data may be in
|
|
// the mdl or the ani. When the data is contained in the mdl, the animdesc index fields
|
|
// represent offsets from the location of the animdesc header. When the data is in the ani,
|
|
// the index fields contain offsets from the start of the animblock in which the animdesc data is contained.
|
|
|
|
mstudioanimdesc_t *pAnimDesc = pHdr->pLocalAnimdesc( 0 );
|
|
for ( int i = 0; i < pHdr->numlocalanim; ++i, ++pAnimDesc )
|
|
{
|
|
// printf("anim %d : %d : %d\n", i, pAnimDesc->animblock, pAnimDesc->sectionframes );
|
|
if ( pAnimDesc->animblock == -1)
|
|
{
|
|
// out of date model format
|
|
continue;
|
|
}
|
|
|
|
if ( pAnimDesc->animblock == 0 && pAnimDesc->sectionframes == 0)
|
|
{
|
|
// already saved out
|
|
continue;
|
|
}
|
|
|
|
if ( pAnimDesc->sectionframes == 0 )
|
|
{
|
|
mstudioanimblock_t *pAnimBlock = pHdr->pAnimBlock( pAnimDesc->animblock );
|
|
|
|
// printf("block %d : start %d + %d\n", pAnimDesc->animblock, pAnimBlock->datastart, pAnimDesc->animindex );
|
|
// Base address of the animblock
|
|
byte *pBlockBaseSrc = (byte*)pSrcBase + pAnimBlock->datastart;
|
|
byte *pBlockBaseDest = (byte*)pDestBase + pAnimBlock->datastart;
|
|
|
|
// Base address of the animation in the animblock
|
|
byte *pDataSrc = pBlockBaseSrc + pAnimDesc->animindex;
|
|
byte *pDataDest = pBlockBaseDest + pAnimDesc->animindex;
|
|
|
|
ByteswapAnimData( pAnimDesc, 0, pDataSrc, pDataDest );
|
|
}
|
|
else
|
|
{
|
|
int numsections = pAnimDesc->numframes / pAnimDesc->sectionframes + 2;
|
|
|
|
for ( int i = 0; i < numsections; ++i )
|
|
{
|
|
int block = pAnimDesc->pSection( i )->animblock;
|
|
int index = pAnimDesc->pSection( i )->animindex;
|
|
|
|
if ( block != 0 )
|
|
{
|
|
// printf("%s %d %d\n", pAnimDesc->pszName(), block, index );
|
|
|
|
mstudioanimblock_t *pAnimBlock = pHdr->pAnimBlock( block );
|
|
|
|
// Base address of the animblock
|
|
byte *pBlockBaseSrc = (byte*)pSrcBase + pAnimBlock->datastart;
|
|
byte *pBlockBaseDest = (byte*)pDestBase + pAnimBlock->datastart;
|
|
FIXUP_OFFSETS( pBlockBase, pAnimBlock, datastart )
|
|
|
|
// Base address of the animation in the animblock
|
|
byte *pDataSrc = pBlockBaseSrc + index;
|
|
byte *pDataDest = pBlockBaseDest + index;
|
|
|
|
ByteswapAnimData( pAnimDesc, i, pDataSrc, pDataDest );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( pAnimDesc->animblock == 0)
|
|
{
|
|
// already saved out
|
|
continue;
|
|
}
|
|
|
|
mstudioanimblock_t *pAnimBlock = pHdr->pAnimBlock( pAnimDesc->animblock );
|
|
// Base address of the animblock
|
|
byte *pBlockBaseSrc = (byte*)pSrcBase + pAnimBlock->datastart;
|
|
byte *pBlockBaseDest = (byte*)pDestBase + pAnimBlock->datastart;
|
|
FIXUP_OFFSETS( pBlockBase, pAnimBlock, datastart )
|
|
|
|
// Base address of the animation in the animblock
|
|
byte *pDataSrc = pBlockBaseSrc + pAnimDesc->animindex;
|
|
byte *pDataDest = pBlockBaseDest + pAnimDesc->animindex;
|
|
FIXUP_OFFSETS( pData, pAnimDesc, animindex )
|
|
|
|
/** IK RULES **/
|
|
|
|
if ( pAnimDesc->animblockikruleindex )
|
|
{
|
|
pDataSrc = (byte*)pBlockBaseSrc + pAnimDesc->animblockikruleindex;
|
|
pDataDest = (byte*)pBlockBaseDest + pAnimDesc->animblockikruleindex;
|
|
FIXUP_OFFSETS( pData, pAnimDesc, animblockikruleindex )
|
|
|
|
int numikrules = SrcNative( &pAnimDesc->numikrules );
|
|
ByteswapIKRules( pHdrSrc, pAnimDesc->numikrules, pAnimDesc->numframes, pDataSrc, pDataDest, fixedFileSize, fileSize );
|
|
}
|
|
|
|
/** LOCAL HIERARCHY **/
|
|
|
|
if ( pAnimDesc->localhierarchyindex )
|
|
{
|
|
pDataSrc = (byte*)pBlockBaseSrc + pAnimDesc->localhierarchyindex;
|
|
pDataDest = (byte*)pBlockBaseDest + pAnimDesc->localhierarchyindex;
|
|
DECLARE_OBJECT_POINTERS( pLocalHierarchy, pData, mstudiolocalhierarchy_t )
|
|
|
|
// HACK: Since animdescs are already native, pre-swap pAnimDesc->numlocalhierarchy
|
|
// here so the automatic swap inside ITERATE_BLOCK will restore it
|
|
int numlocalhierarchy = SrcNative( &pAnimDesc->numlocalhierarchy );
|
|
ITERATE_BLOCK( pLocalHierarchy, numlocalhierarchy )
|
|
{
|
|
WriteObjects<mstudiolocalhierarchy_t>( pLocalHierarchyDest, pLocalHierarchySrc, pAnimDesc->numlocalhierarchy );
|
|
|
|
/** COMPRESSED IK ERRORS **/
|
|
|
|
if ( pLocalHierarchy->localanimindex != 0 )
|
|
{
|
|
// Calculate the number of ikerrors by converting the ikerror start and end float values to
|
|
// frame numbers. (See the generation of these values in simplify.cpp: ProcessIKRules()).
|
|
int numFrames = pAnimDesc->numframes;
|
|
float start = floorf( SrcNative( &pLocalHierarchy->start ) * (numFrames - 1) + 0.5f );
|
|
float end = floorf( SrcNative( &pLocalHierarchy->end ) * (numFrames - 1) + 0.5f );
|
|
int totalerror = (int)( end - start + 1 );
|
|
if ( end >= numFrames )
|
|
totalerror += 2;
|
|
|
|
SET_INDEX_POINTERS( pData, pLocalHierarchy, localanimindex )
|
|
WriteObjects<mstudiocompressedikerror_t>( pDataDest, pDataSrc );
|
|
|
|
mstudiocompressedikerror_t *pCompressed = (mstudiocompressedikerror_t *)pDataSrc;
|
|
|
|
// Write the animvalues.
|
|
for ( int idx = 0; idx < 6; ++idx )
|
|
{
|
|
if ( pCompressed->offset[idx] )
|
|
{
|
|
byte *pAnimvalueSrc = pDataSrc + SrcNative( &pCompressed->offset[idx] );
|
|
byte *pAnimvalueDest = pDataDest + SrcNative( &pCompressed->offset[idx] );
|
|
|
|
int numerror = 0;
|
|
while ( numerror < totalerror )
|
|
{
|
|
// Write the first animation value (struct of 2 bytes)
|
|
mstudioanimvalue_t *pDestAnimvalue = (mstudioanimvalue_t*)( g_bNativeSrc ? pAnimvalueSrc : pAnimvalueDest );
|
|
WriteBuffer<char>( &pAnimvalueDest, &pAnimvalueSrc, 2 );
|
|
|
|
// Write the remaining animation values from this group (shorts)
|
|
WriteBuffer<short>( &pAnimvalueDest, &pAnimvalueSrc, pDestAnimvalue->num.valid );
|
|
|
|
numerror += pDestAnimvalue->num.total;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} // Local Hierarchy block
|
|
}
|
|
}
|
|
|
|
// printf("returning %d\n", fixedFileSize );
|
|
|
|
return fixedFileSize;
|
|
}
|
|
|
|
int ByteswapANI( studiohdr_t* pHdr, void *pDestBase, const void *pSrcBase, const int fileSize )
|
|
{
|
|
// Make a working copy of the source to allow for alignment fixups
|
|
void *pNewSrcBase = malloc( fileSize + BYTESWAP_ALIGNMENT_PADDING );
|
|
Q_memcpy( pNewSrcBase, pSrcBase, fileSize );
|
|
|
|
int fixedFileSize = ByteswapANIFile( pHdr, pDestBase, pNewSrcBase, fileSize );
|
|
if ( fixedFileSize != fileSize )
|
|
{
|
|
int finalSize = ByteswapANIFile( pHdr, pDestBase, pNewSrcBase, fixedFileSize );
|
|
if ( finalSize != fixedFileSize )
|
|
{
|
|
if ( g_bVerbose )
|
|
Warning( "Alignment fixups failed on ANI swap!\n" );
|
|
fixedFileSize = 0;
|
|
}
|
|
}
|
|
|
|
free( pNewSrcBase );
|
|
|
|
// the compression needs to happen on the final or "fixed" pass
|
|
if ( g_pCompressFunc && pHdr->numanimblocks >= 2 && fixedFileSize )
|
|
{
|
|
// assemble a new anim of compressed anim blocks
|
|
// start with original size, with room for alignment padding
|
|
fixedFileSize += (pHdr->numanimblocks + 1) * 2048;
|
|
byte *pNewDestBase = (byte *)malloc( fixedFileSize );
|
|
Q_memset( pNewDestBase, 0, fixedFileSize );
|
|
byte *pNewDest = pNewDestBase;
|
|
|
|
// get the header payload as is
|
|
// assuming the header is up to the first anim block
|
|
mstudioanimblock_t *pAnimBlock = pHdr->pAnimBlock( 1 );
|
|
V_memcpy( pNewDest, pDestBase, pAnimBlock->datastart );
|
|
pNewDest += pAnimBlock->datastart;
|
|
|
|
int padding = AlignValue( (unsigned int)pNewDest - (unsigned int)pNewDestBase, 2048 );
|
|
padding -= (unsigned int)pNewDest - (unsigned int)pNewDestBase;
|
|
pNewDest += padding;
|
|
|
|
// iterate and compress anim blocks
|
|
for ( int i = 1; i < pHdr->numanimblocks; ++i )
|
|
{
|
|
pAnimBlock = pHdr->pAnimBlock( i );
|
|
|
|
void *pInput = (byte *)pDestBase + pAnimBlock->datastart;
|
|
int inputSize = pAnimBlock->dataend - pAnimBlock->datastart;
|
|
|
|
pAnimBlock->datastart = (unsigned int)pNewDest - (unsigned int)pNewDestBase;
|
|
|
|
void *pOutput;
|
|
int outputSize;
|
|
if ( g_pCompressFunc( pInput, inputSize, &pOutput, &outputSize ) )
|
|
{
|
|
V_memcpy( pNewDest, pOutput, outputSize );
|
|
pNewDest += outputSize;
|
|
free( pOutput );
|
|
}
|
|
else
|
|
{
|
|
// as is
|
|
V_memcpy( pNewDest, pInput, inputSize );
|
|
pNewDest += inputSize;
|
|
}
|
|
|
|
padding = AlignValue( (unsigned int)pNewDest - (unsigned int)pNewDestBase, 2048 );
|
|
padding -= (unsigned int)pNewDest - (unsigned int)pNewDestBase;
|
|
pNewDest += padding;
|
|
|
|
pAnimBlock->dataend = (unsigned int)pNewDest - (unsigned int)pNewDestBase;
|
|
}
|
|
|
|
fixedFileSize = pNewDest - pNewDestBase;
|
|
V_memcpy( pDestBase, pNewDestBase, fixedFileSize );
|
|
free( pNewDestBase );
|
|
}
|
|
|
|
return fixedFileSize;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Write a .mdl file in big-endian format
|
|
//----------------------------------------------------------------------
|
|
int ByteswapMDLFile( void *pDestBase, void *pSrcBase, const int fileSize )
|
|
{
|
|
// Needed by fixup functions
|
|
g_pDataSrcBase = pSrcBase;
|
|
g_pfnFileProcessFunc = ProcessMDLFields;
|
|
int fixedFileSize = fileSize;
|
|
|
|
Q_memset( pDestBase, 0, fileSize );
|
|
|
|
byte *pDataSrc = (byte*)pSrcBase;
|
|
byte *pDataDest = (byte*)pDestBase;
|
|
|
|
/** FILE HEADER **/
|
|
|
|
DECLARE_OBJECT_POINTERS( pHdr, pData, studiohdr_t )
|
|
WriteObjects( pHdrDest, pHdrSrc );
|
|
|
|
/** BONES **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pHdr, boneindex )
|
|
DECLARE_OBJECT_POINTERS( pStudioBone, pData, mstudiobone_t )
|
|
ITERATE_BLOCK( pStudioBone, pHdr->numbones )
|
|
{
|
|
WriteObjects( pStudioBoneDest, pStudioBoneSrc );
|
|
|
|
if ( pStudioBone->procindex )
|
|
{
|
|
SET_INDEX_POINTERS_FIXUP( pData, pStudioBone, procindex )
|
|
|
|
unsigned int index = SrcNative( &pStudioBone->proctype );
|
|
switch( index )
|
|
{
|
|
case STUDIO_PROC_AXISINTERP:
|
|
{
|
|
/** AXIS-INTERP BONES **/
|
|
DECLARE_OBJECT_POINTERS( pAxisInterpBone, pData, mstudioaxisinterpbone_t )
|
|
WriteObjects( pAxisInterpBoneDest, pAxisInterpBoneSrc );
|
|
break;
|
|
}
|
|
case STUDIO_PROC_QUATINTERP:
|
|
{
|
|
/** QUAT-INTERP BONES **/
|
|
DECLARE_OBJECT_POINTERS( pQuatInterpBone, pData, mstudioquatinterpbone_t )
|
|
WriteObjects( pQuatInterpBoneDest, pQuatInterpBoneSrc );
|
|
|
|
/** QUAT-INTERP TRIGGERS **/
|
|
SET_INDEX_POINTERS_FIXUP( pData, pQuatInterpBone, triggerindex )
|
|
WriteObjects<mstudioquatinterpinfo_t>( pDataDest, pDataSrc, SrcNative( &pQuatInterpBone->numtriggers ) );
|
|
break;
|
|
}
|
|
case STUDIO_PROC_JIGGLE:
|
|
{
|
|
/** JIGGLE BONES **/
|
|
DECLARE_OBJECT_POINTERS( pJiggleBone, pData, mstudiojigglebone_t )
|
|
WriteObjects( pJiggleBoneDest, pJiggleBoneSrc );
|
|
break;
|
|
}
|
|
case STUDIO_PROC_AIMATBONE:
|
|
case STUDIO_PROC_AIMATATTACH:
|
|
{
|
|
/** AIM AT BONES **/
|
|
DECLARE_OBJECT_POINTERS( pAimAtBone, pData, mstudioaimatbone_t )
|
|
WriteObjects( pAimAtBoneDest, pAimAtBoneSrc );
|
|
break;
|
|
}
|
|
default:
|
|
Assert( 0 );
|
|
Warning( "Unknown bone type %d found!\n", index );
|
|
}
|
|
}
|
|
}
|
|
|
|
/** BONE CONTROLLERS **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pHdr, bonecontrollerindex )
|
|
WriteObjects<mstudiobonecontroller_t>( pDataDest, pDataSrc, SrcNative( &pHdr->numbonecontrollers ) );
|
|
|
|
/** ATTACHMENTS **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pHdr, localattachmentindex )
|
|
WriteObjects<mstudioattachment_t>( pDataDest, pDataSrc, SrcNative( &pHdr->numlocalattachments ) );
|
|
|
|
/** HITBOX SETS **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pHdr, hitboxsetindex )
|
|
DECLARE_OBJECT_POINTERS( pHitboxSet, pData, mstudiohitboxset_t )
|
|
ITERATE_BLOCK( pHitboxSet, pHdr->numhitboxsets )
|
|
{
|
|
WriteObjects( pHitboxSetDest, pHitboxSetSrc );
|
|
|
|
/** HITBOXES **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pHitboxSet, hitboxindex )
|
|
WriteObjects<mstudiobbox_t>( pDataDest, pDataSrc, SrcNative( &pHitboxSet->numhitboxes ) );
|
|
}
|
|
|
|
/** BONE TABLE **/
|
|
|
|
SET_INDEX_POINTERS( pData, pHdr, bonetablebynameindex )
|
|
WriteBuffer<char>( pDataDest, pDataSrc, SrcNative( &pHdr->numbones ) );
|
|
|
|
/** ANIMATION DESCRIPTIONS **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pHdr, localanimindex )
|
|
DECLARE_OBJECT_POINTERS( pAnimDesc, pData, mstudioanimdesc_t )
|
|
ITERATE_BLOCK( pAnimDesc, pHdr->numlocalanim )
|
|
{
|
|
WriteObjects( pAnimDescDest, pAnimDescSrc );
|
|
|
|
if ( pAnimDesc->animblock == -1 )
|
|
{
|
|
// out of date model format
|
|
continue;
|
|
}
|
|
|
|
// section data can point to both internal and external blocks
|
|
int numsections = 0;
|
|
if ( pAnimDesc->sectionframes != 0 )
|
|
{
|
|
numsections = pAnimDesc->numframes / pAnimDesc->sectionframes + 2;
|
|
|
|
SET_INDEX_POINTERS( pData, pAnimDesc, sectionindex )
|
|
DECLARE_OBJECT_POINTERS( pSection, pData, mstudioanimsections_t )
|
|
|
|
WriteObjects( pSectionDest, pSectionSrc, numsections );
|
|
}
|
|
|
|
if ( pAnimDesc->animblock == 0 )
|
|
{
|
|
if ( numsections == 0 )
|
|
{
|
|
SET_INDEX_POINTERS( pData, pAnimDesc, animindex )
|
|
ByteswapAnimData( pAnimDesc, 0, pDataSrc, pDataDest );
|
|
}
|
|
else
|
|
{
|
|
for ( int i = 0; i < numsections; ++i )
|
|
{
|
|
if ( pAnimDesc->pSection( i )->animblock == 0 )
|
|
{
|
|
int index = pAnimDesc->pSection( i )->animindex;
|
|
|
|
// Base address of the animation in the animblock
|
|
byte *pDataSrc = (byte *)pAnimDescSrc + index;
|
|
byte *pDataDest = (byte *)pAnimDescDest + index;
|
|
|
|
ByteswapAnimData( pAnimDesc, i, pDataSrc, pDataDest );
|
|
}
|
|
}
|
|
}
|
|
|
|
/** IK RULES **/
|
|
|
|
if ( pAnimDesc->ikruleindex )
|
|
{
|
|
SET_INDEX_POINTERS_FIXUP( pData, pAnimDesc, ikruleindex )
|
|
DECLARE_OBJECT_POINTERS( pIKRule, pData, mstudioikrule_t )
|
|
|
|
int numframes = SrcNative( &pAnimDesc->numframes );
|
|
ByteswapIKRules( pHdrSrc, pAnimDesc->numikrules, numframes, pDataSrc, pDataDest, fixedFileSize, fileSize );
|
|
}
|
|
|
|
/** LOCAL HIERARCHY **/
|
|
|
|
if ( pAnimDesc->localhierarchyindex )
|
|
{
|
|
SET_INDEX_POINTERS( pData, pAnimDesc, localhierarchyindex )
|
|
DECLARE_OBJECT_POINTERS( pLocalHierarchy, pData, mstudiolocalhierarchy_t )
|
|
ITERATE_BLOCK( pLocalHierarchy, pAnimDesc->numlocalhierarchy )
|
|
{
|
|
WriteObjects<mstudiolocalhierarchy_t>( pLocalHierarchyDest, pLocalHierarchySrc, SrcNative( &pAnimDesc->numlocalhierarchy ) );
|
|
|
|
/** COMPRESSED IK ERRORS **/
|
|
|
|
if ( pLocalHierarchy->localanimindex != 0 )
|
|
{
|
|
// Calculate the number of ikerrors by converting the ikerror start and end float values to
|
|
// frame numbers. (See the generation of these values in simplify.cpp: ProcessIKRules()).
|
|
int numFrames = SrcNative( &pAnimDesc->numframes );
|
|
float start = floorf( SrcNative( &pLocalHierarchy->start ) * (numFrames - 1) + 0.5f );
|
|
float end = floorf( SrcNative( &pLocalHierarchy->end ) * (numFrames - 1) + 0.5f );
|
|
int totalerror = (int)( end - start + 1 );
|
|
if ( end >= numFrames )
|
|
totalerror += 2;
|
|
|
|
SET_INDEX_POINTERS( pData, pLocalHierarchy, localanimindex )
|
|
WriteObjects<mstudiocompressedikerror_t>( pDataDest, pDataSrc );
|
|
|
|
mstudiocompressedikerror_t *pCompressed = (mstudiocompressedikerror_t *)pDataSrc;
|
|
|
|
// Write the animvalues.
|
|
for ( int idx = 0; idx < 6; ++idx )
|
|
{
|
|
if ( pCompressed->offset[idx] )
|
|
{
|
|
byte *pAnimvalueSrc = pDataSrc + SrcNative( &pCompressed->offset[idx] );
|
|
byte *pAnimvalueDest = pDataDest + SrcNative( &pCompressed->offset[idx] );
|
|
|
|
int numerror = 0;
|
|
while ( numerror < totalerror )
|
|
{
|
|
// Write the first animation value (struct of 2 bytes)
|
|
mstudioanimvalue_t *pDestAnimvalue = (mstudioanimvalue_t*)( g_bNativeSrc ? pAnimvalueSrc : pAnimvalueDest );
|
|
WriteBuffer<char>( &pAnimvalueDest, &pAnimvalueSrc, 2 );
|
|
|
|
// Write the remaining animation values from this group (shorts)
|
|
WriteBuffer<short>( &pAnimvalueDest, &pAnimvalueSrc, pDestAnimvalue->num.valid );
|
|
|
|
numerror += pDestAnimvalue->num.total;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} // Local Hierarchy block
|
|
}
|
|
} // Animdesc block
|
|
|
|
/** MOVEMENTS **/
|
|
|
|
// Separate loop required by format of mstudioanimdesc_t data
|
|
SET_INDEX_POINTERS( pData, pHdr, localanimindex )
|
|
SET_OBJECT_POINTERS( pAnimDesc, pData, mstudioanimdesc_t )
|
|
ITERATE_BLOCK( pAnimDesc, pHdr->numlocalanim )
|
|
{
|
|
if ( pAnimDesc->nummovements )
|
|
{
|
|
SET_INDEX_POINTERS_FIXUP( pData, pAnimDesc, movementindex )
|
|
WriteObjects<mstudiomovement_t>( pDataDest, pDataSrc, SrcNative( &pAnimDesc->nummovements ) );
|
|
}
|
|
}
|
|
|
|
/** IK RULES (2nd pass) **/
|
|
|
|
// This is required to support older models that had these lumps in a different
|
|
// order - the model version didn't change, so there's no reliable way to detect it.
|
|
SET_INDEX_POINTERS( pData, pHdr, localanimindex )
|
|
SET_OBJECT_POINTERS( pAnimDesc, pData, mstudioanimdesc_t )
|
|
ITERATE_BLOCK( pAnimDesc, pHdr->numlocalanim )
|
|
{
|
|
if ( pAnimDesc->ikruleindex )
|
|
{
|
|
// Only need to write the data again if a fixup happens
|
|
byte *pTest = (byte*)pAnimDesc + SrcNative( &pAnimDesc->ikruleindex );
|
|
SET_INDEX_POINTERS_FIXUP( pData, pAnimDesc, ikruleindex )
|
|
if ( pTest == pDataSrc )
|
|
continue;
|
|
|
|
DECLARE_OBJECT_POINTERS( pIKRule, pData, mstudioikrule_t )
|
|
ITERATE_BLOCK( pIKRule, pAnimDesc->numikrules )
|
|
{
|
|
WriteObjects<mstudioikrule_t>( pIKRuleDest, pIKRuleSrc );
|
|
|
|
/** IK ERROR KEYS **/
|
|
|
|
// Calculate the number of ikerrors by converting the ikerror start and end float values to
|
|
// frame numbers. (See the generation of these values in simplify.cpp: ProcessIKRules()).
|
|
int numFrames = SrcNative( &pAnimDesc->numframes );
|
|
float start = floorf( SrcNative( &pIKRule->start ) * (numFrames - 1) + 0.5f );
|
|
float end = floorf( SrcNative( &pIKRule->end ) * (numFrames - 1) + 0.5f );
|
|
int totalerror = (int)( end - start + 1 );
|
|
if ( end >= numFrames )
|
|
totalerror += 2;
|
|
|
|
// Uncompressed - only found in some older models (shipped hl2)
|
|
if ( pIKRule->ikerrorindex )
|
|
{
|
|
SET_INDEX_POINTERS_FIXUP( pData, pIKRule, ikerrorindex )
|
|
WriteObjects<mstudioikerror_t>( pDataDest, pDataSrc, totalerror );
|
|
}
|
|
|
|
// Compressed - all models since hl2
|
|
if ( pIKRule->compressedikerrorindex )
|
|
{
|
|
SET_INDEX_POINTERS_FIXUP( pData, pIKRule, compressedikerrorindex )
|
|
WriteObjects<mstudiocompressedikerror_t>( pDataDest, pDataSrc );
|
|
|
|
mstudiocompressedikerror_t *pCompressed = (mstudiocompressedikerror_t *)pDataSrc;
|
|
|
|
// Write the animvalues.
|
|
for ( int idx = 0; idx < 6; ++idx )
|
|
{
|
|
if ( pCompressed->offset[idx] )
|
|
{
|
|
byte *pAnimvalueSrc = pDataSrc + SrcNative( &pCompressed->offset[idx] );
|
|
byte *pAnimvalueDest = pDataDest + SrcNative( &pCompressed->offset[idx] );
|
|
|
|
int numerror = 0;
|
|
while ( numerror < totalerror )
|
|
{
|
|
// Write the first animation value (struct of 2 bytes)
|
|
mstudioanimvalue_t *pDestAnimvalue = (mstudioanimvalue_t*)( g_bNativeSrc ? pAnimvalueSrc : pAnimvalueDest );
|
|
WriteBuffer<char>( &pAnimvalueDest, &pAnimvalueSrc, 2 );
|
|
|
|
// Write the remaining animation values from this group (shorts)
|
|
WriteBuffer<short>( &pAnimvalueDest, &pAnimvalueSrc, pDestAnimvalue->num.valid );
|
|
|
|
numerror += pDestAnimvalue->num.total;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( pIKRule->szattachmentindex )
|
|
{
|
|
SET_INDEX_POINTERS( pData, pIKRule, szattachmentindex )
|
|
int size = strlen( (char*)pDataSrc ) + 1;
|
|
WriteBuffer<char>( pDataDest, pDataSrc, size );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Local hierarchy keys don't exist in older models
|
|
}
|
|
|
|
/** ZERO FRAMES **/
|
|
|
|
SET_INDEX_POINTERS( pData, pHdr, localanimindex )
|
|
SET_OBJECT_POINTERS( pAnimDesc, pData, mstudioanimdesc_t )
|
|
ITERATE_BLOCK( pAnimDesc, pHdr->numlocalanim )
|
|
{
|
|
if ( pAnimDesc->pZeroFrameData( ) != NULL )
|
|
{
|
|
int offset = pAnimDesc->pZeroFrameData( ) - (byte *)pAnimDesc;
|
|
|
|
// Base address of the animation in the animblock
|
|
byte *pZeroFrameSrc = (byte *)pAnimDescSrc + offset;
|
|
byte *pZeroFrameDest = (byte *)pAnimDescDest + offset;
|
|
|
|
SET_INDEX_POINTERS( pData, pHdr, boneindex )
|
|
SET_OBJECT_POINTERS( pStudioBone, pData, mstudiobone_t )
|
|
ITERATE_BLOCK( pStudioBone, pHdr->numbones )
|
|
{
|
|
if ( pStudioBone->flags & BONE_HAS_SAVEFRAME_POS )
|
|
{
|
|
for ( int j = 0; j < pAnimDesc->zeroframecount; j++)
|
|
{
|
|
WriteBuffer<short>( &pZeroFrameDest, &pZeroFrameSrc, 3 );
|
|
}
|
|
}
|
|
if ( pStudioBone->flags & BONE_HAS_SAVEFRAME_ROT )
|
|
{
|
|
for ( int j = 0; j < pAnimDesc->zeroframecount; j++)
|
|
{
|
|
WriteBuffer<int64>( &pZeroFrameDest, &pZeroFrameSrc, 1 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** SEQUENCE INFO **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pHdr, localseqindex )
|
|
DECLARE_OBJECT_POINTERS( pSequence, pData, mstudioseqdesc_t )
|
|
ITERATE_BLOCK( pSequence, pHdr->numlocalseq )
|
|
{
|
|
WriteObjects( pSequenceDest, pSequenceSrc );
|
|
|
|
/** POSE KEYS **/
|
|
|
|
if ( pSequence->posekeyindex )
|
|
{
|
|
SET_INDEX_POINTERS_FIXUP( pData, pSequence, posekeyindex )
|
|
WriteBuffer<float>( pDataDest, pDataSrc, SrcNative( &pSequence->groupsize[0] ) + SrcNative( &pSequence->groupsize[1] ) );
|
|
}
|
|
|
|
/** STUDIO EVENTS **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pSequence, eventindex )
|
|
WriteObjects<mstudioevent_t>( pDataDest, pDataSrc, SrcNative( &pSequence->numevents ) );
|
|
|
|
/** AUTOLAYERS **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pSequence, autolayerindex )
|
|
WriteObjects<mstudioautolayer_t>( pDataDest, pDataSrc, SrcNative( &pSequence->numautolayers ) );
|
|
|
|
/** BONE WEIGHTS **/
|
|
|
|
// Data may be shared across sequences
|
|
DECLARE_INDEX_POINTERS_FIXUP( pWeight, pSequence, weightlistindex )
|
|
if ( pWeightSrc >= pDataSrc )
|
|
{
|
|
int numBoneWeights = ( SrcNative( &pSequence->iklockindex ) - SrcNative( &pSequence->weightlistindex ) ) / sizeof(float);
|
|
WriteBuffer<float>( pWeightDest, pWeightSrc, numBoneWeights );
|
|
}
|
|
|
|
/** IK LOCKS **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pSequence, iklockindex )
|
|
WriteObjects<mstudioiklock_t>( pDataDest, pDataSrc, SrcNative( &pSequence->numiklocks ) );
|
|
|
|
/** ANIMATION INDICES **/
|
|
|
|
if ( pSequence->animindexindex )
|
|
{
|
|
SET_INDEX_POINTERS( pData, pSequence, animindexindex )
|
|
WriteBuffer<short>( pDataDest, pDataSrc, SrcNative( &pSequence->groupsize[0] ) * SrcNative( &pSequence->groupsize[1] ) );
|
|
}
|
|
|
|
/** KEYVALUES **/
|
|
|
|
SET_INDEX_POINTERS( pData, pSequence, keyvalueindex )
|
|
WriteBuffer<char>( pDataDest, pDataSrc, SrcNative( &pSequence->keyvaluesize ) );
|
|
}
|
|
|
|
/** TRANSITION GRAPH **/
|
|
|
|
int numLocalNodes = SrcNative( &pHdr->numlocalnodes );
|
|
SET_INDEX_POINTERS_FIXUP( pData, pHdr, localnodenameindex )
|
|
WriteBuffer<int>( pDataDest, pDataSrc, numLocalNodes );
|
|
|
|
/** LOCAL NODES **/
|
|
|
|
SET_INDEX_POINTERS( pData, pHdr, localnodeindex )
|
|
WriteBuffer<char>( pDataDest, pDataSrc, numLocalNodes * numLocalNodes );
|
|
|
|
/** BODYPART INFO **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pHdr, bodypartindex )
|
|
DECLARE_OBJECT_POINTERS( pBodypart, pData, mstudiobodyparts_t )
|
|
ITERATE_BLOCK( pBodypart, pHdr->numbodyparts )
|
|
{
|
|
WriteObjects( pBodypartDest, pBodypartSrc );
|
|
|
|
/** MODEL INFO **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pBodypart, modelindex )
|
|
DECLARE_OBJECT_POINTERS( pModel, pData, mstudiomodel_t )
|
|
ITERATE_BLOCK( pModel, pBodypart->nummodels )
|
|
{
|
|
WriteObjects( pModelDest, pModelSrc );
|
|
|
|
/** MESHES **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pModel, meshindex )
|
|
DECLARE_OBJECT_POINTERS( pMesh, pData, mstudiomesh_t )
|
|
ITERATE_BLOCK( pMesh, pModel->nummeshes )
|
|
{
|
|
WriteObjects( pMeshDest, pMeshSrc );
|
|
|
|
if ( !pMesh->numflexes )
|
|
continue;
|
|
|
|
/** FLEXES **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pMesh, flexindex )
|
|
DECLARE_OBJECT_POINTERS( pFlex, pData, mstudioflex_t )
|
|
ITERATE_BLOCK( pFlex, pMesh->numflexes )
|
|
{
|
|
WriteObjects( pFlexDest, pFlexSrc );
|
|
|
|
/** VERT ANIMS **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pFlex, vertindex )
|
|
WriteObjects<mstudiovertanim_t>( pDataDest, pDataSrc, SrcNative( &pFlex->numverts ) );
|
|
}
|
|
}
|
|
|
|
/** EYEBALLS **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pModel, eyeballindex )
|
|
WriteObjects<mstudioeyeball_t>( pDataDest, pDataSrc, SrcNative( &pModel->numeyeballs ) );
|
|
}
|
|
}
|
|
|
|
/** GLOBAL FLEX NAMES **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pHdr, flexdescindex )
|
|
WriteObjects<mstudioflexdesc_t>( pDataDest, pDataSrc, SrcNative( &pHdr->numflexdesc ) );
|
|
|
|
/** GLOBAL FLEX CONTROLLERS **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pHdr, flexcontrollerindex )
|
|
WriteObjects<mstudioflexcontroller_t>( pDataDest, pDataSrc, SrcNative( &pHdr->numflexcontrollers ) );
|
|
|
|
/** GLOBAL FLEX CONTROLLER REMAPS **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pHdr, flexcontrolleruiindex )
|
|
WriteObjects<mstudioflexcontrollerui_t>( pDataDest, pDataSrc, SrcNative( &pHdr->numflexcontrollerui ) );
|
|
|
|
// TODOKD: The remap indices after the flex controller remap headers need to be swapped as well?
|
|
|
|
/** FLEX RULES **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pHdr, flexruleindex )
|
|
DECLARE_OBJECT_POINTERS( pFlexRule, pData, mstudioflexrule_t )
|
|
ITERATE_BLOCK( pFlexRule, pHdr->numflexrules )
|
|
{
|
|
WriteObjects( pFlexRuleDest, pFlexRuleSrc );
|
|
|
|
/** FLEX OPS **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pFlexRule, opindex )
|
|
WriteObjects<mstudioflexop_t>( pDataDest, pDataSrc, SrcNative( &pFlexRule->numops ) );
|
|
}
|
|
|
|
/** IK CHAINS **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pHdr, ikchainindex )
|
|
DECLARE_OBJECT_POINTERS( pIKChain, pData, mstudioikchain_t )
|
|
ITERATE_BLOCK( pIKChain, pHdr->numikchains )
|
|
{
|
|
WriteObjects( pIKChainDest, pIKChainSrc );
|
|
|
|
/** IK LINKS **/
|
|
|
|
SET_INDEX_POINTERS( pData, pIKChain, linkindex )
|
|
WriteObjects<mstudioiklink_t>( pDataDest, pDataSrc, SrcNative( &pIKChain->numlinks ) );
|
|
}
|
|
|
|
/** IK AUTOPLAY LOCKS **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pHdr, localikautoplaylockindex )
|
|
WriteObjects<mstudioiklock_t>( pDataDest, pDataSrc, SrcNative( &pHdr->numlocalikautoplaylocks ) );
|
|
|
|
/** MOUTH INFO **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pHdr, mouthindex )
|
|
WriteObjects<mstudiomouth_t>( pDataDest, pDataSrc, SrcNative( &pHdr->nummouths ) );
|
|
|
|
/** POSE PARAMATERS **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pHdr, localposeparamindex )
|
|
WriteObjects<mstudioposeparamdesc_t>( pDataDest, pDataSrc, SrcNative( &pHdr->numlocalposeparameters ) );
|
|
|
|
/** MODEL GROUPS **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pHdr, includemodelindex )
|
|
WriteObjects<mstudiomodelgroup_t>( pDataDest, pDataSrc, SrcNative( &pHdr->numincludemodels ) );
|
|
|
|
/** ANIMBLOCK GROUP INFO **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pHdr, animblockindex )
|
|
WriteObjects<mstudioanimblock_t>( pDataDest, pDataSrc, SrcNative( &pHdr->numanimblocks ) );
|
|
|
|
/** TEXTURE INFO **/
|
|
|
|
// While swapping, kill off unwanted textures by name
|
|
SET_INDEX_POINTERS_FIXUP( pData, pHdr, textureindex )
|
|
DECLARE_OBJECT_POINTERS( pTexture, pData, mstudiotexture_t )
|
|
int textureCt = SrcNative( &pHdr->numtextures );
|
|
int nameOffset = 0;
|
|
for ( int i = 0; i < SrcNative( &pHdr->numtextures ); ++i, ++pTexture, ++pTextureSrc )
|
|
{
|
|
WriteObjects<mstudiotexture_t>( pTextureDest, pTextureSrc );
|
|
|
|
int destnameindex = SrcNative( &pTexture->sznameindex ) + nameOffset;
|
|
pTextureDest->sznameindex = DestNative( &destnameindex );
|
|
char *pName = (char*)pTexture + SrcNative( &pTexture->sznameindex );
|
|
#if 0 // Undone: Killing textures here can cause crashes at runtime.
|
|
// Don't need pupil textures
|
|
if ( Q_stristr( pName, "pupil_" ) || !Q_stricmp( pName, "pupil" ) )
|
|
{
|
|
--textureCt;
|
|
nameOffset += sizeof(mstudiotexture_t);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
++pTextureDest;
|
|
}
|
|
}
|
|
pHdrDest->numtextures = DestNative( &textureCt );
|
|
|
|
/** TEXTURE INDICES **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pHdr, cdtextureindex )
|
|
WriteBuffer<int>( &pDataDest, &pDataSrc, SrcNative( &pHdr->numcdtextures ) );
|
|
|
|
/** TEXTURE DICTIONARY **/
|
|
|
|
SET_INDEX_POINTERS( pData, pHdr, skinindex )
|
|
WriteBuffer<short>( &pDataDest, &pDataSrc, SrcNative( &pHdr->numskinfamilies ) * SrcNative( &pHdr->numskinref ) );
|
|
|
|
/** KEYVALUES **/
|
|
|
|
SET_INDEX_POINTERS( pData, pHdr, keyvalueindex )
|
|
WriteBuffer<char>( &pDataDest, &pDataSrc, SrcNative( &pHdr->keyvaluesize ) );
|
|
|
|
/** STUDIOHDR2 **/
|
|
|
|
if ( pHdr->studiohdr2index )
|
|
{
|
|
DECLARE_INDEX_POINTERS_FIXUP( pLocalData, pHdr, studiohdr2index )
|
|
DECLARE_OBJECT_POINTERS( pStudioHdr2, pLocalData, studiohdr2_t )
|
|
|
|
// HACK: Pre-swap the constant "1" here so the automatic swap inside ITERATE_BLOCK will restore it
|
|
int studiohdr2ct = 1;
|
|
studiohdr2ct = SrcNative( &studiohdr2ct );
|
|
ITERATE_BLOCK( pStudioHdr2, studiohdr2ct )
|
|
{
|
|
WriteObjects( pStudioHdr2Dest, pStudioHdr2Src );
|
|
|
|
/** SRC BONE TRANSFORMS **/
|
|
|
|
if ( pStudioHdr2->numsrcbonetransform )
|
|
{
|
|
// Note, srcbonetransformindex is an offset from the start of the file, not the start of the studiohdr2
|
|
// as is the convention. That's why the macros can't be used here.
|
|
pDataSrc = (byte*)pHdrSrc + SrcNative( &pStudioHdr2->srcbonetransformindex );
|
|
pDataDest = (byte*)pHdrDest + SrcNative( &pStudioHdr2->srcbonetransformindex );
|
|
WriteObjects<mstudiosrcbonetransform_t>( &pDataDest, &pDataSrc, SrcNative( &pStudioHdr2->numsrcbonetransform ) );
|
|
}
|
|
|
|
if ( pStudioHdr2->linearboneindex )
|
|
{
|
|
SET_INDEX_POINTERS_FIXUP( pData, pStudioHdr2, linearboneindex )
|
|
DECLARE_OBJECT_POINTERS( pLinearBone, pData, mstudiolinearbone_t )
|
|
|
|
WriteObjects( pLinearBoneDest, pLinearBoneSrc );
|
|
|
|
int numBones = SrcNative( &pLinearBone->numbones );
|
|
SET_INDEX_POINTERS_FIXUP( pData, pLinearBone, flagsindex )
|
|
WriteBuffer<int>( &pDataDest, &pDataSrc, numBones );
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pLinearBone, parentindex )
|
|
WriteBuffer<int>( &pDataDest, &pDataSrc, numBones );
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pLinearBone, posindex )
|
|
WriteBuffer<float>( &pDataDest, &pDataSrc, 3*numBones );
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pLinearBone, quatindex )
|
|
WriteBuffer<float>( &pDataDest, &pDataSrc, 4*numBones );
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pLinearBone, rotindex )
|
|
WriteBuffer<float>( &pDataDest, &pDataSrc, 3*numBones );
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pLinearBone, posetoboneindex )
|
|
WriteBuffer<float>( &pDataDest, &pDataSrc, 12*numBones );
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pLinearBone, posscaleindex )
|
|
WriteBuffer<float>( &pDataDest, &pDataSrc, 3*numBones );
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pLinearBone, rotscaleindex )
|
|
WriteBuffer<float>( &pDataDest, &pDataSrc, 3*numBones );
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pLinearBone, qalignmentindex )
|
|
WriteBuffer<float>( &pDataDest, &pDataSrc, 4*numBones );
|
|
}
|
|
|
|
/** BONE FLEX DRIVERS **/
|
|
if ( pStudioHdr2->m_nBoneFlexDriverIndex )
|
|
{
|
|
SET_INDEX_POINTERS_FIXUP( pData, pStudioHdr2, m_nBoneFlexDriverIndex )
|
|
DECLARE_OBJECT_POINTERS( pBoneFlexDriver, pData, mstudioboneflexdriver_t )
|
|
ITERATE_BLOCK( pBoneFlexDriver, pStudioHdr2->m_nBoneFlexDriverCount )
|
|
{
|
|
WriteObjects( pBoneFlexDriverDest, pBoneFlexDriverSrc );
|
|
|
|
/** BONE FLEX DRIVER CONTROLS **/
|
|
|
|
SET_INDEX_POINTERS_FIXUP( pData, pBoneFlexDriver, m_nControlIndex );
|
|
WriteObjects< mstudioboneflexdrivercontrol_t >( &pDataDest, &pDataSrc, SrcNative( &pBoneFlexDriver->m_nControlCount ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** STRING TABLE **/
|
|
|
|
// NOTE: The block of data (above) swapped immediately before the string table MUST update the
|
|
// pDataSrc pointer position, in order for this string table offset calculation to work correctly.
|
|
// To update the pointer position, pass the pointer address to WriteObjects().
|
|
int offset = pDataSrc - (byte*)pSrcBase;
|
|
int stringTableBytes = fixedFileSize - offset;
|
|
WriteBuffer<char>( pDataDest, pDataSrc, stringTableBytes );
|
|
|
|
pHdrDest->length = DestNative( &fixedFileSize );
|
|
|
|
// Cleanup texture paths
|
|
// Some older MDL's have double terminal slashes
|
|
SET_INDEX_POINTERS( pData, pHdr, cdtextureindex )
|
|
int numCdTextures = SrcNative( &pHdr->numcdtextures );
|
|
for ( int i = 0; i < numCdTextures; ++i )
|
|
{
|
|
char *pPath = (char*)pHdrDest + SrcNative( &((int *)pDataSrc)[i] );
|
|
int len = strlen( pPath );
|
|
if ( len >= 2 && ( pPath[len-1] == '\\' || pPath[len-1] == '/' ) && ( pPath[len-2] == '\\' || pPath[len-2] == '/' ) )
|
|
{
|
|
pPath[len-1] = '\0';
|
|
}
|
|
}
|
|
|
|
return fixedFileSize;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Swap a .mdl in two passes - first pass fixes alignment errors by shifting
|
|
// the data and updating offsets, then the second pass does the final swap.
|
|
//----------------------------------------------------------------------
|
|
int ByteswapMDL( void *pDestBase, const void *pSrcBase, const int fileSize )
|
|
{
|
|
// Make a working copy of the source to allow for alignment fixups
|
|
void *pNewSrcBase = malloc( fileSize + BYTESWAP_ALIGNMENT_PADDING );
|
|
Q_memcpy( pNewSrcBase, pSrcBase, fileSize );
|
|
|
|
int fixedFileSize = ByteswapMDLFile( pDestBase, pNewSrcBase, fileSize );
|
|
if ( fixedFileSize != fileSize )
|
|
{
|
|
int finalSize = ByteswapMDLFile( pDestBase, pNewSrcBase, fixedFileSize );
|
|
if ( finalSize != fixedFileSize )
|
|
{
|
|
Warning( "Alignment fixups failed on MDL swap!\n" );
|
|
fixedFileSize = 0;
|
|
}
|
|
}
|
|
|
|
free( pNewSrcBase );
|
|
|
|
// the compression needs to happen on the final or "fixed" pass
|
|
if ( g_pCompressFunc && fixedFileSize )
|
|
{
|
|
void *pInput = pDestBase;
|
|
int inputSize = fixedFileSize;
|
|
void *pOutput;
|
|
int outputSize;
|
|
if ( g_pCompressFunc( pInput, inputSize, &pOutput, &outputSize ) )
|
|
{
|
|
V_memcpy( pDestBase, pOutput, outputSize );
|
|
free( pOutput );
|
|
fixedFileSize = outputSize;
|
|
}
|
|
}
|
|
|
|
return fixedFileSize;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Determines what kind of file this is and calls the correct swap function
|
|
//----------------------------------------------------------------------
|
|
int ByteswapStudioFile( const char *pFilename, void *pOutBase, const void *pFileBase, int fileSize, studiohdr_t *pHdr, CompressFunc_t pCompressFunc )
|
|
{
|
|
assert( pFilename );
|
|
assert( pOutBase != pFileBase );
|
|
|
|
g_pCompressFunc = pCompressFunc;
|
|
|
|
int retVal = 0;
|
|
|
|
if ( Q_stristr( pFilename, ".mdl" ) )
|
|
{
|
|
retVal = ByteswapMDL( pOutBase, pFileBase, fileSize );
|
|
}
|
|
else if ( Q_stristr( pFilename, ".vvd" ) )
|
|
{
|
|
retVal = ByteswapVVD( pOutBase, pFileBase, fileSize );
|
|
}
|
|
else if ( Q_stristr( pFilename, ".vtx" ) )
|
|
{
|
|
retVal = ByteswapVTX( pOutBase, pFileBase, fileSize );
|
|
}
|
|
else if ( Q_stristr( pFilename, ".phy" ) )
|
|
{
|
|
retVal = ByteswapPHY( pOutBase, pFileBase, fileSize );
|
|
}
|
|
else if ( Q_stristr( pFilename, ".ani" ) )
|
|
{
|
|
// some dead .ani files exist in the tree
|
|
// only process valid .ani files properly hooked to their .mdl
|
|
if ( pHdr && pHdr->numanimblocks != 0 )
|
|
{
|
|
retVal = ByteswapANI( pHdr, pOutBase, pFileBase, fileSize );
|
|
}
|
|
}
|
|
|
|
g_pCompressFunc = NULL;
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// LEGACY ANI FIXUPS - No need to update this function
|
|
//
|
|
// If model data needs to be shifted to fix a misalignment, this function is
|
|
// called with the process func "UpdateSrcIndexFields" to update every datadesc field
|
|
// that was marked as FIELD_INDEX. Any index that "points" across
|
|
// the shifted data location will have its value incremented or decremented
|
|
// by the appropriate number of bytes. This misalignment issue only
|
|
// applies to some pre-EP2 models, as all newly compiled models are guaranteed
|
|
// to be aligned correctly. Therefore, this function should not need to change
|
|
// when model formats are updated, as any model compiled with a new format will
|
|
// naturally not require this fixup function to be called.
|
|
//----------------------------------------------------------------------
|
|
void ProcessANIFields( void *pDataBase, datadescProcessFunc_t pfnProcessFunc )
|
|
{
|
|
studiohdr_t *pHdr = g_pHdr;
|
|
byte *pData = (byte*)pDataBase;
|
|
byte *pSrcBase = (byte*)g_pDataSrcBase;
|
|
|
|
// Since the animblocks and animdescs are native data, trick the system
|
|
// into not swapping their index values during processing.
|
|
bool bNativeSrc = g_bNativeSrc;
|
|
g_bNativeSrc = true;
|
|
|
|
// Update the .mdl's animblock offsets into the .ani file
|
|
mstudioanimblock_t *pAnimBlock = pHdr->pAnimBlock( 1 );
|
|
for ( int i = 1; i < pHdr->numanimblocks; ++i, ++pAnimBlock )
|
|
{
|
|
ProcessFields( pSrcBase, pAnimBlock, &mstudioanimblock_t::m_DataMap, pfnProcessFunc );
|
|
}
|
|
|
|
// Update the .mdl's animindex offsets into the .ani file
|
|
// Don't bother with local hierarchy keys - they only exist in newer, properly aligned models
|
|
mstudioanimdesc_t *pAnimDesc = pHdr->pLocalAnimdesc( 0 );
|
|
for ( int i = 0; i < pHdr->numlocalanim; ++i, ++pAnimDesc )
|
|
{
|
|
mstudioanimblock_t *pAnimBlock = pHdr->pAnimBlock( pAnimDesc->animblock );
|
|
byte *pBlockBase = (byte*)pSrcBase + pAnimBlock->datastart;
|
|
|
|
ProcessFieldByName( pBlockBase, pAnimDesc, &mstudioanimdesc_t::m_DataMap, "animindex", pfnProcessFunc );
|
|
ProcessFieldByName( pBlockBase, pAnimDesc, &mstudioanimdesc_t::m_DataMap, "animblockikruleindex", pfnProcessFunc );
|
|
}
|
|
|
|
// Restore the correct native setting
|
|
g_bNativeSrc = bNativeSrc;
|
|
|
|
// Update the .ani file's internal offsets
|
|
pAnimDesc = pHdr->pLocalAnimdesc( 0 );
|
|
for ( int i = 0; i < pHdr->numlocalanim; ++i, ++pAnimDesc )
|
|
{
|
|
pAnimBlock = pHdr->pAnimBlock( pAnimDesc->animblock );
|
|
byte *pBlockBase = (byte*)pSrcBase + pAnimBlock->datastart;
|
|
|
|
byte *pData = pBlockBase + pAnimDesc->animindex;
|
|
mstudioanim_t* pAnimation = (mstudioanim_t*)pData;
|
|
if ( pAnimation->bone == 255 )
|
|
{
|
|
// No animation data
|
|
pAnimation = 0;
|
|
}
|
|
|
|
while( pAnimation )
|
|
{
|
|
ProcessFields( pAnimation, &mstudioanim_t::m_DataMap, pfnProcessFunc );
|
|
|
|
if ( pAnimation->nextoffset )
|
|
{
|
|
pData = (byte*)pAnimation + SrcNative( &pAnimation->nextoffset );
|
|
pAnimation = (mstudioanim_t*)pData;
|
|
}
|
|
else
|
|
{
|
|
pAnimation = NULL;
|
|
}
|
|
}
|
|
|
|
if ( pAnimDesc->animblockikruleindex )
|
|
{
|
|
pData = (byte*)pBlockBase + pAnimDesc->animblockikruleindex;
|
|
|
|
mstudioikrule_t *pIKRule = (mstudioikrule_t *)pData;
|
|
for ( int i = 0; i < pAnimDesc->numikrules; ++i, ++pIKRule )
|
|
{
|
|
ProcessFields( pIKRule, &mstudioikrule_t::m_DataMap, pfnProcessFunc );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// LEGACY MDL FIXUPS - No need to update this function
|
|
//
|
|
// If model data needs to be shifted to fix a misalignment, this function is
|
|
// called with the process func "UpdateSrcIndexFields" to update every datadesc field
|
|
// that was marked as FIELD_INDEX. Any index that "points" across
|
|
// the shifted data location will have its value incremented or decremented
|
|
// by the appropriate number of bytes. This misalignment issue only
|
|
// applies to some pre-EP2 models, as all newly compiled models are guaranteed
|
|
// to be aligned correctly. Therefore, this function should not need to change
|
|
// when model formats are updated, as any model compiled with a new format will
|
|
// naturally not require this fixup function to be called.
|
|
//----------------------------------------------------------------------
|
|
void ProcessMDLFields( void *pDataBase, datadescProcessFunc_t pfnProcessFunc )
|
|
{
|
|
byte *pData = (byte*)pDataBase;
|
|
|
|
/** FILE HEADER **/
|
|
|
|
studiohdr_t *pHdr = (studiohdr_t*)pData;
|
|
ProcessFields( pHdr, &studiohdr_t::m_DataMap, pfnProcessFunc );
|
|
|
|
/** BONES **/
|
|
|
|
pData = (byte*)pHdr + SrcNative( &pHdr->boneindex );
|
|
mstudiobone_t *pBone = (mstudiobone_t*)pData;
|
|
for ( int i = 0; i < SrcNative( &pHdr->numbones ); ++i, ++pBone )
|
|
{
|
|
ProcessFields( pBone, &mstudiobone_t::m_DataMap, pfnProcessFunc );
|
|
|
|
if ( pBone->procindex )
|
|
{
|
|
pData = (byte*)pBone + SrcNative( &pBone->procindex );
|
|
|
|
unsigned int proctype = SrcNative( &pBone->proctype );
|
|
switch( proctype )
|
|
{
|
|
case STUDIO_PROC_AXISINTERP:
|
|
|
|
/** AXIS-INTERP BONES **/
|
|
ProcessFields( pData, &mstudioaxisinterpbone_t::m_DataMap, pfnProcessFunc );
|
|
break;
|
|
|
|
case STUDIO_PROC_QUATINTERP:
|
|
|
|
/** QUAT-INTERP BONES **/
|
|
ProcessFields( pData, &mstudioquatinterpbone_t::m_DataMap, pfnProcessFunc );
|
|
break;
|
|
|
|
case STUDIO_PROC_JIGGLE:
|
|
|
|
/** JIGGLE BONES **/
|
|
ProcessFields( pData, &mstudiojigglebone_t::m_DataMap, pfnProcessFunc );
|
|
break;
|
|
|
|
case STUDIO_PROC_AIMATBONE:
|
|
case STUDIO_PROC_AIMATATTACH:
|
|
|
|
/** AIM AT BONES **/
|
|
ProcessFields( pData, &mstudioaimatbone_t::m_DataMap, pfnProcessFunc );
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
/** ATTACHMENTS **/
|
|
|
|
pData = (byte*)pHdr + SrcNative( &pHdr->localattachmentindex );
|
|
mstudioattachment_t *pAttachment = (mstudioattachment_t*)pData;
|
|
for ( int i = 0; i < SrcNative( &pHdr->numlocalattachments ); ++i, ++pAttachment )
|
|
{
|
|
ProcessFields( pAttachment, &mstudioattachment_t::m_DataMap, pfnProcessFunc );
|
|
}
|
|
|
|
/** HITBOX SETS **/
|
|
|
|
pData = (byte*)pHdr + SrcNative( &pHdr->hitboxsetindex );
|
|
mstudiohitboxset_t* pHitboxSet = (mstudiohitboxset_t*)pData;
|
|
for ( int i = 0; i < SrcNative( &pHdr->numhitboxsets ); ++i, ++pHitboxSet )
|
|
{
|
|
ProcessFields( pHitboxSet, &mstudiohitboxset_t::m_DataMap, pfnProcessFunc );
|
|
|
|
/** HITBOXES **/
|
|
pData = (byte*)pHitboxSet + SrcNative( &pHitboxSet->hitboxindex );
|
|
mstudiobbox_t *pBBox = (mstudiobbox_t*)pData;
|
|
for ( int i = 0; i < SrcNative( &pHitboxSet->numhitboxes ); ++i, ++pBBox )
|
|
{
|
|
ProcessFields( pBBox, &mstudiobbox_t::m_DataMap, pfnProcessFunc );
|
|
}
|
|
}
|
|
|
|
/** ANIMATION DESCRIPTIONS **/
|
|
|
|
pData = (byte*)pHdr + SrcNative( &pHdr->localanimindex );
|
|
mstudioanimdesc_t* pAnimDesc = (mstudioanimdesc_t*)pData;
|
|
for ( int i = 0; i < SrcNative( &pHdr->numlocalanim ); ++i, ++pAnimDesc )
|
|
{
|
|
// Can't update animindex or animblockindex for animations that are in a separate .ani file
|
|
ProcessFieldByName( pAnimDesc, &mstudioanimdesc_t::m_DataMap, "baseptr", pfnProcessFunc );
|
|
ProcessFieldByName( pAnimDesc, &mstudioanimdesc_t::m_DataMap, "sznameindex", pfnProcessFunc );
|
|
ProcessFieldByName( pAnimDesc, &mstudioanimdesc_t::m_DataMap, "movementindex", pfnProcessFunc );
|
|
ProcessFieldByName( pAnimDesc, &mstudioanimdesc_t::m_DataMap, "ikruleindex", pfnProcessFunc );
|
|
|
|
/** ANIMATIONS **/
|
|
|
|
if ( pAnimDesc->animblock == 0 )
|
|
{
|
|
// Now it's safe to update the animindex
|
|
ProcessFieldByName( pAnimDesc, &mstudioanimdesc_t::m_DataMap, "animindex", pfnProcessFunc );
|
|
|
|
pData = (byte*)pAnimDesc + SrcNative( &pAnimDesc->animindex );
|
|
mstudioanim_t* pAnimation = (mstudioanim_t*)pData;
|
|
while( pAnimation )
|
|
{
|
|
ProcessFields( pAnimation, &mstudioanim_t::m_DataMap, pfnProcessFunc );
|
|
|
|
if ( pAnimation->nextoffset )
|
|
{
|
|
pData = (byte*)pAnimation + SrcNative( &pAnimation->nextoffset );
|
|
pAnimation = (mstudioanim_t*)pData;
|
|
}
|
|
else
|
|
{
|
|
pAnimation = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( pAnimDesc->ikruleindex )
|
|
{
|
|
pData = (byte*)pAnimDesc + SrcNative( &pAnimDesc->ikruleindex );
|
|
|
|
mstudioikrule_t *pIKRule = (mstudioikrule_t *)pData;
|
|
for ( int i = 0; i < SrcNative( &pAnimDesc->numikrules ); ++i, ++pIKRule )
|
|
{
|
|
ProcessFields( pIKRule, &mstudioikrule_t::m_DataMap, pfnProcessFunc );
|
|
}
|
|
}
|
|
}
|
|
|
|
/** SEQUENCE INFO **/
|
|
|
|
pData = (byte*)pHdr + SrcNative( &pHdr->localseqindex );
|
|
mstudioseqdesc_t *pSequenceHdr = (mstudioseqdesc_t*)pData;
|
|
for ( int i = 0; i < SrcNative( &pHdr->numlocalseq ); ++i, ++pSequenceHdr )
|
|
{
|
|
ProcessFields( pSequenceHdr, &mstudioseqdesc_t::m_DataMap, pfnProcessFunc );
|
|
|
|
/** STUDIO EVENTS **/
|
|
|
|
pData = (byte*)pHdr + SrcNative( &pSequenceHdr->eventindex );
|
|
mstudioevent_t *pEvent = (mstudioevent_t*)pData;
|
|
for ( int i = 0; i < SrcNative( &pSequenceHdr->numevents ); ++i, ++pEvent )
|
|
{
|
|
ProcessFields( pSequenceHdr, &mstudioevent_t::m_DataMap, pfnProcessFunc );
|
|
}
|
|
}
|
|
|
|
/** BODYPART INFO **/
|
|
|
|
pData = (byte*)pHdr + SrcNative( &pHdr->bodypartindex );
|
|
mstudiobodyparts_t *pBodypart = (mstudiobodyparts_t*)pData;
|
|
for ( int i = 0; i < SrcNative( &pHdr->numbodyparts ); ++i, ++pBodypart )
|
|
{
|
|
ProcessFields( pBodypart, &mstudiobodyparts_t::m_DataMap, pfnProcessFunc );
|
|
|
|
/** MODEL INFO **/
|
|
|
|
byte *pData = (byte*)pBodypart + SrcNative( &pBodypart->modelindex );
|
|
mstudiomodel_t *pModel = (mstudiomodel_t*)pData;
|
|
for ( int i = 0; i < SrcNative( &pBodypart->nummodels ); ++i, ++pModel )
|
|
{
|
|
ProcessFields( pModel, &mstudiomodel_t::m_DataMap, pfnProcessFunc );
|
|
|
|
/** MESHES **/
|
|
|
|
pData = (byte*)pModel + SrcNative( &pModel->meshindex );
|
|
mstudiomesh_t *pMesh = (mstudiomesh_t*)pData;
|
|
for ( int i = 0; i < SrcNative( &pModel->nummeshes ); ++i, ++pMesh )
|
|
{
|
|
ProcessFields( pMesh, &mstudiomesh_t::m_DataMap, pfnProcessFunc );
|
|
|
|
if ( !pMesh->numflexes )
|
|
continue;
|
|
|
|
/** FLEXES **/
|
|
|
|
pData = (byte*)pMesh + SrcNative( &pMesh->flexindex );
|
|
mstudioflex_t *pFlex = (mstudioflex_t*)pData;
|
|
for ( int i = 0; i < SrcNative( &pMesh->numflexes ); ++i, ++pFlex )
|
|
{
|
|
ProcessFields( pFlex, &mstudioflex_t::m_DataMap, pfnProcessFunc );
|
|
}
|
|
}
|
|
|
|
/** EYEBALLS **/
|
|
|
|
pData= (byte*)pModel + SrcNative( &pModel->eyeballindex );
|
|
mstudioeyeball_t *pEyeball = (mstudioeyeball_t*)pData;
|
|
for ( int i = 0; i < SrcNative( &pModel->numeyeballs ); ++i, ++pEyeball )
|
|
{
|
|
ProcessFields( pEyeball, &mstudioeyeball_t::m_DataMap, pfnProcessFunc );
|
|
}
|
|
}
|
|
}
|
|
|
|
/** GLOBAL FLEX NAMES **/
|
|
|
|
pData = (byte*)pHdr + SrcNative( &pHdr->flexdescindex );
|
|
mstudioflexdesc_t *pFlexDesc = (mstudioflexdesc_t*)pData;
|
|
for ( int i = 0; i < SrcNative( &pHdr->numflexdesc ); ++i, ++pFlexDesc )
|
|
{
|
|
ProcessFields( pFlexDesc, &mstudioflexdesc_t::m_DataMap, pfnProcessFunc );
|
|
}
|
|
|
|
/** GLOBAL FLEX CONTROLLERS **/
|
|
|
|
pData = (byte*)pHdr + SrcNative( &pHdr->flexcontrollerindex );
|
|
mstudioflexcontroller_t *pFlexController = (mstudioflexcontroller_t*)pData;
|
|
for ( int i = 0; i < SrcNative( &pHdr->numflexcontrollers ); ++i, ++pFlexController )
|
|
{
|
|
ProcessFields( pFlexController, &mstudioflexcontroller_t::m_DataMap, pfnProcessFunc );
|
|
}
|
|
|
|
/** GLOBAL FLEX CONTROLLER REMAPS **/
|
|
|
|
pData = (byte*)pHdr + SrcNative( &pHdr->flexcontrolleruiindex );
|
|
mstudioflexcontrollerui_t *pFlexControllerRemap = (mstudioflexcontrollerui_t*)pData;
|
|
for ( int i = 0; i < SrcNative( &pHdr->numflexcontrollerui ); ++i, ++pFlexControllerRemap )
|
|
{
|
|
ProcessFields( pFlexControllerRemap, &mstudioflexcontrollerui_t::m_DataMap, pfnProcessFunc );
|
|
}
|
|
|
|
/** FLEX RULES **/
|
|
|
|
pData = (byte*)pHdr + SrcNative( &pHdr->flexruleindex );
|
|
mstudioflexrule_t *pFlexRule = (mstudioflexrule_t*)pData;
|
|
for ( int i = 0; i < SrcNative( &pHdr->numflexrules ); ++i, ++pFlexRule )
|
|
{
|
|
ProcessFields( pFlexRule, &mstudioflexrule_t::m_DataMap, pfnProcessFunc );
|
|
}
|
|
|
|
/** IK CHAINS **/
|
|
|
|
pData = (byte*)pHdr + SrcNative( &pHdr->ikchainindex );
|
|
mstudioikchain_t *pIKChain = (mstudioikchain_t*)pData;
|
|
for ( int i = 0; i < SrcNative( &pHdr->numikchains ); ++i, ++pIKChain )
|
|
{
|
|
ProcessFields( pIKChain, &mstudioikchain_t::m_DataMap, pfnProcessFunc );
|
|
}
|
|
|
|
/** POSE PARAMATERS **/
|
|
|
|
pData = (byte*)pHdr + SrcNative( &pHdr->localposeparamindex );
|
|
mstudioposeparamdesc_t *pPoseParam = (mstudioposeparamdesc_t*)pData;
|
|
for ( int i = 0; i < SrcNative( &pHdr->numlocalposeparameters ); ++i, ++pPoseParam )
|
|
{
|
|
ProcessFields( pPoseParam, &mstudioposeparamdesc_t::m_DataMap, pfnProcessFunc );
|
|
}
|
|
|
|
/** MODEL GROUPS **/
|
|
|
|
pData = (byte*)pHdr + SrcNative( &pHdr->includemodelindex );
|
|
mstudiomodelgroup_t *pMdl = (mstudiomodelgroup_t*)pData;
|
|
for ( int i = 0; i < SrcNative( &pHdr->numincludemodels ); ++i, ++pMdl )
|
|
{
|
|
ProcessFields( pMdl, &mstudiomodelgroup_t::m_DataMap, pfnProcessFunc );
|
|
}
|
|
|
|
/** TEXTURE INFO **/
|
|
|
|
pData = (byte*)pHdr + SrcNative( &pHdr->textureindex );
|
|
mstudiotexture_t *pTexture = (mstudiotexture_t*)pData;
|
|
for ( int i = 0; i < SrcNative( &pHdr->numtextures ); ++i, ++pTexture )
|
|
{
|
|
ProcessFields( pTexture, &mstudiotexture_t::m_DataMap, pfnProcessFunc );
|
|
}
|
|
|
|
/** CDTEXTURE OFFSETS **/
|
|
|
|
pData = (byte*)pHdr + SrcNative( &pHdr->cdtextureindex );
|
|
int *pIdx = (int*)pData;
|
|
for ( int i = 0; i < SrcNative( &pHdr->numcdtextures ); ++i, ++pIdx )
|
|
{
|
|
int idx = SrcNative( pIdx );
|
|
UpdateIndex( pHdr, &idx );
|
|
*pIdx = SrcNative( &idx );
|
|
}
|
|
|
|
/** STUDIOHDR2 **/
|
|
|
|
if ( pHdr->studiohdr2index )
|
|
{
|
|
pData = (byte*)pHdr + SrcNative( &pHdr->studiohdr2index );
|
|
studiohdr2_t *pStudioHdr2 = (studiohdr2_t*)pData;
|
|
for ( int i = 0; i < 1; ++i, ++pStudioHdr2 )
|
|
{
|
|
ProcessFields( pStudioHdr2, &studiohdr2_t::m_DataMap, pfnProcessFunc );
|
|
|
|
/** SRC BONE TRANSFORMS **/
|
|
|
|
pData = (byte*)pHdr + SrcNative( &pStudioHdr2->srcbonetransformindex );
|
|
mstudiosrcbonetransform_t *pSrcBoneTransform = (mstudiosrcbonetransform_t*)pData;
|
|
for ( int i = 0; i < SrcNative( &pStudioHdr2->numsrcbonetransform ); ++i, ++pSrcBoneTransform )
|
|
{
|
|
ProcessFields( pSrcBoneTransform, &mstudiosrcbonetransform_t::m_DataMap, pfnProcessFunc );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#pragma warning( pop ) // local variable is initialized but not referenced
|
|
|
|
} // namespace StudioByteSwap
|
|
|
|
// Data descriptions for byte swapping - only needed
|
|
// for structures that are written to file for use by the game.
|
|
// For any fields that reference other data in the file, use the
|
|
// DEFINE_INDEX macro to identify them as such.
|
|
BEGIN_BYTESWAP_DATADESC( studiohdr_t )
|
|
DEFINE_FIELD( id, FIELD_INTEGER ),
|
|
DEFINE_FIELD( version, FIELD_INTEGER ),
|
|
DEFINE_FIELD( checksum, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( name, FIELD_CHARACTER, 64 ),
|
|
DEFINE_FIELD( length, FIELD_INTEGER ),
|
|
DEFINE_FIELD( eyeposition, FIELD_VECTOR ),
|
|
DEFINE_FIELD( illumposition, FIELD_VECTOR ),
|
|
DEFINE_FIELD( hull_min, FIELD_VECTOR ),
|
|
DEFINE_FIELD( hull_max, FIELD_VECTOR ),
|
|
DEFINE_FIELD( view_bbmin, FIELD_VECTOR ),
|
|
DEFINE_FIELD( view_bbmax, FIELD_VECTOR ),
|
|
DEFINE_FIELD( flags, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numbones, FIELD_INTEGER ), // bones
|
|
DEFINE_INDEX( boneindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numbonecontrollers, FIELD_INTEGER ), // bone controllers
|
|
DEFINE_INDEX( bonecontrollerindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numhitboxsets, FIELD_INTEGER ),
|
|
DEFINE_INDEX( hitboxsetindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numlocalanim, FIELD_INTEGER ), // animations/poses
|
|
DEFINE_INDEX( localanimindex, FIELD_INTEGER ), // animation descriptions
|
|
DEFINE_FIELD( numlocalseq, FIELD_INTEGER ), // sequences
|
|
DEFINE_INDEX( localseqindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( activitylistversion, FIELD_INTEGER ), // initialization flag - have the sequences been indexed?
|
|
DEFINE_FIELD( eventsindexed, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numtextures, FIELD_INTEGER ),
|
|
DEFINE_INDEX( textureindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numcdtextures, FIELD_INTEGER ),
|
|
DEFINE_INDEX( cdtextureindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numskinref, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numskinfamilies, FIELD_INTEGER ),
|
|
DEFINE_INDEX( skinindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numbodyparts, FIELD_INTEGER ),
|
|
DEFINE_INDEX( bodypartindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numlocalattachments, FIELD_INTEGER ),
|
|
DEFINE_INDEX( localattachmentindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numlocalnodes, FIELD_INTEGER ),
|
|
DEFINE_INDEX( localnodeindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( localnodenameindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numflexdesc, FIELD_INTEGER ),
|
|
DEFINE_INDEX( flexdescindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numflexcontrollers, FIELD_INTEGER ),
|
|
DEFINE_INDEX( flexcontrollerindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numflexrules, FIELD_INTEGER ),
|
|
DEFINE_INDEX( flexruleindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numikchains, FIELD_INTEGER ),
|
|
DEFINE_INDEX( ikchainindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( nummouths, FIELD_INTEGER ),
|
|
DEFINE_INDEX( mouthindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numlocalposeparameters, FIELD_INTEGER ),
|
|
DEFINE_INDEX( localposeparamindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( surfacepropindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( keyvalueindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( keyvaluesize, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numlocalikautoplaylocks, FIELD_INTEGER ),
|
|
DEFINE_INDEX( localikautoplaylockindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( mass, FIELD_FLOAT ),
|
|
DEFINE_FIELD( contents, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numincludemodels, FIELD_INTEGER ),
|
|
DEFINE_INDEX( includemodelindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( virtualModel, FIELD_INTEGER ), // void*
|
|
DEFINE_INDEX( szanimblocknameindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numanimblocks, FIELD_INTEGER ),
|
|
DEFINE_INDEX( animblockindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( animblockModel, FIELD_INTEGER ), // void*
|
|
DEFINE_INDEX( bonetablebynameindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( pVertexBase, FIELD_INTEGER ), // void*
|
|
DEFINE_FIELD( pIndexBase, FIELD_INTEGER ), // void*
|
|
DEFINE_FIELD( constdirectionallightdot, FIELD_CHARACTER ), // byte
|
|
DEFINE_FIELD( rootLOD, FIELD_CHARACTER ), // byte
|
|
DEFINE_FIELD( numAllowedRootLODs, FIELD_CHARACTER ), // byte
|
|
DEFINE_ARRAY( unused, FIELD_CHARACTER, 1 ), // byte
|
|
DEFINE_INDEX( unused4, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numflexcontrollerui, FIELD_INTEGER ),
|
|
DEFINE_INDEX( flexcontrolleruiindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( flVertAnimFixedPointScale, FIELD_FLOAT ),
|
|
DEFINE_ARRAY( unused3, FIELD_INTEGER, 1 ),
|
|
DEFINE_INDEX( studiohdr2index, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( unused2, FIELD_INTEGER, 1 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
// NOTE! Next time we up the .mdl file format, remove studiohdr2_t
|
|
// and insert all fields in this structure into studiohdr_t.
|
|
BEGIN_BYTESWAP_DATADESC( studiohdr2_t )
|
|
DEFINE_FIELD( numsrcbonetransform, FIELD_INTEGER ),
|
|
DEFINE_INDEX( srcbonetransformindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( illumpositionattachmentindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( flMaxEyeDeflection, FIELD_FLOAT ),
|
|
DEFINE_INDEX( linearboneindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( sznameindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( m_nBoneFlexDriverCount, FIELD_INTEGER ),
|
|
DEFINE_INDEX( m_nBoneFlexDriverIndex, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( reserved, FIELD_INTEGER, 56 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudiobone_t )
|
|
DEFINE_INDEX( sznameindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( parent, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( bonecontroller, FIELD_INTEGER, 6 ),
|
|
DEFINE_FIELD( pos, FIELD_VECTOR ),
|
|
DEFINE_FIELD( quat, FIELD_QUATERNION ),
|
|
DEFINE_ARRAY( rot, FIELD_FLOAT, 3 ), // RadianEuler
|
|
DEFINE_FIELD( posscale, FIELD_VECTOR ),
|
|
DEFINE_FIELD( rotscale, FIELD_VECTOR ),
|
|
DEFINE_ARRAY( poseToBone, FIELD_FLOAT, 12 ), // matrix3x4_t
|
|
DEFINE_FIELD( qAlignment, FIELD_QUATERNION ),
|
|
DEFINE_FIELD( flags, FIELD_INTEGER ),
|
|
DEFINE_FIELD( proctype, FIELD_INTEGER ),
|
|
DEFINE_INDEX( procindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( physicsbone, FIELD_INTEGER ),
|
|
DEFINE_INDEX( surfacepropidx, FIELD_INTEGER ),
|
|
DEFINE_FIELD( contents, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( unused, FIELD_INTEGER, 8 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudiolinearbone_t )
|
|
DEFINE_FIELD( numbones, FIELD_INTEGER ),
|
|
DEFINE_INDEX( flagsindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( parentindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( posindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( quatindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( rotindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( posetoboneindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( posscaleindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( rotscaleindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( qalignmentindex, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( unused, FIELD_INTEGER, 6 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioboneflexdrivercontrol_t )
|
|
DEFINE_INDEX( m_nBoneComponent, FIELD_INTEGER ),
|
|
DEFINE_FIELD( m_nFlexControllerIndex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( m_flMin, FIELD_FLOAT ),
|
|
DEFINE_INDEX( m_flMax, FIELD_FLOAT ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioboneflexdriver_t )
|
|
DEFINE_INDEX( m_nBoneIndex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( m_nControlCount, FIELD_INTEGER ),
|
|
DEFINE_INDEX( m_nControlIndex, FIELD_FLOAT ),
|
|
DEFINE_ARRAY( unused, FIELD_INTEGER, 3 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioaxisinterpbone_t )
|
|
DEFINE_FIELD( control, FIELD_INTEGER ),
|
|
DEFINE_FIELD( axis, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( pos, FIELD_VECTOR, 6 ),
|
|
DEFINE_ARRAY( quat, FIELD_QUATERNION, 6 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioquatinterpbone_t )
|
|
DEFINE_FIELD( control, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numtriggers, FIELD_INTEGER ),
|
|
DEFINE_INDEX( triggerindex, FIELD_INTEGER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudiojigglebone_t )
|
|
DEFINE_FIELD( flags, FIELD_INTEGER ),
|
|
DEFINE_FIELD( length, FIELD_FLOAT ),
|
|
DEFINE_FIELD( tipMass, FIELD_FLOAT ),
|
|
DEFINE_FIELD( yawStiffness, FIELD_FLOAT ),
|
|
DEFINE_FIELD( yawDamping, FIELD_FLOAT ),
|
|
DEFINE_FIELD( pitchStiffness, FIELD_FLOAT ),
|
|
DEFINE_FIELD( pitchDamping, FIELD_FLOAT ),
|
|
DEFINE_FIELD( alongStiffness, FIELD_FLOAT ),
|
|
DEFINE_FIELD( alongDamping, FIELD_FLOAT ),
|
|
DEFINE_FIELD( angleLimit, FIELD_FLOAT ),
|
|
DEFINE_FIELD( minYaw, FIELD_FLOAT ),
|
|
DEFINE_FIELD( maxYaw, FIELD_FLOAT ),
|
|
DEFINE_FIELD( yawFriction, FIELD_FLOAT ),
|
|
DEFINE_FIELD( yawBounce, FIELD_FLOAT ),
|
|
DEFINE_FIELD( minPitch, FIELD_FLOAT ),
|
|
DEFINE_FIELD( maxPitch, FIELD_FLOAT ),
|
|
DEFINE_FIELD( pitchFriction, FIELD_FLOAT ),
|
|
DEFINE_FIELD( pitchBounce, FIELD_FLOAT ),
|
|
DEFINE_FIELD( baseMass, FIELD_FLOAT ),
|
|
DEFINE_FIELD( baseStiffness, FIELD_FLOAT ),
|
|
DEFINE_FIELD( baseDamping, FIELD_FLOAT ),
|
|
DEFINE_FIELD( baseMinLeft, FIELD_FLOAT ),
|
|
DEFINE_FIELD( baseMaxLeft, FIELD_FLOAT ),
|
|
DEFINE_FIELD( baseLeftFriction, FIELD_FLOAT ),
|
|
DEFINE_FIELD( baseMinUp, FIELD_FLOAT ),
|
|
DEFINE_FIELD( baseMaxUp, FIELD_FLOAT ),
|
|
DEFINE_FIELD( baseUpFriction, FIELD_FLOAT ),
|
|
DEFINE_FIELD( baseMinForward, FIELD_FLOAT ),
|
|
DEFINE_FIELD( baseMaxForward, FIELD_FLOAT ),
|
|
DEFINE_FIELD( baseForwardFriction, FIELD_FLOAT ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioaimatbone_t )
|
|
DEFINE_FIELD( parent, FIELD_INTEGER ),
|
|
DEFINE_FIELD( aim, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( aimvector, FIELD_FLOAT, 3 ),
|
|
DEFINE_ARRAY( upvector, FIELD_FLOAT, 3 ),
|
|
DEFINE_ARRAY( basepos, FIELD_FLOAT, 3 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioquatinterpinfo_t )
|
|
DEFINE_FIELD( inv_tolerance, FIELD_FLOAT ),
|
|
DEFINE_FIELD( trigger, FIELD_QUATERNION ),
|
|
DEFINE_FIELD( pos, FIELD_VECTOR ),
|
|
DEFINE_FIELD( quat, FIELD_QUATERNION ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudiobonecontroller_t )
|
|
DEFINE_FIELD( bone, FIELD_INTEGER ),
|
|
DEFINE_FIELD( type, FIELD_INTEGER ),
|
|
DEFINE_FIELD( start, FIELD_FLOAT ),
|
|
DEFINE_FIELD( end, FIELD_FLOAT ),
|
|
DEFINE_FIELD( rest, FIELD_INTEGER ),
|
|
DEFINE_FIELD( inputfield, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( unused, FIELD_INTEGER, 8 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioattachment_t )
|
|
DEFINE_INDEX( sznameindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( flags, FIELD_INTEGER ),
|
|
DEFINE_FIELD( localbone, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( local, FIELD_FLOAT, 12 ), // matrix3x4_t
|
|
DEFINE_ARRAY( unused, FIELD_INTEGER, 8 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudiohitboxset_t )
|
|
DEFINE_INDEX( sznameindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numhitboxes, FIELD_INTEGER ),
|
|
DEFINE_INDEX( hitboxindex, FIELD_INTEGER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudiosrcbonetransform_t )
|
|
DEFINE_INDEX( sznameindex, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( pretransform, FIELD_FLOAT, 12 ), // matrix3x4_t
|
|
DEFINE_ARRAY( posttransform, FIELD_FLOAT, 12 ), // matrix3x4_t
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudiobbox_t )
|
|
DEFINE_FIELD( bone, FIELD_INTEGER ),
|
|
DEFINE_FIELD( group, FIELD_INTEGER ),
|
|
DEFINE_FIELD( bbmin, FIELD_VECTOR ),
|
|
DEFINE_FIELD( bbmax, FIELD_VECTOR ),
|
|
DEFINE_INDEX( szhitboxnameindex, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( unused, FIELD_INTEGER, 8 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioanim_valueptr_t )
|
|
DEFINE_ARRAY( offset, FIELD_SHORT, 3 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudiolocalhierarchy_t )
|
|
DEFINE_FIELD( iBone, FIELD_INTEGER ),
|
|
DEFINE_FIELD( iNewParent, FIELD_INTEGER ),
|
|
DEFINE_FIELD( start, FIELD_FLOAT ),
|
|
DEFINE_FIELD( peak, FIELD_FLOAT ),
|
|
DEFINE_FIELD( tail, FIELD_FLOAT ),
|
|
DEFINE_FIELD( end, FIELD_FLOAT ),
|
|
DEFINE_FIELD( iStart, FIELD_INTEGER ),
|
|
DEFINE_INDEX( localanimindex, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( unused, FIELD_INTEGER, 4 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioanimsections_t )
|
|
DEFINE_FIELD( animblock, FIELD_INTEGER ),
|
|
DEFINE_INDEX( animindex, FIELD_INTEGER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioanimdesc_t )
|
|
DEFINE_INDEX( baseptr, FIELD_INTEGER ),
|
|
DEFINE_INDEX( sznameindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( fps, FIELD_FLOAT ),
|
|
DEFINE_FIELD( flags, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numframes, FIELD_INTEGER ),
|
|
DEFINE_FIELD( nummovements, FIELD_INTEGER ),
|
|
DEFINE_INDEX( movementindex, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( unused1, FIELD_INTEGER, 6 ),
|
|
DEFINE_FIELD( animblock, FIELD_INTEGER ),
|
|
DEFINE_INDEX( animindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numikrules, FIELD_INTEGER ),
|
|
DEFINE_INDEX( ikruleindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( animblockikruleindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numlocalhierarchy, FIELD_INTEGER ),
|
|
DEFINE_INDEX( localhierarchyindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( sectionindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( sectionframes, FIELD_INTEGER ),
|
|
DEFINE_FIELD( zeroframespan, FIELD_SHORT ),
|
|
DEFINE_FIELD( zeroframecount, FIELD_SHORT ),
|
|
DEFINE_INDEX( zeroframeindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( zeroframestalltime, FIELD_FLOAT ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioanim_t )
|
|
DEFINE_FIELD( bone, FIELD_CHARACTER ),
|
|
DEFINE_FIELD( flags, FIELD_CHARACTER ),
|
|
DEFINE_INDEX( nextoffset, FIELD_SHORT ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioikerror_t )
|
|
DEFINE_FIELD( pos, FIELD_VECTOR ),
|
|
DEFINE_FIELD( q, FIELD_QUATERNION ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudiocompressedikerror_t )
|
|
DEFINE_ARRAY( scale, FIELD_FLOAT, 6 ),
|
|
DEFINE_ARRAY( offset, FIELD_SHORT, 6 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioikrule_t )
|
|
DEFINE_FIELD( index, FIELD_INTEGER ),
|
|
DEFINE_FIELD( type, FIELD_INTEGER ),
|
|
DEFINE_FIELD( chain, FIELD_INTEGER ),
|
|
DEFINE_FIELD( bone, FIELD_INTEGER ),
|
|
DEFINE_FIELD( slot, FIELD_INTEGER ),
|
|
DEFINE_FIELD( height, FIELD_FLOAT ),
|
|
DEFINE_FIELD( radius, FIELD_FLOAT ),
|
|
DEFINE_FIELD( floor, FIELD_FLOAT ),
|
|
DEFINE_FIELD( pos, FIELD_VECTOR ),
|
|
DEFINE_FIELD( q, FIELD_QUATERNION ),
|
|
DEFINE_INDEX( compressedikerrorindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( unused2, FIELD_INTEGER ),
|
|
DEFINE_FIELD( iStart, FIELD_INTEGER ),
|
|
DEFINE_INDEX( ikerrorindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( start, FIELD_FLOAT ),
|
|
DEFINE_FIELD( peak, FIELD_FLOAT ),
|
|
DEFINE_FIELD( tail, FIELD_FLOAT ),
|
|
DEFINE_FIELD( end, FIELD_FLOAT ),
|
|
DEFINE_FIELD( unused3, FIELD_FLOAT ),
|
|
DEFINE_FIELD( contact, FIELD_FLOAT ),
|
|
DEFINE_FIELD( drop, FIELD_FLOAT ),
|
|
DEFINE_FIELD( top, FIELD_FLOAT ),
|
|
DEFINE_FIELD( unused6, FIELD_INTEGER ),
|
|
DEFINE_FIELD( unused7, FIELD_INTEGER ),
|
|
DEFINE_FIELD( unused8, FIELD_INTEGER ),
|
|
DEFINE_INDEX( szattachmentindex, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( unused, FIELD_INTEGER, 7 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudiomovement_t )
|
|
DEFINE_FIELD( endframe, FIELD_INTEGER ),
|
|
DEFINE_FIELD( motionflags, FIELD_INTEGER ),
|
|
DEFINE_FIELD( v0, FIELD_FLOAT ),
|
|
DEFINE_FIELD( v1, FIELD_FLOAT ),
|
|
DEFINE_FIELD( angle, FIELD_FLOAT ),
|
|
DEFINE_FIELD( vector, FIELD_VECTOR ),
|
|
DEFINE_FIELD( position, FIELD_VECTOR ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioseqdesc_t )
|
|
DEFINE_INDEX( baseptr, FIELD_INTEGER ),
|
|
DEFINE_INDEX( szlabelindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( szactivitynameindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( flags, FIELD_INTEGER ), // looping/non-looping flags
|
|
DEFINE_FIELD( activity, FIELD_INTEGER ), // initialized at loadtime to game DLL values
|
|
DEFINE_FIELD( actweight, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numevents, FIELD_INTEGER ),
|
|
DEFINE_INDEX( eventindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( bbmin, FIELD_VECTOR ),
|
|
DEFINE_FIELD( bbmax, FIELD_VECTOR ),
|
|
DEFINE_FIELD( numblends, FIELD_INTEGER ),
|
|
DEFINE_INDEX( animindexindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( movementindex, FIELD_INTEGER ), // [blend] float array for blended movement
|
|
DEFINE_ARRAY( groupsize, FIELD_INTEGER, 2 ),
|
|
DEFINE_ARRAY( paramindex, FIELD_INTEGER, 2 ), // X, Y, Z, XR, YR, ZR
|
|
DEFINE_ARRAY( paramstart, FIELD_FLOAT, 2 ), // local (0..1) starting value
|
|
DEFINE_ARRAY( paramend, FIELD_FLOAT, 2 ), // local (0..1) ending value
|
|
DEFINE_FIELD( paramparent, FIELD_INTEGER ),
|
|
DEFINE_FIELD( fadeintime, FIELD_FLOAT ), // ideal cross fate in time (0.2 default)
|
|
DEFINE_FIELD( fadeouttime, FIELD_FLOAT ), // ideal cross fade out time (0.2 default)
|
|
DEFINE_FIELD( localentrynode, FIELD_INTEGER ), // transition node at entry
|
|
DEFINE_FIELD( localexitnode, FIELD_INTEGER ), // transition node at exit
|
|
DEFINE_FIELD( nodeflags, FIELD_INTEGER ), // transition rules
|
|
DEFINE_FIELD( entryphase, FIELD_FLOAT ), // used to match entry gait
|
|
DEFINE_FIELD( exitphase, FIELD_FLOAT ), // used to match exit gait
|
|
DEFINE_FIELD( lastframe, FIELD_FLOAT ), // frame that should generation EndOfSequence
|
|
DEFINE_FIELD( nextseq, FIELD_INTEGER ), // auto advancing sequences
|
|
DEFINE_FIELD( pose, FIELD_INTEGER ), // index of delta animation between end and nextseq
|
|
DEFINE_FIELD( numikrules, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numautolayers, FIELD_INTEGER ),
|
|
DEFINE_INDEX( autolayerindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( weightlistindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( posekeyindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numiklocks, FIELD_INTEGER ),
|
|
DEFINE_INDEX( iklockindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( keyvalueindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( keyvaluesize, FIELD_INTEGER ),
|
|
DEFINE_INDEX( cycleposeindex, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( unused, FIELD_INTEGER, 7 ), // remove/add as appropriate (grow back to 8 ints on version change!)
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioevent_t )
|
|
DEFINE_FIELD( cycle, FIELD_FLOAT ),
|
|
DEFINE_FIELD( event, FIELD_INTEGER ),
|
|
DEFINE_FIELD( type, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( options, FIELD_CHARACTER, 64 ),
|
|
DEFINE_INDEX( szeventindex, FIELD_INTEGER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioautolayer_t )
|
|
DEFINE_FIELD( iSequence, FIELD_SHORT ),
|
|
DEFINE_FIELD( iPose, FIELD_SHORT ),
|
|
DEFINE_FIELD( flags, FIELD_INTEGER ),
|
|
DEFINE_FIELD( start, FIELD_FLOAT ),
|
|
DEFINE_FIELD( peak, FIELD_FLOAT ),
|
|
DEFINE_FIELD( tail, FIELD_FLOAT ),
|
|
DEFINE_FIELD( end, FIELD_FLOAT ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioiklock_t )
|
|
DEFINE_FIELD( chain, FIELD_INTEGER ),
|
|
DEFINE_FIELD( flPosWeight, FIELD_FLOAT ),
|
|
DEFINE_FIELD( flLocalQWeight, FIELD_FLOAT ),
|
|
DEFINE_FIELD( flags, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( unused, FIELD_INTEGER, 4 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudiobodyparts_t )
|
|
DEFINE_INDEX( sznameindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( nummodels, FIELD_INTEGER ),
|
|
DEFINE_FIELD( base, FIELD_INTEGER ),
|
|
DEFINE_INDEX( modelindex, FIELD_INTEGER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudiomodel_t )
|
|
DEFINE_ARRAY( name, FIELD_CHARACTER, 64 ),
|
|
DEFINE_FIELD( type, FIELD_INTEGER ),
|
|
DEFINE_FIELD( boundingradius, FIELD_FLOAT ),
|
|
DEFINE_FIELD( nummeshes, FIELD_INTEGER ),
|
|
DEFINE_INDEX( meshindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numvertices, FIELD_INTEGER ),
|
|
DEFINE_INDEX( vertexindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( tangentsindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numattachments, FIELD_INTEGER ),
|
|
DEFINE_INDEX( attachmentindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numeyeballs, FIELD_INTEGER ),
|
|
DEFINE_INDEX( eyeballindex, FIELD_INTEGER ),
|
|
DEFINE_EMBEDDED( vertexdata ),
|
|
DEFINE_ARRAY( unused, FIELD_INTEGER, 8 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudio_modelvertexdata_t )
|
|
DEFINE_FIELD( pVertexData, FIELD_INTEGER ), // void*
|
|
DEFINE_FIELD( pTangentData, FIELD_INTEGER ), // void*
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioflexdesc_t )
|
|
DEFINE_INDEX( szFACSindex, FIELD_INTEGER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioflexcontroller_t )
|
|
DEFINE_INDEX( sztypeindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( sznameindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( localToGlobal, FIELD_INTEGER ),
|
|
DEFINE_FIELD( min, FIELD_FLOAT ),
|
|
DEFINE_FIELD( max, FIELD_FLOAT ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioflexcontrollerui_t )
|
|
DEFINE_INDEX( sznameindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( szindex0, FIELD_INTEGER ),
|
|
DEFINE_INDEX( szindex1, FIELD_INTEGER ),
|
|
DEFINE_INDEX( szindex2, FIELD_INTEGER ),
|
|
DEFINE_FIELD( remaptype, FIELD_CHARACTER ),
|
|
DEFINE_FIELD( stereo, FIELD_BOOLEAN ),
|
|
DEFINE_ARRAY( unused, FIELD_CHARACTER, 2 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioflexrule_t )
|
|
DEFINE_FIELD( flex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numops, FIELD_INTEGER ),
|
|
DEFINE_INDEX( opindex, FIELD_INTEGER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioflexop_t )
|
|
DEFINE_FIELD( op, FIELD_INTEGER ),
|
|
DEFINE_FIELD( d, FIELD_INTEGER ), // int/float union
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioikchain_t )
|
|
DEFINE_INDEX( sznameindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( linktype, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numlinks, FIELD_INTEGER ),
|
|
DEFINE_INDEX( linkindex, FIELD_INTEGER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioiklink_t )
|
|
DEFINE_FIELD( bone, FIELD_INTEGER ),
|
|
DEFINE_FIELD( kneeDir, FIELD_VECTOR ),
|
|
DEFINE_FIELD( unused0, FIELD_VECTOR ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudiomouth_t )
|
|
DEFINE_FIELD( bone, FIELD_INTEGER ),
|
|
DEFINE_FIELD( forward, FIELD_VECTOR ),
|
|
DEFINE_FIELD( flexdesc, FIELD_INTEGER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioposeparamdesc_t )
|
|
DEFINE_INDEX( sznameindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( flags, FIELD_INTEGER ),
|
|
DEFINE_FIELD( start, FIELD_FLOAT ),
|
|
DEFINE_FIELD( end, FIELD_FLOAT ),
|
|
DEFINE_FIELD( loop, FIELD_FLOAT ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudiomesh_t )
|
|
DEFINE_FIELD( material, FIELD_INTEGER ),
|
|
DEFINE_INDEX( modelindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numvertices, FIELD_INTEGER ),
|
|
DEFINE_FIELD( vertexoffset, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numflexes, FIELD_INTEGER ),
|
|
DEFINE_INDEX( flexindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( materialtype, FIELD_INTEGER ),
|
|
DEFINE_FIELD( materialparam, FIELD_INTEGER ),
|
|
DEFINE_FIELD( meshid, FIELD_INTEGER ),
|
|
DEFINE_FIELD( center, FIELD_VECTOR ),
|
|
DEFINE_EMBEDDED( vertexdata ),
|
|
DEFINE_ARRAY( unused, FIELD_INTEGER, 8 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudio_meshvertexdata_t )
|
|
DEFINE_FIELD( modelvertexdata, FIELD_INTEGER ), // mstudio_modelvertexdata_t*
|
|
DEFINE_ARRAY( numLODVertexes, FIELD_INTEGER, MAX_NUM_LODS ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioeyeball_t )
|
|
DEFINE_INDEX( sznameindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( bone, FIELD_INTEGER ),
|
|
DEFINE_FIELD( org, FIELD_VECTOR ),
|
|
DEFINE_FIELD( zoffset, FIELD_FLOAT ),
|
|
DEFINE_FIELD( radius, FIELD_FLOAT ),
|
|
DEFINE_FIELD( up, FIELD_VECTOR ),
|
|
DEFINE_FIELD( forward, FIELD_VECTOR ),
|
|
DEFINE_FIELD( texture, FIELD_INTEGER ),
|
|
DEFINE_FIELD( unused1, FIELD_INTEGER ),
|
|
DEFINE_FIELD( iris_scale, FIELD_FLOAT ),
|
|
DEFINE_FIELD( unused2, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( upperflexdesc, FIELD_INTEGER, 3 ),
|
|
DEFINE_ARRAY( lowerflexdesc, FIELD_INTEGER, 3 ),
|
|
DEFINE_ARRAY( uppertarget, FIELD_FLOAT, 3 ),
|
|
DEFINE_ARRAY( lowertarget, FIELD_FLOAT, 3 ),
|
|
DEFINE_FIELD( upperlidflexdesc, FIELD_INTEGER ),
|
|
DEFINE_FIELD( lowerlidflexdesc, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( unused, FIELD_INTEGER, 4 ),
|
|
DEFINE_FIELD( m_bNonFACS, FIELD_BOOLEAN ),
|
|
DEFINE_ARRAY( unused3, FIELD_CHARACTER, 3 ),
|
|
DEFINE_ARRAY( unused4, FIELD_INTEGER, 7 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioflex_t )
|
|
DEFINE_FIELD( flexdesc, FIELD_INTEGER ),
|
|
DEFINE_FIELD( target0, FIELD_FLOAT ),
|
|
DEFINE_FIELD( target1, FIELD_FLOAT ),
|
|
DEFINE_FIELD( target2, FIELD_FLOAT ),
|
|
DEFINE_FIELD( target3, FIELD_FLOAT ),
|
|
DEFINE_FIELD( numverts, FIELD_INTEGER ),
|
|
DEFINE_INDEX( vertindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( flexpair, FIELD_INTEGER ),
|
|
DEFINE_FIELD( vertanimtype, FIELD_CHARACTER ),
|
|
DEFINE_ARRAY( unusedchar, FIELD_CHARACTER, 3 ),
|
|
DEFINE_ARRAY( unused, FIELD_INTEGER, 6 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudiovertanim_t )
|
|
DEFINE_FIELD( index, FIELD_SHORT ),
|
|
DEFINE_FIELD( speed, FIELD_CHARACTER ),
|
|
DEFINE_FIELD( side, FIELD_CHARACTER ),
|
|
DEFINE_ARRAY( delta, FIELD_SHORT, 3 ), // short[3]/float16[3]union
|
|
DEFINE_ARRAY( ndelta, FIELD_SHORT, 3 ), // short[3]/float16[3] union
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudiomodelgroup_t )
|
|
DEFINE_INDEX( szlabelindex, FIELD_INTEGER ),
|
|
DEFINE_INDEX( sznameindex, FIELD_INTEGER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioanimblock_t )
|
|
DEFINE_INDEX( datastart, FIELD_INTEGER ),
|
|
DEFINE_INDEX( dataend, FIELD_INTEGER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudiotexture_t )
|
|
DEFINE_INDEX( sznameindex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( flags, FIELD_INTEGER ),
|
|
DEFINE_FIELD( used, FIELD_INTEGER ),
|
|
DEFINE_FIELD( unused1, FIELD_INTEGER ),
|
|
DEFINE_FIELD( material, FIELD_INTEGER ), // IMaterial*
|
|
DEFINE_FIELD( clientmaterial, FIELD_INTEGER ), // void*
|
|
DEFINE_ARRAY( unused, FIELD_INTEGER, 10 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( vertexFileHeader_t )
|
|
DEFINE_FIELD( id, FIELD_INTEGER ),
|
|
DEFINE_FIELD( version, FIELD_INTEGER ),
|
|
DEFINE_FIELD( checksum, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numLODs, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( numLODVertexes, FIELD_INTEGER, MAX_NUM_LODS ),
|
|
DEFINE_FIELD( numFixups, FIELD_INTEGER ),
|
|
DEFINE_FIELD( fixupTableStart, FIELD_INTEGER ),
|
|
DEFINE_FIELD( vertexDataStart, FIELD_INTEGER ),
|
|
DEFINE_FIELD( tangentDataStart, FIELD_INTEGER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( vertexFileFixup_t )
|
|
DEFINE_FIELD( lod, FIELD_INTEGER ),
|
|
DEFINE_FIELD( sourceVertexID, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numVertexes, FIELD_INTEGER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudioboneweight_t )
|
|
DEFINE_ARRAY( weight, FIELD_FLOAT, MAX_NUM_BONES_PER_VERT ),
|
|
DEFINE_ARRAY( bone, FIELD_CHARACTER, MAX_NUM_BONES_PER_VERT ),
|
|
DEFINE_FIELD( numbones, FIELD_CHARACTER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( mstudiovertex_t )
|
|
DEFINE_EMBEDDED( m_BoneWeights ),
|
|
DEFINE_FIELD( m_vecPosition, FIELD_VECTOR ),
|
|
DEFINE_FIELD( m_vecNormal, FIELD_VECTOR ),
|
|
DEFINE_ARRAY( m_vecTexCoord, FIELD_FLOAT, 2 ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
// Data descriptions from OptimizedModel.h
|
|
namespace OptimizedModel
|
|
{
|
|
|
|
BEGIN_BYTESWAP_DATADESC( BoneStateChangeHeader_t )
|
|
DEFINE_FIELD( hardwareID, FIELD_INTEGER ),
|
|
DEFINE_FIELD( newBoneID, FIELD_INTEGER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( Vertex_t )
|
|
DEFINE_ARRAY( boneWeightIndex, FIELD_CHARACTER, MAX_NUM_BONES_PER_VERT ),
|
|
DEFINE_FIELD( numBones, FIELD_CHARACTER ),
|
|
DEFINE_FIELD( origMeshVertID, FIELD_SHORT ),
|
|
DEFINE_ARRAY( boneID, FIELD_CHARACTER, MAX_NUM_BONES_PER_VERT ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( StripHeader_t )
|
|
DEFINE_FIELD( numIndices, FIELD_INTEGER ),
|
|
DEFINE_FIELD( indexOffset, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numVerts, FIELD_INTEGER ),
|
|
DEFINE_FIELD( vertOffset, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numBones, FIELD_SHORT ),
|
|
DEFINE_FIELD( flags, FIELD_CHARACTER ),
|
|
DEFINE_FIELD( numBoneStateChanges, FIELD_INTEGER ),
|
|
DEFINE_FIELD( boneStateChangeOffset, FIELD_INTEGER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( StripGroupHeader_t )
|
|
DEFINE_FIELD( numVerts, FIELD_INTEGER ),
|
|
DEFINE_FIELD( vertOffset, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numIndices, FIELD_INTEGER ),
|
|
DEFINE_FIELD( indexOffset, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numStrips, FIELD_INTEGER ),
|
|
DEFINE_FIELD( stripOffset, FIELD_INTEGER ),
|
|
DEFINE_FIELD( flags, FIELD_CHARACTER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( MeshHeader_t )
|
|
DEFINE_FIELD( numStripGroups, FIELD_INTEGER ),
|
|
DEFINE_FIELD( stripGroupHeaderOffset, FIELD_INTEGER ),
|
|
DEFINE_FIELD( flags, FIELD_CHARACTER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( ModelLODHeader_t )
|
|
DEFINE_FIELD( numMeshes, FIELD_INTEGER ),
|
|
DEFINE_FIELD( meshOffset, FIELD_INTEGER ),
|
|
DEFINE_FIELD( switchPoint, FIELD_FLOAT ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( ModelHeader_t )
|
|
DEFINE_FIELD( numLODs, FIELD_INTEGER ),
|
|
DEFINE_FIELD( lodOffset, FIELD_INTEGER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( BodyPartHeader_t )
|
|
DEFINE_FIELD( numModels, FIELD_INTEGER ),
|
|
DEFINE_FIELD( modelOffset, FIELD_INTEGER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( MaterialReplacementHeader_t )
|
|
DEFINE_FIELD( materialID, FIELD_SHORT ),
|
|
DEFINE_FIELD( replacementMaterialNameOffset, FIELD_INTEGER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( MaterialReplacementListHeader_t )
|
|
DEFINE_FIELD( numReplacements, FIELD_INTEGER ),
|
|
DEFINE_FIELD( replacementOffset, FIELD_INTEGER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
BEGIN_BYTESWAP_DATADESC( FileHeader_t )
|
|
DEFINE_FIELD( version, FIELD_INTEGER ),
|
|
DEFINE_FIELD( vertCacheSize, FIELD_INTEGER ),
|
|
DEFINE_FIELD( maxBonesPerStrip, FIELD_SHORT ),
|
|
DEFINE_FIELD( maxBonesPerTri, FIELD_SHORT ),
|
|
DEFINE_FIELD( maxBonesPerVert, FIELD_INTEGER ),
|
|
DEFINE_FIELD( checkSum, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numLODs, FIELD_INTEGER ),
|
|
DEFINE_FIELD( materialReplacementListOffset, FIELD_INTEGER ),
|
|
DEFINE_FIELD( numBodyParts, FIELD_INTEGER ),
|
|
DEFINE_FIELD( bodyPartOffset, FIELD_INTEGER ),
|
|
END_BYTESWAP_DATADESC()
|
|
|
|
} // namespace OptimizedModel
|
|
|
|
// Data descriptions from phyfile.h
|
|
BEGIN_BYTESWAP_DATADESC( phyheader_t )
|
|
DEFINE_FIELD( size, FIELD_INTEGER ),
|
|
DEFINE_FIELD( id, FIELD_INTEGER ),
|
|
DEFINE_FIELD( solidCount, FIELD_INTEGER ),
|
|
DEFINE_FIELD( checkSum, FIELD_INTEGER ),
|
|
END_BYTESWAP_DATADESC()
|