csgo-2018-source/dmxloader/utlsoacontainer_serialization.cpp
2021-07-24 21:11:47 -07:00

204 lines
7.1 KiB
C++

//========== Copyright (c) Valve Corporation, All rights reserved. ==========//
//
// Purpose: see utlsoacontainer_serialization.h
//
//===========================================================================//
#include "tier0/platform.h"
#include "tier1/utlsoacontainer.h"
#include "dmxloader/dmxloader.h"
#include "dmxloader/dmxelement.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// Simple wrapper class to provide access to the CSOAContainer innards
class CSOAContainer_Serializable : public CSOAContainer
{
DECLARE_DMXELEMENT_UNPACK();
public:
bool Serialize( CDmxElement *pRootElement );
bool Unserialize( const CDmxElement *pRootElement );
private:
bool ContainsValidAttributes( void );
enum SoaContainerDmxVersion_t { SOA_CONTAINER_DMX_VERSION = 1 };
};
BEGIN_DMXELEMENT_UNPACK( CSOAContainer_Serializable )
// NOTE: All other member variables are recomputed from the below values, after unpack, by 'AllocateData' (the stored data is copyied in after that)
DMXELEMENT_UNPACK_FIELD( "num_columns", "0", int, m_nColumns )
DMXELEMENT_UNPACK_FIELD( "num_rows", "0", int, m_nRows )
DMXELEMENT_UNPACK_FIELD( "num_slices", "0", int, m_nSlices )
DMXELEMENT_UNPACK_FIELD_ARRAY( "attribute_types", "-1", int, m_nDataType )
DMXELEMENT_UNPACK_FIELD( "field_present_mask", "0", int, m_nFieldPresentMask )
DMXELEMENT_UNPACK_FIELD( "thread_mode", "-1", int, m_eThreadMode )
END_DMXELEMENT_UNPACK( CSOAContainer_Serializable, s_pSOAContainerUnpack )
bool CSOAContainer_Serializable::Serialize( CDmxElement *pRootElement )
{
CDmxElementModifyScope modifyRoot( pRootElement );
COMPILE_TIME_ASSERT( ATTRDATATYPE_NONE == -1 ); // If this changes, modify the line for m_nDataType in the BEGIN_DMXELEMENT_UNPACK block above
COMPILE_TIME_ASSERT( SOATHREADMODE_AUTO == -1 ); // If this changes, modify the line for m_eThreadMode in the BEGIN_DMXELEMENT_UNPACK block above
if ( !ContainsValidAttributes() || ( !m_pDataMemory && !m_pConstantDataMemory ) )
{
Warning( "ERROR: CSOAContainer_Serializable::Unserialize - no data to serialize!\n" );
return false;
}
// Write the version number first
const int nDmxVersion = SOA_CONTAINER_DMX_VERSION;
pRootElement->SetValue( "version", nDmxVersion );
// Write some member variables (enough to recompute the rest)
pRootElement->AddAttributesFromStructure( this, s_pSOAContainerUnpack );
// Now write out the data, as floats (NOTE: we have to at least init the attribute as a zero-element vector or it won't serialize!)
CDmxAttribute *pDataMemoryAttribute = pRootElement->AddAttribute( "memory_data" );
CUtlVector< float >& dataVector = pDataMemoryAttribute->GetArrayForEdit< float >();
size_t nDataMemorySize = DataMemorySize();
dataVector.SetCount( nDataMemorySize / sizeof( float ) );
// NOTE: Constant data is always zero for now, but we write it out in case that changes (non-zero constant values seem potentially useful)
CDmxAttribute *pConstantMemoryAttribute = pRootElement->AddAttribute( "constant_data" );
CUtlVector< float >& constantVector = pConstantMemoryAttribute->GetArrayForEdit< float >();
size_t nConstantMemorySize = ConstantMemorySize();
constantVector.SetCount( nConstantMemorySize / sizeof( float ) );
// To account for 'separate' memory allocations, we need to copy each attribute one at a time
byte *pBaseDataPtr = (byte *)dataVector.Base();
byte *pBaseConstantPtr = (byte *)constantVector.Base();
for( int i = 0; i < MAX_SOA_FIELDS; i++ )
{
if ( m_nDataType[i] == ATTRDATATYPE_NONE )
continue;
if ( m_nFieldPresentMask & ( 1 << i ) )
{
memcpy( pBaseDataPtr, m_pAttributePtrs[ i ], AttributeMemorySize( i ) );
pBaseDataPtr += AttributeMemorySize( i );
}
else
{
memcpy( pBaseConstantPtr, m_pAttributePtrs[ i ], AttributeMemorySize( i ) );
pBaseConstantPtr += AttributeMemorySize( i );
}
}
return true;
}
bool CSOAContainer_Serializable::Unserialize( const CDmxElement *pRootElement )
{
// Read the version number
int nVersion = pRootElement->GetValue( "version", -1 );
if ( nVersion == -1 )
{
Warning( "ERROR: CSOAContainer_Serializable::Unserialize - missing version field!\n" );
return false;
}
// Clear, then unpack the stored members
Purge();
pRootElement->UnpackIntoStructure( this, s_pSOAContainerUnpack );
// Check that we have enough data to create a valid container!
int nError = 0;
const CDmxAttribute *pDataMemoryAttribute = pRootElement->GetAttribute( "memory_data" );
const CDmxAttribute *pConstantMemoryAttribute = pRootElement->GetAttribute( "constant_data" );
if ( !pDataMemoryAttribute || !pConstantMemoryAttribute )
nError = 1;
if ( !ContainsValidAttributes() )
nError = 1;
if ( !nError )
{
// Update files saved in old versions
switch( nVersion )
{
case SOA_CONTAINER_DMX_VERSION:
break; // Up to date - nothing to do.
default:
// The DMX unpack structure will set reasonable defaults or flag stuff that needs fixing up
nError = 1; // TODO: add code when versions are bumped and fixup needs to happen
break;
}
}
if ( !nError )
{
SOAThreadMode_t eSavedThreadMode = m_eThreadMode;
// Allocate memory (fills in all the pointers and strides)
AllocateData( NumCols(), NumRows(), NumSlices() );
// Set thread mode from the unserialized value (AllocateData stomps on it)
SetThreadMode( eSavedThreadMode );
// Now copy in the data
if ( m_pDataMemory )
{
const CUtlVector< float >& floatVector = pDataMemoryAttribute->GetArray< float >();
size_t nDataMemorySize = DataMemorySize();
int nFloats = nDataMemorySize / sizeof( float );
if ( nFloats == floatVector.Count() )
memcpy( m_pDataMemory, floatVector.Base(), nDataMemorySize );
else
nError = 2;
}
if ( m_pConstantDataMemory )
{
const CUtlVector< float >& floatVector = pConstantMemoryAttribute->GetArray< float >();
size_t nConstantMemorySize = ConstantMemorySize();
int nFloats = nConstantMemorySize / sizeof( float );
if ( nFloats == floatVector.Count() )
memcpy( m_pConstantDataMemory, floatVector.Base(), nConstantMemorySize );
else
nError = 3;
}
}
if ( nError )
{
switch( nError )
{
case 1: Warning( "ERROR: CSOAContainer_Serializable::Unserialize - DMX data does not represent a valid container!\n" ); break;
case 2: Warning( "ERROR: CSOAContainer_Serializable::Unserialize - found wrong amount of memory data!\n" ); break;
case 3: Warning( "ERROR: CSOAContainer_Serializable::Unserialize - found wrong amount of constant data!\n" ); break;
}
Assert( 0 );
Purge();
return false;
}
return true;
}
bool CSOAContainer_Serializable::ContainsValidAttributes( void )
{
if ( ( NumCols() <= 0 ) || ( NumRows() <= 0 ) || ( NumSlices() <= 0 ) )
return false;
for ( int i = 0; i < MAX_SOA_FIELDS; i++ )
{
if ( m_nDataType[ i ] != ATTRDATATYPE_NONE )
return true;
}
return false;
}
bool SerializeCSOAContainer( const CSOAContainer *pContainer, CDmxElement *pRootElement )
{
return ((CSOAContainer_Serializable*)pContainer)->Serialize( pRootElement );
}
bool UnserializeCSOAContainer( const CSOAContainer *pContainer, const CDmxElement *pRootElement )
{
return ((CSOAContainer_Serializable*)pContainer)->Unserialize( pRootElement );
}