//========== 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 ); }