diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /dmserializers | |
| download | archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip | |
Diffstat (limited to 'dmserializers')
| -rw-r--r-- | dmserializers/dmebaseimporter.cpp | 42 | ||||
| -rw-r--r-- | dmserializers/dmebaseimporter.h | 43 | ||||
| -rw-r--r-- | dmserializers/dmserializers.cpp | 163 | ||||
| -rw-r--r-- | dmserializers/dmserializers.h | 55 | ||||
| -rw-r--r-- | dmserializers/dmserializers.vpc | 46 | ||||
| -rw-r--r-- | dmserializers/importactbusy.cpp | 182 | ||||
| -rw-r--r-- | dmserializers/importkeyvaluebase.cpp | 292 | ||||
| -rw-r--r-- | dmserializers/importkeyvaluebase.h | 84 | ||||
| -rw-r--r-- | dmserializers/importsfmv1.cpp | 219 | ||||
| -rw-r--r-- | dmserializers/importsfmv2.cpp | 294 | ||||
| -rw-r--r-- | dmserializers/importsfmv3.cpp | 227 | ||||
| -rw-r--r-- | dmserializers/importsfmv4.cpp | 123 | ||||
| -rw-r--r-- | dmserializers/importsfmv5.cpp | 120 | ||||
| -rw-r--r-- | dmserializers/importsfmv6.cpp | 140 | ||||
| -rw-r--r-- | dmserializers/importsfmv7.cpp | 144 | ||||
| -rw-r--r-- | dmserializers/importsfmv8.cpp | 139 | ||||
| -rw-r--r-- | dmserializers/importsfmv9.cpp | 142 | ||||
| -rw-r--r-- | dmserializers/importvmf.cpp | 629 | ||||
| -rw-r--r-- | dmserializers/importvmt.cpp | 738 |
19 files changed, 3822 insertions, 0 deletions
diff --git a/dmserializers/dmebaseimporter.cpp b/dmserializers/dmebaseimporter.cpp new file mode 100644 index 0000000..7fc10bc --- /dev/null +++ b/dmserializers/dmebaseimporter.cpp @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= +#include "dmserializers.h" +#include "dmebaseimporter.h" + +CDmeBaseImporter::CDmeBaseImporter( char const *formatName, char const *nextFormatName ) : + m_pFormatName( formatName ), + m_pNextSerializer( nextFormatName ) +{ +} + +bool CDmeBaseImporter::IsLatestVersion() const +{ + return g_pDataModel->FindLegacyUpdater( m_pNextSerializer ) == NULL; +} + +// Updates ppRoot to first non-legacy generic dmx format, returns false if the conversion fails +bool CDmeBaseImporter::Update( CDmElement **ppRoot ) +{ + if ( !DoFixup( *ppRoot ) ) + return false; + + if ( !m_pNextSerializer ) + return true; + + // Chain + IDmLegacyUpdater *pUpdater = g_pDataModel->FindLegacyUpdater( m_pNextSerializer ); + if ( !pUpdater ) + return true; + + return pUpdater->Update( ppRoot ); +} + + + +CSFMBaseImporter::CSFMBaseImporter( char const *formatName, char const *nextFormatName ) : + BaseClass( formatName, nextFormatName ) +{ +} diff --git a/dmserializers/dmebaseimporter.h b/dmserializers/dmebaseimporter.h new file mode 100644 index 0000000..1a74d77 --- /dev/null +++ b/dmserializers/dmebaseimporter.h @@ -0,0 +1,43 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef DMEBASEIMPORTER_H +#define DMEBASEIMPORTER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "datamodel/idatamodel.h" + +class CDmeBaseImporter : public IDmLegacyUpdater +{ + typedef IDmLegacyUpdater BaseClass; + +public: + CDmeBaseImporter( char const *formatName, char const *nextFormatName ); + + virtual const char *GetName() const { return m_pFormatName; } + virtual bool IsLatestVersion() const; + + virtual bool Update( CDmElement **ppRoot ); + +private: + virtual bool DoFixup( CDmElement *pRoot ) = 0; + +protected: + char const *m_pFormatName; + char const *m_pNextSerializer; +}; + +class CSFMBaseImporter : public CDmeBaseImporter +{ + typedef CDmeBaseImporter BaseClass; + +public: + CSFMBaseImporter( char const *formatName, char const *nextFormatName ); +}; + +#endif // DMEBASEIMPORTER_H diff --git a/dmserializers/dmserializers.cpp b/dmserializers/dmserializers.cpp new file mode 100644 index 0000000..860bcf9 --- /dev/null +++ b/dmserializers/dmserializers.cpp @@ -0,0 +1,163 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// Converts from any one DMX file format to another +// +//============================================================================= + +#include "dmserializers.h" +#include "dmserializers/idmserializers.h" +#include "appframework/iappsystem.h" +#include "filesystem.h" +#include "datamodel/idatamodel.h" +#include "datamodel/dmelementfactoryhelper.h" +#include "tier2/tier2.h" + + +//----------------------------------------------------------------------------- +// format updater macros +//----------------------------------------------------------------------------- + +#define DECLARE_FORMAT_UPDATER( _name, _description, _extension, _version, _encoding ) \ + class CDmFormatUpdater_ ## _name : public IDmFormatUpdater \ + { \ + public: \ + CDmFormatUpdater_ ## _name() {} \ + virtual const char *GetName() const { return #_name; } \ + virtual const char *GetDescription() const { return _description; } \ + virtual const char *GetExtension() const { return _extension; } \ + virtual const char *GetDefaultEncoding() const { return _encoding; } \ + virtual int GetCurrentVersion() const { return _version; } \ + virtual bool Update( CDmElement **pRoot, int nSourceVersion ) { return true; } \ + }; \ + static CDmFormatUpdater_ ## _name s_FormatUpdater ## _name; \ + void InstallFormatUpdater_ ## _name( IDataModel *pFactory ) \ + { \ + pFactory->AddFormatUpdater( &s_FormatUpdater ## _name ); \ + } + +#define INSTALL_FORMAT_UPDATER( _name ) InstallFormatUpdater_ ## _name( g_pDataModel ) + + +//----------------------------------------------------------------------------- +// format updaters +//----------------------------------------------------------------------------- + +DECLARE_FORMAT_UPDATER( dmx, "Generic DMX", "dmx", 1, "binary" ) +DECLARE_FORMAT_UPDATER( movieobjects, "Generic MovieObjects", "dmx", 1, "binary" ) +DECLARE_FORMAT_UPDATER( sfm, "Generic SFM", "dmx", 1, "binary" ) +DECLARE_FORMAT_UPDATER( sfm_session, "SFM Session", "dmx", 1, "binary" ) +DECLARE_FORMAT_UPDATER( sfm_trackgroup, "SFM TrackGroup", "dmx", 1, "binary" ) +DECLARE_FORMAT_UPDATER( pcf, "Particle Configuration File", "dmx", 1, "binary" ) +DECLARE_FORMAT_UPDATER( preset, "Preset File", "dmx", 1, "keyvalues2" ) +DECLARE_FORMAT_UPDATER( facial_animation, "Facial Animation File", "dmx", 1, "binary" ) +DECLARE_FORMAT_UPDATER( model, "DMX Model", "dmx", 1, "binary" ) +//DECLARE_FORMAT_UPDATER( animation, "DMX Animation", "dmx", 1, "binary" ) +//DECLARE_FORMAT_UPDATER( dcc_makefile, "DMX Makefile", "dmx", 1, "keyvalues2" ) + + +//----------------------------------------------------------------------------- +// The application object +//----------------------------------------------------------------------------- +class CDmSerializers : public CBaseAppSystem< IDmSerializers > +{ + typedef CBaseAppSystem< IDmSerializers > BaseClass; + +public: + // Inherited from IAppSystem + virtual bool Connect( CreateInterfaceFn factory ); + virtual void *QueryInterface( const char *pInterfaceName ); + virtual InitReturnVal_t Init(); +}; + + +//----------------------------------------------------------------------------- +// Singleton interface +//----------------------------------------------------------------------------- +static CDmSerializers g_DmSerializers; +IDmSerializers *g_pDmSerializers = &g_DmSerializers; + + +//----------------------------------------------------------------------------- +// Here's where the app systems get to learn about each other +//----------------------------------------------------------------------------- +bool CDmSerializers::Connect( CreateInterfaceFn factory ) +{ + if ( !BaseClass::Connect( factory ) ) + return false; + + if ( !factory( FILESYSTEM_INTERFACE_VERSION, NULL ) ) + { + Warning( "DmSerializers needs the file system to function" ); + return false; + } + + // Here's the main point where all DM element classes get installed + // Necessary to do it here so all type symbols for all DME classes are set + // up prior to install + InstallDmElementFactories( ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Here's where systems can access other interfaces implemented by this object +//----------------------------------------------------------------------------- +void *CDmSerializers::QueryInterface( const char *pInterfaceName ) +{ + if ( !V_strcmp( pInterfaceName, DMSERIALIZERS_INTERFACE_VERSION ) ) + return (IDmSerializers*)this; + + return NULL; +} + + +//----------------------------------------------------------------------------- +// Init, shutdown +//----------------------------------------------------------------------------- +InitReturnVal_t CDmSerializers::Init() +{ + InitReturnVal_t nRetVal = BaseClass::Init(); + if ( nRetVal != INIT_OK ) + return nRetVal; + + // Install non-dmx importers + InstallActBusyImporter( g_pDataModel ); + InstallVMTImporter( g_pDataModel ); + InstallVMFImporter( g_pDataModel ); + + // Install legacy dmx importers + InstallSFMV1Importer( g_pDataModel ); + InstallSFMV2Importer( g_pDataModel ); + InstallSFMV3Importer( g_pDataModel ); + InstallSFMV4Importer( g_pDataModel ); + InstallSFMV5Importer( g_pDataModel ); + InstallSFMV6Importer( g_pDataModel ); + InstallSFMV7Importer( g_pDataModel ); + InstallSFMV8Importer( g_pDataModel ); + InstallSFMV9Importer( g_pDataModel ); + + // install dmx format updaters + INSTALL_FORMAT_UPDATER( dmx ); + INSTALL_FORMAT_UPDATER( movieobjects ); + INSTALL_FORMAT_UPDATER( sfm ); + INSTALL_FORMAT_UPDATER( sfm_session ); + INSTALL_FORMAT_UPDATER( sfm_trackgroup ); + INSTALL_FORMAT_UPDATER( pcf ); + INSTALL_FORMAT_UPDATER( preset ); + INSTALL_FORMAT_UPDATER( facial_animation ); + INSTALL_FORMAT_UPDATER( model ); +// INSTALL_FORMAT_UPDATER( animation ); +// INSTALL_FORMAT_UPDATER( dcc_makefile ); + + return INIT_OK; +} + diff --git a/dmserializers/dmserializers.h b/dmserializers/dmserializers.h new file mode 100644 index 0000000..24e07a2 --- /dev/null +++ b/dmserializers/dmserializers.h @@ -0,0 +1,55 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// Main header file for the serializers DLL +// +//============================================================================= + +#ifndef DMSERIALIZERS_H +#define DMSERIALIZERS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "datamodel/dmelement.h" +#include "datamodel/dmattribute.h" +#include "datamodel/dmattributevar.h" + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class IDataModel; + + +//----------------------------------------------------------------------------- +// Externally defined importers +//----------------------------------------------------------------------------- +void InstallActBusyImporter( IDataModel *pFactory ); +void InstallVMTImporter( IDataModel *pFactory ); +void InstallSFMV1Importer( IDataModel *pFactory ); +void InstallSFMV2Importer( IDataModel *pFactory ); +void InstallSFMV3Importer( IDataModel *pFactory ); +void InstallSFMV4Importer( IDataModel *pFactory ); +void InstallSFMV5Importer( IDataModel *pFactory ); +void InstallSFMV6Importer( IDataModel *pFactory ); +void InstallSFMV7Importer( IDataModel *pFactory ); +void InstallSFMV8Importer( IDataModel *pFactory ); +void InstallSFMV9Importer( IDataModel *pFactory ); +void InstallVMFImporter( IDataModel *pFactory ); + +void InstallDMXUpdater( IDataModel *pFactory ); +void InstallSFMSessionUpdater( IDataModel *pFactory ); +void InstallPCFUpdater( IDataModel *pFactory ); + + +#endif // DMSERIALIZERS_H + + diff --git a/dmserializers/dmserializers.vpc b/dmserializers/dmserializers.vpc new file mode 100644 index 0000000..6e7226d --- /dev/null +++ b/dmserializers/dmserializers.vpc @@ -0,0 +1,46 @@ +//----------------------------------------------------------------------------- +// DMSERIALIZERS.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR ".." +$include "$SRCDIR\vpc_scripts\source_lib_base.vpc" + +$Configuration +{ + $Compiler + { + $PreprocessorDefinitions "$BASE;DMSERIALIZERS_LIB" + } +} + +$Project "Dmserializers" +{ + $Folder "Source Files" + { + $File "dmebaseimporter.cpp" + $File "dmserializers.cpp" + $File "importactbusy.cpp" + $File "importkeyvaluebase.cpp" + $File "importsfmv1.cpp" + $File "importsfmv2.cpp" + $File "importsfmv3.cpp" + $File "importsfmv4.cpp" + $File "importsfmv5.cpp" + $File "importsfmv6.cpp" + $File "importsfmv7.cpp" + $File "importsfmv8.cpp" + $File "importsfmv9.cpp" + $File "importvmf.cpp" + $File "importvmt.cpp" + } + + $Folder "Header Files" + { + $File "dmebaseimporter.h" + $File "dmserializers.h" + $File "$SRCDIR\public\dmserializers\idmserializers.h" + $File "importkeyvaluebase.h" + } +} diff --git a/dmserializers/importactbusy.cpp b/dmserializers/importactbusy.cpp new file mode 100644 index 0000000..2ca816e --- /dev/null +++ b/dmserializers/importactbusy.cpp @@ -0,0 +1,182 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "importkeyvaluebase.h" +#include "dmserializers.h" +#include "datamodel/idatamodel.h" +#include "datamodel/dmelement.h" +#include "tier1/KeyValues.h" +#include "tier1/utlbuffer.h" +#include "datamodel/dmattribute.h" + + +//----------------------------------------------------------------------------- +// Serialization class for Key Values +//----------------------------------------------------------------------------- +class CImportActBusy : public CImportKeyValueBase +{ +public: + virtual const char *GetName() const { return "actbusy"; } + virtual const char *GetDescription() const { return "ActBusy Script File"; } + virtual int GetCurrentVersion() const { return 0; } // doesn't store a version + + bool Serialize( CUtlBuffer &outBuf, CDmElement *pRoot ); + CDmElement* UnserializeFromKeyValues( KeyValues *pKeyValues ); + +private: + // Reads a single element + bool UnserializeActBusyKey( CDmAttribute *pChildren, KeyValues *pKeyValues ); + + // Writes out the actbusy header + void SerializeHeader( CUtlBuffer &buf ); +}; + + +//----------------------------------------------------------------------------- +// Singleton instance +//----------------------------------------------------------------------------- +static CImportActBusy s_ImportActBusy; + +void InstallActBusyImporter( IDataModel *pFactory ) +{ + pFactory->AddSerializer( &s_ImportActBusy ); +} + + +//----------------------------------------------------------------------------- +// Writes out the actbusy header +//----------------------------------------------------------------------------- +void CImportActBusy::SerializeHeader( CUtlBuffer &buf ) +{ + buf.Printf( "// \"act busy name\"\t\tThis is the name that a mapmaker must specify in the hint node.\n" ); + buf.Printf( "// {\n" ); + buf.Printf( "// \t\"busy_anim\"\t\t\t\"Activity Name\".\n" ); + buf.Printf( "// \t\"entry_anim\"\t\t\"Activity Name\"\n" ); + buf.Printf( "// \t\"exit_anim\"\t\t\t\"Activity Name\"\n" ); + buf.Printf( "// \t\"busy_sequence\"\t\t\"Sequence Name\". If specified, this is used over the activity name. Specify it in the hint node.\n" ); + buf.Printf( "// \t\"entry_sequence\"\t\"Sequence Name\". If specified, this is used over the entry anim.\n" ); + buf.Printf( "// \t\"exit_sequence\"\t\t\"Sequence Name\". If specified, this is used over the exit anim.\n" ); + buf.Printf( "// \t\"min_time\"\t\t\t\"Minimum time to spend in this busy anim\"\n" ); + buf.Printf( "// \t\"max_time\"\t\t\t\"Maximum time to spend in this busy anim\" 0 = only stop when interrupted by external event\n" ); + buf.Printf( "// \t\"interrupts\"\t\tOne of:\n" ); + buf.Printf( "// \t\t\t\t\t\t\"BA_INT_NONE\"\t\tbreak out only when time runs out. No external influence will break me out.\n" ); + buf.Printf( "// \t\t\t\t\t\t\"BA_INT_DANGER\"\t\tbreak out of this anim only if threatened\n" ); + buf.Printf( "// \t\t\t\t\t\t\"BA_INT_PLAYER\"\t\tbreak out of this anim if I can see the player, or I'm threatened\n" ); + buf.Printf( "// \t\t\t\t\t\t\"BA_INT_AMBUSH\"\t\tsomeone please define this - I have no idea what it does\n" ); + buf.Printf( "// \t\t\t\t\t\t\"BA_INT_COMBAT\"\t\tbreak out of this anim if combat occurs in my line of sight (bullet hits, grenades, etc), -OR- the max time is reached\n" ); + buf.Printf( "// }\n" ); + buf.Printf( "//\n" ); +} + + +//----------------------------------------------------------------------------- +// Writes out a new actbusy file +//----------------------------------------------------------------------------- +bool CImportActBusy::Serialize( CUtlBuffer &buf, CDmElement *pRoot ) +{ + SerializeHeader( buf ); + buf.Printf( "\"ActBusy.txt\"\n" ); + buf.Printf( "{\n" ); + + CDmAttribute *pChildren = pRoot->GetAttribute( "children" ); + if ( !pChildren || pChildren->GetType() != AT_ELEMENT_ARRAY ) + return NULL; + + CDmrElementArray<> children( pChildren ); + int nCount = children.Count(); + + buf.PushTab(); + for ( int i = 0; i < nCount; ++i ) + { + CDmElement *pChild = children[i]; + buf.Printf( "\"%s\"\n", pChild->GetName() ); + buf.Printf( "{\n" ); + + buf.PushTab(); + PrintStringAttribute( pChild, buf, "busy_anim", true ); + PrintStringAttribute( pChild, buf, "entry_anim", true ); + PrintStringAttribute( pChild, buf, "exit_anim", true ); + PrintStringAttribute( pChild, buf, "busy_sequence", true ); + PrintStringAttribute( pChild, buf, "entry_sequence", true ); + PrintStringAttribute( pChild, buf, "exit_sequence", true ); + PrintFloatAttribute( pChild, buf, "min_time" ); + PrintFloatAttribute( pChild, buf, "max_time" ); + PrintStringAttribute( pChild, buf, "interrupts" ); + buf.PopTab(); + + buf.Printf( "}\n" ); + } + buf.PopTab(); + + buf.Printf( "}\n" ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Reads a single element +//----------------------------------------------------------------------------- +bool CImportActBusy::UnserializeActBusyKey( CDmAttribute *pChildren, KeyValues *pKeyValues ) +{ + CDmElement *pActBusy = CreateDmElement( "DmElement", pKeyValues->GetName(), NULL ); + if ( !pActBusy ) + return false; + + // Each act busy needs to have an editortype associated with it so it displays nicely in editors + pActBusy->SetValue( "editorType", "actBusy" ); + + float flZero = 0.0f; + AddStringAttribute( pActBusy, pKeyValues, "busy_anim", "" ); + AddStringAttribute( pActBusy, pKeyValues, "entry_anim", "" ); + AddStringAttribute( pActBusy, pKeyValues, "exit_anim", "" ); + AddStringAttribute( pActBusy, pKeyValues, "busy_sequence", "" ); + AddStringAttribute( pActBusy, pKeyValues, "entry_sequence", "" ); + AddStringAttribute( pActBusy, pKeyValues, "exit_sequence", "" ); + AddFloatAttribute( pActBusy, pKeyValues, "min_time", &flZero ); + AddFloatAttribute( pActBusy, pKeyValues, "max_time", &flZero ); + AddStringAttribute( pActBusy, pKeyValues, "interrupts", "BA_INT_NONE" ); + + CDmrElementArray<> children( pChildren ); + children.AddToTail( pActBusy ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Main entry point for the unserialization +//----------------------------------------------------------------------------- +CDmElement* CImportActBusy::UnserializeFromKeyValues( KeyValues *pKeyValues ) +{ + // Create the main element + CDmElement *pElement = CreateDmElement( "DmElement", "ActBusyList", NULL ); + if ( !pElement ) + return NULL; + + // Each act busy list needs to have an editortype associated with it so it displays nicely in editors + pElement->SetValue( "editorType", "actBusyList" ); + + // All actbusy keys are elements of a single element array attribute 'children' + CDmAttribute *pChildren = pElement->AddAttribute( "children", AT_ELEMENT_ARRAY ); + if ( !pChildren ) + return NULL; + + // Under the root are all the actbusy keys + for ( KeyValues *pActBusyKey = pKeyValues->GetFirstTrueSubKey(); pActBusyKey != NULL; pActBusyKey = pActBusyKey->GetNextTrueSubKey() ) + { + if ( !UnserializeActBusyKey( pChildren, pActBusyKey ) ) + { + Warning( "Error importing actbusy element %s\n", pActBusyKey->GetName() ); + return NULL; + } + } + + // Resolve all element references recursively + RecursivelyResolveElement( pElement ); + + return pElement; +} diff --git a/dmserializers/importkeyvaluebase.cpp b/dmserializers/importkeyvaluebase.cpp new file mode 100644 index 0000000..88d2308 --- /dev/null +++ b/dmserializers/importkeyvaluebase.cpp @@ -0,0 +1,292 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "importkeyvaluebase.h" +#include "dmserializers.h" +#include "datamodel/idatamodel.h" +#include "datamodel/dmelement.h" +#include "tier1/KeyValues.h" +#include "tier1/utlbuffer.h" +#include <limits.h> + + +//----------------------------------------------------------------------------- +// Default serialization method +//----------------------------------------------------------------------------- +bool CImportKeyValueBase::Serialize( CUtlBuffer &outBuf, CDmElement *pRoot ) +{ + Warning( "Serialization not supported for importing from keyvalues files\n"); + return false; +} + + +//----------------------------------------------------------------------------- +// Creates a new element +//----------------------------------------------------------------------------- +CDmElement* CImportKeyValueBase::CreateDmElement( const char *pElementType, const char *pElementName, DmObjectId_t *pId ) +{ + // See if we can create an element of that type + DmElementHandle_t hElement = g_pDataModel->CreateElement( pElementType, pElementName, DMFILEID_INVALID, pId ); + if ( hElement == DMELEMENT_HANDLE_INVALID ) + { + Warning("%s: Element uses unknown element type %s\n", m_pFileName, pElementType ); + return NULL; + } + + return g_pDataModel->GetElement( hElement ); +} + + +//----------------------------------------------------------------------------- +// Used to output typed attributes to keyvalues +//----------------------------------------------------------------------------- +void CImportKeyValueBase::PrintBoolAttribute( CDmElement* pElement, CUtlBuffer &outBuf, const char *pKeyName ) +{ + if ( pElement->HasAttribute( pKeyName ) ) + { + CDmAttribute *pAttribute = pElement->GetAttribute( pKeyName ); + if ( pAttribute->GetType() == AT_BOOL ) + { + outBuf.Printf("\"%s\" \"%d\"\n", pKeyName, pAttribute->GetValue<bool>( ) ); + } + } +} + +void CImportKeyValueBase::PrintIntAttribute( CDmElement* pElement, CUtlBuffer &outBuf, const char *pKeyName ) +{ + if ( pElement->HasAttribute( pKeyName ) ) + { + CDmAttribute *pAttribute = pElement->GetAttribute( pKeyName ); + if ( pAttribute->GetType() == AT_INT ) + { + outBuf.Printf("\"%s\" \"%d\"\n", pKeyName, pAttribute->GetValue<int>( ) ); + } + } +} + +void CImportKeyValueBase::PrintFloatAttribute( CDmElement* pElement, CUtlBuffer &outBuf, const char *pKeyName ) +{ + if ( pElement->HasAttribute( pKeyName ) ) + { + CDmAttribute *pAttribute = pElement->GetAttribute( pKeyName ); + if ( pAttribute->GetType() == AT_FLOAT ) + { + outBuf.Printf("\"%s\" \"%.10f\"\n", pKeyName, pAttribute->GetValue<float>( ) ); + } + } +} + +void CImportKeyValueBase::PrintStringAttribute( CDmElement* pElement, CUtlBuffer &outBuf, const char *pKeyName, bool bSkipEmptryStrings, bool bPrintValueOnly ) +{ + if ( pElement->HasAttribute( pKeyName ) ) + { + CDmAttribute *pAttribute = pElement->GetAttribute( pKeyName ); + if ( pAttribute->GetType() == AT_STRING ) + { + const char *pValue = pAttribute->GetValueString(); + if ( !bSkipEmptryStrings || pValue[0] ) + { + if ( !bPrintValueOnly ) + { + outBuf.Printf("\"%s\" \"%s\"\n", pKeyName, pValue ); + } + else + { + outBuf.Printf("\"%s\"\n", pValue ); + } + } + } + } +} + + +//----------------------------------------------------------------------------- +// Used to add typed attributes from keyvalues +//----------------------------------------------------------------------------- +bool CImportKeyValueBase::AddBoolAttribute( CDmElement* pElement, KeyValues *pKeyValues, const char *pKeyName, bool *pDefault ) +{ + KeyValues *pKey = pKeyValues->FindKey( pKeyName ); + bool bValue; + if ( pKey ) + { + bValue = pKey->GetInt() != 0; + } + else + { + if ( !pDefault ) + return true; + bValue = *pDefault; + } + + return pElement->SetValue( pKeyName, bValue ) != NULL; +} + + +//----------------------------------------------------------------------------- +// Used to add typed attributes from keyvalues +//----------------------------------------------------------------------------- +bool CImportKeyValueBase::AddIntAttribute( CDmElement* pElement, KeyValues *pKeyValues, const char *pKeyName, int *pDefault ) +{ + KeyValues *pKey = pKeyValues->FindKey( pKeyName ); + int nValue; + if ( pKey ) + { + nValue = pKey->GetInt(); + } + else + { + if ( !pDefault ) + return true; + nValue = *pDefault; + } + + return pElement->SetValue( pKeyName, nValue ) != NULL; +} + +bool CImportKeyValueBase::AddFloatAttribute( CDmElement* pElement, KeyValues *pKeyValues, const char *pKeyName, float *pDefault ) +{ + KeyValues *pKey = pKeyValues->FindKey( pKeyName ); + float flValue; + if ( pKey ) + { + flValue = pKey->GetFloat(); + } + else + { + if ( !pDefault ) + return true; + flValue = *pDefault; + } + + return pElement->SetValue( pKeyName, flValue ) != NULL; +} + +bool CImportKeyValueBase::AddStringAttribute( CDmElement* pElement, KeyValues *pKeyValues, const char *pKeyName, const char *pDefault ) +{ + KeyValues *pKey = pKeyValues->FindKey( pKeyName ); + const char *pValue = ""; + if ( pKey ) + { + pValue = pKey->GetString(); + } + else + { + if ( !pDefault ) + return true; + pValue = pDefault; + } + + return pElement->SetValue( pKeyName, pValue ) != NULL; +} + + +//----------------------------------------------------------------------------- +// Used to add typed attributes from keyvalues +//----------------------------------------------------------------------------- +bool CImportKeyValueBase::AddBoolAttributeFlags( CDmElement* pElement, KeyValues *pKeyValue, const char *pKeyName, int nFlags, bool *pDefault ) +{ + if ( !AddBoolAttribute( pElement, pKeyValue, pKeyName, pDefault ) ) + return false; + + CDmAttribute *pAttribute = pElement->GetAttribute( pKeyName ); + pAttribute->AddFlag( nFlags ); + return true; +} + +bool CImportKeyValueBase::AddIntAttributeFlags( CDmElement* pElement, KeyValues *pKeyValue, const char *pKeyName, int nFlags, int *pDefault ) +{ + if ( !AddIntAttribute( pElement, pKeyValue, pKeyName, pDefault ) ) + return false; + + CDmAttribute *pAttribute = pElement->GetAttribute( pKeyName ); + pAttribute->AddFlag( nFlags ); + return true; +} + +bool CImportKeyValueBase::AddFloatAttributeFlags( CDmElement* pElement, KeyValues *pKeyValue, const char *pKeyName, int nFlags, float *pDefault ) +{ + if ( !AddFloatAttribute( pElement, pKeyValue, pKeyName, pDefault ) ) + return false; + + CDmAttribute *pAttribute = pElement->GetAttribute( pKeyName ); + pAttribute->AddFlag( nFlags ); + return true; +} + +bool CImportKeyValueBase::AddStringAttributeFlags( CDmElement* pElement, KeyValues *pKeyValue, const char *pKeyName, int nFlags, const char *pDefault ) +{ + if ( !AddStringAttribute( pElement, pKeyValue, pKeyName, pDefault ) ) + return false; + + CDmAttribute *pAttribute = pElement->GetAttribute( pKeyName ); + pAttribute->AddFlag( nFlags ); + return true; +} + + +//----------------------------------------------------------------------------- +// Recursively resolves all attributes pointing to elements +//----------------------------------------------------------------------------- +void CImportKeyValueBase::RecursivelyResolveElement( CDmElement* pElement ) +{ + if ( !pElement ) + return; + + pElement->Resolve(); + + CDmAttribute *pAttribute = pElement->FirstAttribute(); + while ( pAttribute ) + { + switch ( pAttribute->GetType() ) + { + case AT_ELEMENT: + { + CDmElement *pElementAt = pAttribute->GetValueElement<CDmElement>(); + RecursivelyResolveElement( pElementAt ); + } + break; + + case AT_ELEMENT_ARRAY: + { + CDmrElementArray<> array( pAttribute ); + int nCount = array.Count(); + for ( int i = 0; i < nCount; ++i ) + { + CDmElement *pElementAt = array[ i ]; + RecursivelyResolveElement( pElementAt ); + } + } + break; + } + + pAttribute = pAttribute->NextAttribute( ); + } +} + + +//----------------------------------------------------------------------------- +// Main entry point for the unserialization +//----------------------------------------------------------------------------- +bool CImportKeyValueBase::Unserialize( CUtlBuffer &buf, const char *pEncodingName, int nEncodingVersion, + const char *pSourceFormatName, int nSourceFormatVersion, + DmFileId_t fileid, DmConflictResolution_t idConflictResolution, CDmElement **ppRoot ) +{ + *ppRoot = NULL; + m_pFileName = g_pDataModel->GetFileName( fileid ); + + KeyValues *kv = new KeyValues( "dmx file" ); + if ( !kv ) + return false; + + bool bOk = kv->LoadFromBuffer( "dmx file", buf ); + if ( bOk ) + { + *ppRoot = UnserializeFromKeyValues( kv ); + } + + kv->deleteThis(); + return bOk; +} diff --git a/dmserializers/importkeyvaluebase.h b/dmserializers/importkeyvaluebase.h new file mode 100644 index 0000000..771d048 --- /dev/null +++ b/dmserializers/importkeyvaluebase.h @@ -0,0 +1,84 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef IMPORTKEYVALUEBASE_H +#define IMPORTKEYVALUEBASE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "datamodel/idatamodel.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CUtlBuffer; +class KeyValues; +class CDmElement; + + +//----------------------------------------------------------------------------- +// Serialization class for Key Values +//----------------------------------------------------------------------------- +abstract_class CImportKeyValueBase : public IDmSerializer +{ +public: + // Inherited from IDMSerializer + virtual bool StoresVersionInFile() const { return false; } + virtual bool IsBinaryFormat() const { return false; } + virtual bool Serialize( CUtlBuffer &buf, CDmElement *pRoot ); + virtual bool Unserialize( CUtlBuffer &buf, const char *pEncodingName, int nEncodingVersion, + const char *pSourceFormatName, int nSourceFormatVersion, + DmFileId_t fileid, DmConflictResolution_t idConflictResolution, CDmElement **ppRoot ); + +protected: + // Main entry point for derived classes to implement unserialization + virtual CDmElement* UnserializeFromKeyValues( KeyValues *pKeyValues ) = 0; + + // Returns the file name associated with the unserialization + const char *FileName() const; + + // Creates new elements + CDmElement* CreateDmElement( const char *pElementType, const char *pElementName, DmObjectId_t *pId ); + + // Recursively resolves all attributes pointing to elements + void RecursivelyResolveElement( CDmElement* pElement ); + + // Used to add typed attributes from keyvalues + bool AddBoolAttribute( CDmElement* pElement, KeyValues *pKeyValue, const char *pKeyName, bool *pDefault = NULL ); + bool AddIntAttribute( CDmElement* pElement, KeyValues *pKeyValue, const char *pKeyName, int *pDefault = NULL ); + bool AddFloatAttribute( CDmElement* pElement, KeyValues *pKeyValue, const char *pKeyName, float *pDefault = NULL ); + bool AddStringAttribute( CDmElement* pElement, KeyValues *pKeyValue, const char *pKeyName, const char *pDefault = NULL ); + + // Used to add typed attributes from keyvalues + bool AddBoolAttributeFlags( CDmElement* pElement, KeyValues *pKeyValue, const char *pKeyName, int nFlags, bool *pDefault = NULL ); + bool AddIntAttributeFlags( CDmElement* pElement, KeyValues *pKeyValue, const char *pKeyName, int nFlags, int *pDefault = NULL ); + bool AddFloatAttributeFlags( CDmElement* pElement, KeyValues *pKeyValue, const char *pKeyName, int nFlags, float *pDefault = NULL ); + bool AddStringAttributeFlags( CDmElement* pElement, KeyValues *pKeyValue, const char *pKeyName, int nFlags, const char *pDefault = NULL ); + + // Used to output typed attributes to keyvalues + void PrintBoolAttribute( CDmElement* pElement, CUtlBuffer &outBuf, const char *pKeyName ); + void PrintIntAttribute( CDmElement* pElement, CUtlBuffer &outBuf, const char *pKeyName ); + void PrintFloatAttribute( CDmElement* pElement, CUtlBuffer &outBuf, const char *pKeyName ); + void PrintStringAttribute( CDmElement* pElement, CUtlBuffer &outBuf, const char *pKeyName, bool bSkipEmptryStrings = false, bool bPrintValueOnly = false ); + +private: + const char *m_pFileName; +}; + + +//----------------------------------------------------------------------------- +// Returns the file name associated with the unserialization +//----------------------------------------------------------------------------- +inline const char *CImportKeyValueBase::FileName() const +{ + return m_pFileName; +} + + +#endif // IMPORTKEYVALUEBASE_H diff --git a/dmserializers/importsfmv1.cpp b/dmserializers/importsfmv1.cpp new file mode 100644 index 0000000..1da3f5e --- /dev/null +++ b/dmserializers/importsfmv1.cpp @@ -0,0 +1,219 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "dmserializers.h" +#include "dmebaseimporter.h" +#include "datamodel/idatamodel.h" +#include "datamodel/dmattribute.h" +#include "datamodel/dmelement.h" + +#include <math.h> + +//----------------------------------------------------------------------------- +// Format converter +//----------------------------------------------------------------------------- +class CImportSFMV1 : public CSFMBaseImporter +{ + typedef CSFMBaseImporter BaseClass; +public: + CImportSFMV1( char const *formatName, char const *nextFormatName ); + +private: + virtual bool DoFixup( CDmElement *pSourceRoot ); + + // Fixes up a single time attribute - converting from float seconds to int tenths-of-a-millisecond + void ConvertTimeAttribute( CDmElement *pElementInternal, const char *pOldName, const char *pNewName ); + + // Fixes up a single timeframe + void FixupTimeframe( CDmElement *pElementInternal ); + + // Fixes up a single log - converting from int milliseconds to int tenths-of-a-millisecond + void FixupLog( CDmElement *pElementInternal ); + + CUtlRBTree< CDmElement*, int > m_fixedElements; +}; + + +//----------------------------------------------------------------------------- +// Singleton instance +//----------------------------------------------------------------------------- +static CImportSFMV1 s_ImportDmxV1( "sfm_v1", "sfm_v2" ); + +void InstallSFMV1Importer( IDataModel *pFactory ) +{ + pFactory->AddLegacyUpdater( &s_ImportDmxV1 ); +} + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CImportSFMV1::CImportSFMV1( char const *formatName, char const *nextFormatName ) : + BaseClass( formatName, nextFormatName ) +{ + m_fixedElements.SetLessFunc( DefLessFunc( CDmElement * ) ); +} + + +//----------------------------------------------------------------------------- +// Fixes up all elements +//----------------------------------------------------------------------------- +bool CImportSFMV1::DoFixup( CDmElement *pElementInternal ) +{ + if ( !pElementInternal ) + return true; + + if ( m_fixedElements.Find( pElementInternal ) != m_fixedElements.InvalidIndex() ) + return true; + + m_fixedElements.Insert( pElementInternal ); + + const char *pType = pElementInternal->GetTypeString(); + if ( !Q_strcmp( pType, "DmeTimeFrame" ) ) + { + FixupTimeframe( pElementInternal ); + } + else if ( !Q_strcmp( pType, "DmeLog" ) || + !Q_strcmp( pType, "DmeIntLog" ) || + !Q_strcmp( pType, "DmeFloatLog" ) || + !Q_strcmp( pType, "DmeBoolLog" ) || + !Q_strcmp( pType, "DmeColorLog" ) || + !Q_strcmp( pType, "DmeVector2Log" ) || + !Q_strcmp( pType, "DmeVector3Log" ) || + !Q_strcmp( pType, "DmeVector4Log" ) || + !Q_strcmp( pType, "DmeQAngleLog" ) || + !Q_strcmp( pType, "DmeQuaternionLog" ) || + !Q_strcmp( pType, "DmeVMatrixLog" ) ) + { + FixupLog( pElementInternal ); + } + + + for ( CDmAttribute *pAttribute = pElementInternal->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() ) + { + if ( pAttribute->GetType() == AT_ELEMENT ) + { + CDmElement *pElement = pAttribute->GetValueElement<CDmElement>( ); + DoFixup( pElement ); + continue; + } + + if ( pAttribute->GetType() == AT_ELEMENT_ARRAY ) + { + CDmrElementArray<> array( pAttribute ); + int nCount = array.Count(); + for ( int i = 0; i < nCount; ++i ) + { + CDmElement *pChild = array[ i ]; + DoFixup( pChild ); + } + continue; + } + } + + return true; +} + +//----------------------------------------------------------------------------- +// Fixes up a single time attribute - converting from float seconds to int tenths-of-a-millisecond +//----------------------------------------------------------------------------- +void CImportSFMV1::ConvertTimeAttribute( CDmElement *pElementInternal, const char *pOldName, const char *pNewName ) +{ + float time = 0.0f; + CDmAttribute *pOldAttr = pElementInternal->GetAttribute( pOldName ); + if ( !pOldAttr ) + { + Warning( "*** Problem in file encountered!\n" ); + Warning( "*** TimeFrame \"%s\" is missing attribute \"%s\"!\n", pElementInternal->GetName(), pOldName ); + Warning( "*** Setting new attribute \"%s\" to 0\n", pNewName ); + } + else if ( pOldAttr->GetType() != AT_FLOAT ) + { + Warning( "*** Problem in file encountered!\n" ); + Warning( "*** TimeFrame \"%s\" has attribute \"%s\" with an unexpected type (expected float)!\n", pElementInternal->GetName(), pOldName ); + } + else + { + time = pOldAttr->GetValue< float >(); + pElementInternal->RemoveAttribute( pOldName ); + } + + CDmAttribute *pNewAttr = NULL; + + // this is disabled because even dmxconvert installs *some* movieobjects factories, when it probably shouldn't + // the method of installing movieobjects factories will change at some point in the future, and we can turn on this safety check then +#if 0 + int i = g_pDataModel->GetFirstFactory(); + if ( g_pDataModel->IsValidFactory( i ) ) + { + // factories installed - most likely from within movieobjects.lib + // ie there may be different ways of allocating attributes, so it's not safe to add them here + pNewAttr = pElementInternal->GetAttribute( pNewName ); + if ( !pNewAttr || pNewAttr->GetType() != AT_INT ) + { + Assert( 0 ); + Warning( "*** Converter error - expected element \"%s\" to contain int attribute \"%s\"!\n", pElementInternal->GetName(), pNewName ); + Warning( "*** - if you get this error, the converter is out of sync with the element library!\n" ); + return; + } + } + else + { +#endif + // no factories installed - most likely from within dmxconvert.exe + // ie we're just working with CDmElement subclasses, so it's safe to add attributes + pNewAttr = pElementInternal->AddAttribute( pNewName, AT_INT ); + if ( !pNewAttr ) + { + Assert( 0 ); + Warning( "*** Converter error - element \"%s\" already has a non-int attribute \"%s\"!\n", pElementInternal->GetName(), pNewName ); + return; + } +#if 0 + } +#endif + + pNewAttr->SetValue< int >( floor( time * 10000 + 0.5f ) ); +} + +//----------------------------------------------------------------------------- +// Fixes up a single timeframe +//----------------------------------------------------------------------------- +void CImportSFMV1::FixupTimeframe( CDmElement *pElementInternal ) +{ + ConvertTimeAttribute( pElementInternal, "start", "startTime" ); + ConvertTimeAttribute( pElementInternal, "duration", "durationTime" ); + ConvertTimeAttribute( pElementInternal, "offset", "offsetTime" ); +} + +//----------------------------------------------------------------------------- +// Fixes up a single log - converting from int milliseconds to int tenths-of-a-millisecond +//----------------------------------------------------------------------------- +void CImportSFMV1::FixupLog( CDmElement *pElementInternal ) +{ + CDmAttribute *pAttr = pElementInternal->GetAttribute( "times" ); + if ( !pAttr ) + { + Warning( "*** Problem in file encountered!\n" ); + Warning( "*** Log \"%s\" is missing attribute \"%s\"!\n", pElementInternal->GetName(), "times" ); + return; + } + + if ( pAttr->GetType() != AT_INT_ARRAY ) + { + Warning( "*** Problem in file encountered!\n" ); + Warning( "*** Log \"%s\" has attribute \"%s\" with an unexpected type (expected int array)!\n", pElementInternal->GetName(), "times" ); + return; + } + + CDmrArray<int> array( pAttr ); + int c = array.Count(); + for ( int i = 0; i < c; ++i ) + { + // convert all log times from int milliseconds to int tenths-of-a-millisecond + array.Set( i, 10 * array[i] ); + } +} diff --git a/dmserializers/importsfmv2.cpp b/dmserializers/importsfmv2.cpp new file mode 100644 index 0000000..829ae0c --- /dev/null +++ b/dmserializers/importsfmv2.cpp @@ -0,0 +1,294 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "dmserializers.h" +#include "dmebaseimporter.h" +#include "datamodel/idatamodel.h" +#include "datamodel/dmelement.h" +#include "tier1/KeyValues.h" +#include "tier1/utlbuffer.h" +#include "tier1/utlmap.h" +#include <limits.h> + + +//----------------------------------------------------------------------------- +// Format converter +//----------------------------------------------------------------------------- +class CImportSFMV2 : public CSFMBaseImporter +{ + typedef CSFMBaseImporter BaseClass; +public: + CImportSFMV2( char const *formatName, char const *nextFormatName ); + +private: + virtual bool DoFixup( CDmElement *pSourceRoot ); + + + void FixupElement( CDmElement *pElement ); + // Fixes up all elements + void BuildList( CDmElement *pElement, CUtlRBTree< CDmElement *, int >& list ); +}; + + +//----------------------------------------------------------------------------- +// Singleton instance +//----------------------------------------------------------------------------- +static CImportSFMV2 s_ImportSFMV2( "sfm_v2", "sfm_v3" ); + +void InstallSFMV2Importer( IDataModel *pFactory ) +{ + pFactory->AddLegacyUpdater( &s_ImportSFMV2 ); +} + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CImportSFMV2::CImportSFMV2( char const *formatName, char const *nextFormatName ) : + BaseClass( formatName, nextFormatName ) +{ +} + + +struct LayerType_t +{ + char const *loglayertype; + int datatype; + char const *logtype; +}; + +static LayerType_t g_LayerTypes[] = +{ + { "DmeIntLogLayer", AT_INT_ARRAY, "DmeIntLog" }, + { "DmeFloatLogLayer", AT_FLOAT_ARRAY, "DmeFloatLog" }, + { "DmeBoolLogLayer", AT_BOOL_ARRAY, "DmeBoolLog" }, + // AT_STRING_ARRAY, + // AT_VOID_ARRAY, + // AT_OBJECTID_ARRAY, + { "DmeColorLogLayer", AT_COLOR_ARRAY, "DmeColorLog" }, + { "DmeVector2LogLayer", AT_VECTOR2_ARRAY, "DmeVector2Log" }, + { "DmeVector3LogLayer", AT_VECTOR3_ARRAY, "DmeVector3Log" }, + { "DmeVector4LogLayer", AT_VECTOR4_ARRAY, "DmeVector4Log" }, + { "DmeQAngleLogLayer", AT_QANGLE_ARRAY, "DmeQAngleLog" }, + { "DmeQuaternionLogLayer", AT_QUATERNION_ARRAY, "DmeQuaternionLog" }, + { "DmeVMatrixLogLayer", AT_VMATRIX_ARRAY, "DmeVMatrixLog" }, + // AT_ELEMENT_ARRAY + // NO ARRAY TYPES EITHER!!! +}; + +int GetLogType( char const *type ) +{ + int c = ARRAYSIZE( g_LayerTypes ); + for ( int i = 0; i < c; ++i ) + { + if ( !Q_stricmp( type, g_LayerTypes[ i ].logtype ) ) + return g_LayerTypes[ i ].datatype; + } + return AT_UNKNOWN; +} + +char const *GetLogLayerType( int nDataType ) +{ + int c = ARRAYSIZE( g_LayerTypes ); + for ( int i = 0; i < c; ++i ) + { + if ( nDataType == g_LayerTypes[ i ].datatype ) + return g_LayerTypes[ i ].loglayertype; + } + return NULL; +} + +char const *GetLogLayerType( char const *logType ) +{ + int c = ARRAYSIZE( g_LayerTypes ); + for ( int i = 0; i < c; ++i ) + { + if ( !Q_stricmp( logType, g_LayerTypes[ i ].logtype ) ) + return g_LayerTypes[ i ].loglayertype; + } + return NULL; +} + +template< class T > +void CopyValues( int layerType, CDmElement *pElement, CDmElement *pLayer, CDmAttribute *pInTimeAttribute, CDmAttribute *pInCurveTypeAttribute ) +{ + CDmAttribute *pInValueAttribute = pElement->GetAttribute( "values" ); + if ( !pInValueAttribute ) + { + Assert( 0 ); + return; + } + + CDmrArray<T> outValues( pLayer->AddAttribute( "values", (DmAttributeType_t)layerType ) ); + CDmrArray<int> outTimes( pLayer->AddAttribute( "times", AT_INT_ARRAY ) ); + CDmrArray<int> outCurveTypes; + if ( pInCurveTypeAttribute ) + { + outCurveTypes.Init( pLayer->AddAttribute( "curvetypes", AT_INT_ARRAY ) ); + } + + CDmrArray<T> inValues( pInValueAttribute ); + CDmrArray<int> inTimes( pInTimeAttribute ); + CDmrArray<int> inCurveTypes( pInCurveTypeAttribute ); + + Assert( inValues.Count() == inTimes.Count() ); + int c = inValues.Count(); + for ( int i = 0; i < c; ++i ) + { + outTimes.AddToTail( inTimes[ i ] ); + outValues.AddToTail( inValues[ i ] ); + if ( outCurveTypes.IsValid() ) + { + outCurveTypes.AddToTail( inCurveTypes[ i ] ); + } + } +} + + +//----------------------------------------------------------------------------- +// Fixes up all elements +//----------------------------------------------------------------------------- +void CImportSFMV2::FixupElement( CDmElement *pElement ) +{ + if ( !pElement ) + return; + + // Perform the fixup + const char *pType = pElement->GetTypeString(); + int layerType = GetLogType( pType ); + if ( layerType != AT_UNKNOWN ) + { + /* + char buf[ 128 ]; + g_pDataModel->ToString( pElement->GetId(), buf, sizeof( buf ) ); + + Msg( "Processing %s %s id %s\n", + pElement->GetTypeString(), pElement->GetName(), buf ); + */ + + // Find attribute arrays for times, values and curvetypes + CDmAttribute *pTimes = pElement->GetAttribute( "times" ); + CDmAttribute *pCurveTypes = NULL; + + // FIX + CDmAttribute *pAttr = pElement->AddAttribute( "usecurvetypes", AT_BOOL ); + if ( pAttr->GetValue<bool>() ) + { + pCurveTypes = pElement->GetAttribute( "curvetypes" ); + } + + // Get the default layer (added when the new style log is created) + CDmrElementArray<> layers( pElement->AddAttribute( "layers", AT_ELEMENT_ARRAY ) ); + CDmElement *layer = NULL; + if ( layers.Count() == 0 ) + { + DmElementHandle_t hElement = g_pDataModel->CreateElement( GetLogLayerType( layerType ), GetLogLayerType( layerType ), pElement->GetFileId() ); + layer = g_pDataModel->GetElement( hElement ); + layers.AddToTail( layer ); + } + else + { + Assert( layers.Count() == 1 ); + layer = layers[ 0 ]; + } + + // Copy data + switch ( layerType ) + { + default: + case AT_UNKNOWN: + break; + case AT_FLOAT_ARRAY: + CopyValues< float >( layerType, pElement, layer, pTimes, pCurveTypes ); + break; + case AT_INT_ARRAY: + CopyValues< int >( layerType, pElement, layer, pTimes, pCurveTypes ); + break; + case AT_BOOL_ARRAY: + CopyValues< bool >( layerType, pElement, layer, pTimes, pCurveTypes ); + break; + case AT_COLOR_ARRAY: + CopyValues< Color >( layerType, pElement, layer, pTimes, pCurveTypes ); + break; + case AT_VECTOR2_ARRAY: + CopyValues< Vector2D >( layerType, pElement, layer, pTimes, pCurveTypes ); + break; + case AT_VECTOR3_ARRAY: + CopyValues< Vector >( layerType, pElement, layer, pTimes, pCurveTypes ); + break; + case AT_VECTOR4_ARRAY: + CopyValues< Vector4D >( layerType, pElement, layer, pTimes, pCurveTypes ); + break; + case AT_QANGLE_ARRAY: + CopyValues< QAngle >( layerType, pElement, layer, pTimes, pCurveTypes ); + break; + case AT_QUATERNION_ARRAY: + CopyValues< Quaternion >( layerType, pElement, layer, pTimes, pCurveTypes ); + break; + case AT_VMATRIX_ARRAY: + CopyValues< VMatrix >( layerType, pElement, layer, pTimes, pCurveTypes ); + break; + } + + // Set the back pointer + CDmAttribute *ownerLog = layer->AddAttribute( "ownerlog", AT_ELEMENT ); + Assert( ownerLog ); + ownerLog->SetValue( pElement->GetHandle() ); + + // Delete the base attributes + pElement->RemoveAttribute( "times" ); + pElement->RemoveAttribute( "values" ); + pElement->RemoveAttribute( "curvetypes" ); + } +} + +// Fixes up all elements +//----------------------------------------------------------------------------- +void CImportSFMV2::BuildList( CDmElement *pElement, CUtlRBTree< CDmElement *, int >& list ) +{ + if ( !pElement ) + return; + + if ( list.Find( pElement ) != list.InvalidIndex() ) + return; + + list.Insert( pElement ); + + // Descene to bottom of tree, then do fixup coming back up the tree + for ( CDmAttribute *pAttribute = pElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() ) + { + if ( pAttribute->GetType() == AT_ELEMENT ) + { + CDmElement *pElementAt = pAttribute->GetValueElement<CDmElement>( ); + BuildList( pElementAt, list ); + continue; + } + + if ( pAttribute->GetType() == AT_ELEMENT_ARRAY ) + { + CDmrElementArray<> array( pAttribute ); + int nCount = array.Count(); + for ( int i = 0; i < nCount; ++i ) + { + CDmElement *pChild = array[ i ]; + BuildList( pChild, list ); + } + continue; + } + } +} + +bool CImportSFMV2::DoFixup( CDmElement *pSourceRoot ) +{ + CUtlRBTree< CDmElement *, int > fixlist( 0, 0, DefLessFunc( CDmElement * ) ); + BuildList( pSourceRoot, fixlist ); + for ( int i = fixlist.FirstInorder(); i != fixlist.InvalidIndex() ; i = fixlist.NextInorder( i ) ) + { + // Search and replace in the entire tree! + FixupElement( fixlist[ i ] ); + } + return true; +} diff --git a/dmserializers/importsfmv3.cpp b/dmserializers/importsfmv3.cpp new file mode 100644 index 0000000..d421eb3 --- /dev/null +++ b/dmserializers/importsfmv3.cpp @@ -0,0 +1,227 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "dmserializers.h" +#include "dmebaseimporter.h" +#include "datamodel/idatamodel.h" +#include "datamodel/dmelement.h" +#include "tier1/KeyValues.h" +#include "tier1/utlbuffer.h" +#include "tier1/utlmap.h" +#include <limits.h> + + +//----------------------------------------------------------------------------- +// Format converter +//----------------------------------------------------------------------------- +class CImportSFMV3 : public CSFMBaseImporter +{ + typedef CSFMBaseImporter BaseClass; +public: + CImportSFMV3( char const *formatName, char const *nextFormatName ); + +private: + virtual bool DoFixup( CDmElement *pSourceRoot ); + + + void FixupElement( CDmElement *pElement ); + // Fixes up all elements + void BuildList( CDmElement *pElement, CUtlRBTree< CDmElement *, int >& list ); +}; + + +//----------------------------------------------------------------------------- +// Singleton instance +//----------------------------------------------------------------------------- +static CImportSFMV3 s_ImportSFMV3( "sfm_v3", "sfm_v4" ); + +void InstallSFMV3Importer( IDataModel *pFactory ) +{ + pFactory->AddLegacyUpdater( &s_ImportSFMV3 ); +} + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CImportSFMV3::CImportSFMV3( char const *formatName, char const *nextFormatName ) : + BaseClass( formatName, nextFormatName ) +{ +} + + +struct LogToCurveInfoTypeMap_t +{ + const char *pLogType; + const char *pLogLayerType; + const char *pCurveInfoType; +}; + +LogToCurveInfoTypeMap_t g_typeMap[] = +{ + { "DmeIntLog", "DmeIntLogLayer", "DmeIntCurveInfo" }, + { "DmeFloatLog", "DmeFloatLogLayer", "DmeFloatCurveInfo" }, + { "DmeBoolLog", "DmeBoolLogLayer", "DmeBoolCurveInfo" }, + // string, + // void, + // objectid, + { "DmeColorLog", "DmeColorLogLayer", "DmeColorCurveInfo" }, + { "DmeVector2Log", "DmeVector2LogLayer", "DmeVector2CurveInfo" }, + { "DmeVector3Log", "DmeVector3LogLayer", "DmeVector3CurveInfo" }, + { "DmeVector4Log", "DmeVector4LogLayer", "DmeVector4CurveInfo" }, + { "DmeQAngleLog", "DmeQAngleLogLayer", "DmeQAngleCurveInfo" }, + { "DmeQuaternionLog", "DmeQuaternionLogLayer","DmeQuaternionCurveInfo" }, + { "DmeVMatrixLog", "DmeVMatrixLogLayer", "DmeVMatrixCurveInfo" }, +}; + +const char *GetCurveInfoTypeFromLogType( const char *pLogType ) +{ + int c = ARRAYSIZE( g_typeMap ); + for ( int i = 0; i < c; ++i ) + { + if ( !Q_stricmp( pLogType, g_typeMap[ i ].pLogType ) ) + return g_typeMap[ i ].pCurveInfoType; + } + return NULL; +} + +bool IsLogLayerType( const char *pLogLayerType ) +{ + int c = ARRAYSIZE( g_typeMap ); + for ( int i = 0; i < c; ++i ) + { + if ( !Q_stricmp( pLogLayerType, g_typeMap[ i ].pLogLayerType ) ) + return true; + } + return false; +} + +void MoveAttribute( CDmElement *pFromElement, const char *pFromAttrName, CDmElement *pToElement = NULL, const char *pToAttrName = NULL, DmAttributeType_t toType = AT_UNKNOWN ) +{ + if ( !pToAttrName ) + { + pToAttrName = pFromAttrName; + } + + if ( pToElement ) + { + CDmAttribute *pFromAttr = pFromElement->GetAttribute( pFromAttrName ); + const void *pValue = pFromAttr->GetValueUntyped(); + DmAttributeType_t fromType = pFromAttr->GetType(); + if ( toType == AT_UNKNOWN ) + { + toType = fromType; + } + + CDmAttribute *pToAttr = pToElement->AddAttribute( pToAttrName, toType ); + if ( !pToAttr ) + { + Warning( "*** Problem in converter encountered!\n" ); + Warning( "*** Unable to find or add attribute \"%s\" to element \"%s\"!\n", pToAttrName, pToElement->GetName() ); + } + else if ( fromType != toType ) + { + Warning( "*** Problem in file encountered!\n" ); + Warning( "*** Element \"%s\" has attribute \"%s\" with an unexpected type!\n", pFromElement->GetName(), pFromAttrName ); + } + else + { + pToAttr->SetValue( toType, pValue ); + } + } + + pFromElement->RemoveAttribute( pFromAttrName ); +} + +// Fixes up all elements +//----------------------------------------------------------------------------- +void CImportSFMV3::FixupElement( CDmElement *pElement ) +{ + if ( !pElement ) + return; + + const char *pType = pElement->GetTypeString(); + + // log layer + if ( IsLogLayerType( pType ) ) + { + pElement->RemoveAttribute( "ownerlog" ); + return; + } + + // log + const char *pCurveInfoType = GetCurveInfoTypeFromLogType( pType ); + if ( !pCurveInfoType ) + return; + + CDmElement *pCurveInfo = NULL; + CDmAttribute *pUseCurveTypeAttr = pElement->GetAttribute( "usecurvetypes" ); + if ( pUseCurveTypeAttr && pUseCurveTypeAttr->GetValue<bool>() ) + { + DmElementHandle_t hElement = g_pDataModel->CreateElement( "curve info", pCurveInfoType, pElement->GetFileId() ); + pCurveInfo = g_pDataModel->GetElement( hElement ); + } + pElement->RemoveAttribute( "usecurvetypes" ); + + MoveAttribute( pElement, "defaultcurvetype", pCurveInfo, "defaultCurveType", AT_INT ); + MoveAttribute( pElement, "defaultedgezerovalue",pCurveInfo, "defaultEdgeZeroValue" ); + MoveAttribute( pElement, "useedgeinfo", pCurveInfo, "useEdgeInfo", AT_BOOL ); + MoveAttribute( pElement, "rightedgetime", pCurveInfo, "rightEdgeTime", AT_INT ); + MoveAttribute( pElement, "left_edge_active", pCurveInfo, "leftEdgeActive", AT_BOOL ); + MoveAttribute( pElement, "right_edge_active", pCurveInfo, "rightEdgeActive", AT_BOOL ); + MoveAttribute( pElement, "left_edge_curvetype", pCurveInfo, "leftEdgeCurveType", AT_INT ); + MoveAttribute( pElement, "right_edge_curvetype",pCurveInfo, "rightEdgeCurveType", AT_INT ); + MoveAttribute( pElement, "left_edge_value", pCurveInfo, "leftEdgeValue" ); + MoveAttribute( pElement, "right_edge_value", pCurveInfo, "rightEdgeValue" ); +} + +// Fixes up all elements +//----------------------------------------------------------------------------- +void CImportSFMV3::BuildList( CDmElement *pElement, CUtlRBTree< CDmElement *, int >& list ) +{ + if ( !pElement ) + return; + + if ( list.Find( pElement ) != list.InvalidIndex() ) + return; + + list.Insert( pElement ); + + // Descend to bottom of tree, then do fixup coming back up the tree + for ( CDmAttribute *pAttribute = pElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() ) + { + if ( pAttribute->GetType() == AT_ELEMENT ) + { + CDmElement *pElementAt = pAttribute->GetValueElement<CDmElement>( ); + BuildList( pElementAt, list ); + continue; + } + + if ( pAttribute->GetType() == AT_ELEMENT_ARRAY ) + { + CDmrElementArray<> array( pAttribute ); + int nCount = array.Count(); + for ( int i = 0; i < nCount; ++i ) + { + CDmElement *pChild = array[ i ]; + BuildList( pChild, list ); + } + continue; + } + } +} + +bool CImportSFMV3::DoFixup( CDmElement *pSourceRoot ) +{ + CUtlRBTree< CDmElement *, int > fixlist( 0, 0, DefLessFunc( CDmElement * ) ); + BuildList( pSourceRoot, fixlist ); + for ( int i = fixlist.FirstInorder(); i != fixlist.InvalidIndex() ; i = fixlist.NextInorder( i ) ) + { + // Search and replace in the entire tree! + FixupElement( fixlist[ i ] ); + } + return true; +} diff --git a/dmserializers/importsfmv4.cpp b/dmserializers/importsfmv4.cpp new file mode 100644 index 0000000..278fe12 --- /dev/null +++ b/dmserializers/importsfmv4.cpp @@ -0,0 +1,123 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "dmserializers.h" +#include "dmebaseimporter.h" +#include "datamodel/idatamodel.h" +#include "datamodel/dmelement.h" +#include "tier1/KeyValues.h" +#include "tier1/utlbuffer.h" +#include "tier1/utlmap.h" +#include <limits.h> + + +//----------------------------------------------------------------------------- +// Format converter +//----------------------------------------------------------------------------- +class CImportSFMV4 : public CSFMBaseImporter +{ + typedef CSFMBaseImporter BaseClass; +public: + CImportSFMV4( char const *formatName, char const *nextFormatName ); + +private: + virtual bool DoFixup( CDmElement *pSourceRoot ); + + + void FixupElement( CDmElement *pElement ); + // Fixes up all elements + void BuildList( CDmElement *pElement, CUtlRBTree< CDmElement *, int >& list ); +}; + + +//----------------------------------------------------------------------------- +// Singleton instance +//----------------------------------------------------------------------------- +static CImportSFMV4 s_ImportSFMV4( "sfm_v4", "sfm_v5" ); + +void InstallSFMV4Importer( IDataModel *pFactory ) +{ + pFactory->AddLegacyUpdater( &s_ImportSFMV4 ); +} + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CImportSFMV4::CImportSFMV4( char const *formatName, char const *nextFormatName ) : + BaseClass( formatName, nextFormatName ) +{ +} + +// Fixes up all elements +//----------------------------------------------------------------------------- +void CImportSFMV4::FixupElement( CDmElement *pElement ) +{ + if ( !pElement ) + return; + + const char *pType = pElement->GetTypeString(); + + if ( !V_stricmp( pType, "DmeCamera" ) ) + { + CDmAttribute *pOldToneMapScaleAttr = pElement->GetAttribute( "toneMapScale" ); + float fNewBloomScale = pOldToneMapScaleAttr->GetValue<float>( ); + + Assert( !pElement->HasAttribute("bloomScale") ); + + CDmAttribute *pNewBloomScaleAttr = pElement->AddAttribute( "bloomScale", AT_FLOAT ); + pNewBloomScaleAttr->SetValue( fNewBloomScale ); + pOldToneMapScaleAttr->SetValue( 1.0f ); + } +} + +// Fixes up all elements +//----------------------------------------------------------------------------- +void CImportSFMV4::BuildList( CDmElement *pElement, CUtlRBTree< CDmElement *, int >& list ) +{ + if ( !pElement ) + return; + + if ( list.Find( pElement ) != list.InvalidIndex() ) + return; + + list.Insert( pElement ); + + // Descend to bottom of tree, then do fixup coming back up the tree + for ( CDmAttribute *pAttribute = pElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() ) + { + if ( pAttribute->GetType() == AT_ELEMENT ) + { + CDmElement *pElementAt = pAttribute->GetValueElement<CDmElement>( ); + BuildList( pElementAt, list ); + continue; + } + + if ( pAttribute->GetType() == AT_ELEMENT_ARRAY ) + { + CDmrElementArray<> array( pAttribute ); + int nCount = array.Count(); + for ( int i = 0; i < nCount; ++i ) + { + CDmElement *pChild = array[ i ]; + BuildList( pChild, list ); + } + continue; + } + } +} + +bool CImportSFMV4::DoFixup( CDmElement *pSourceRoot ) +{ + CUtlRBTree< CDmElement *, int > fixlist( 0, 0, DefLessFunc( CDmElement * ) ); + BuildList( pSourceRoot, fixlist ); + for ( int i = fixlist.FirstInorder(); i != fixlist.InvalidIndex() ; i = fixlist.NextInorder( i ) ) + { + // Search and replace in the entire tree! + FixupElement( fixlist[ i ] ); + } + return true; +} diff --git a/dmserializers/importsfmv5.cpp b/dmserializers/importsfmv5.cpp new file mode 100644 index 0000000..3c3d6db --- /dev/null +++ b/dmserializers/importsfmv5.cpp @@ -0,0 +1,120 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "dmserializers.h" +#include "dmebaseimporter.h" +#include "datamodel/idatamodel.h" +#include "datamodel/dmelement.h" +#include "tier1/KeyValues.h" +#include "tier1/utlbuffer.h" +#include "tier1/utlmap.h" +#include <limits.h> + + +//----------------------------------------------------------------------------- +// Format converter +//----------------------------------------------------------------------------- +class CImportSFMV5 : public CSFMBaseImporter +{ + typedef CSFMBaseImporter BaseClass; +public: + CImportSFMV5( char const *formatName, char const *nextFormatName ); + +private: + virtual bool DoFixup( CDmElement *pSourceRoot ); + + + void FixupElement( CDmElement *pElement ); + // Fixes up all elements + void BuildList( CDmElement *pElement, CUtlRBTree< CDmElement *, int >& list ); +}; + + +//----------------------------------------------------------------------------- +// Singleton instance +//----------------------------------------------------------------------------- +static CImportSFMV5 s_ImportSFMV5( "sfm_v5", "sfm_v6" ); + +void InstallSFMV5Importer( IDataModel *pFactory ) +{ + pFactory->AddLegacyUpdater( &s_ImportSFMV5 ); +} + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CImportSFMV5::CImportSFMV5( char const *formatName, char const *nextFormatName ) : + BaseClass( formatName, nextFormatName ) +{ +} + + +//----------------------------------------------------------------------------- +// Fixes up all elements +//----------------------------------------------------------------------------- +void CImportSFMV5::FixupElement( CDmElement *pElement ) +{ + if ( !pElement ) + return; + + const char *pType = pElement->GetTypeString(); + + if ( !V_stricmp( pType, "DmeSpotLight" ) ) + { + pElement->SetType( "DmeProjectedLight" ); + } +} + + +//----------------------------------------------------------------------------- +// Fixes up all elements +//----------------------------------------------------------------------------- +void CImportSFMV5::BuildList( CDmElement *pElement, CUtlRBTree< CDmElement *, int >& list ) +{ + if ( !pElement ) + return; + + if ( list.Find( pElement ) != list.InvalidIndex() ) + return; + + list.Insert( pElement ); + + // Descend to bottom of tree, then do fixup coming back up the tree + for ( CDmAttribute *pAttribute = pElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() ) + { + if ( pAttribute->GetType() == AT_ELEMENT ) + { + CDmElement *pElementAt = pAttribute->GetValueElement<CDmElement>( ); + BuildList( pElementAt, list ); + continue; + } + + if ( pAttribute->GetType() == AT_ELEMENT_ARRAY ) + { + CDmrElementArray<> array( pAttribute ); + int nCount = array.Count(); + for ( int i = 0; i < nCount; ++i ) + { + CDmElement *pChild = array[ i ]; + BuildList( pChild, list ); + } + continue; + } + } +} + +bool CImportSFMV5::DoFixup( CDmElement *pSourceRoot ) +{ + CUtlRBTree< CDmElement *, int > fixlist( 0, 0, DefLessFunc( CDmElement * ) ); + BuildList( pSourceRoot, fixlist ); + for ( int i = fixlist.FirstInorder(); i != fixlist.InvalidIndex() ; i = fixlist.NextInorder( i ) ) + { + // Search and replace in the entire tree! + FixupElement( fixlist[ i ] ); + } + return true; +} diff --git a/dmserializers/importsfmv6.cpp b/dmserializers/importsfmv6.cpp new file mode 100644 index 0000000..bcceaa1 --- /dev/null +++ b/dmserializers/importsfmv6.cpp @@ -0,0 +1,140 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "dmserializers.h" +#include "dmebaseimporter.h" +#include "datamodel/idatamodel.h" +#include "datamodel/dmelement.h" +#include "tier1/KeyValues.h" +#include "tier1/utlbuffer.h" +#include "tier1/utlmap.h" +#include <limits.h> + + +//----------------------------------------------------------------------------- +// Format converter +//----------------------------------------------------------------------------- +class CImportSFMV6 : public CSFMBaseImporter +{ + typedef CSFMBaseImporter BaseClass; +public: + CImportSFMV6( char const *formatName, char const *nextFormatName ); + +private: + virtual bool DoFixup( CDmElement *pSourceRoot ); + + Quaternion DirectionToOrientation( const Vector &dir ); + + void FixupElement( CDmElement *pElement ); + // Fixes up all elements + void BuildList( CDmElement *pElement, CUtlRBTree< CDmElement *, int >& list ); +}; + + +//----------------------------------------------------------------------------- +// Singleton instance +//----------------------------------------------------------------------------- +static CImportSFMV6 s_ImportSFMV6( "sfm_v6", "sfm_v7" ); + +void InstallSFMV6Importer( IDataModel *pFactory ) +{ + pFactory->AddLegacyUpdater( &s_ImportSFMV6 ); +} + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CImportSFMV6::CImportSFMV6( char const *formatName, char const *nextFormatName ) : + BaseClass( formatName, nextFormatName ) +{ +} + +Quaternion CImportSFMV6::DirectionToOrientation( const Vector &dir ) +{ + Vector up( 0, 0, 1 ); + Vector right = CrossProduct( dir, up ); + if ( right.IsLengthLessThan( 0.001f ) ) + { + up.Init( 1, 0, 0 ); + right = CrossProduct( dir, up ); + } + right.NormalizeInPlace(); + up = CrossProduct( right, dir ); + + Quaternion q; + BasisToQuaternion( dir, right, up, q ); + return q; +} + +//----------------------------------------------------------------------------- +// Fixes up all elements +//----------------------------------------------------------------------------- +void CImportSFMV6::FixupElement( CDmElement *pElement ) +{ + if ( !pElement ) + return; + + const char *pType = pElement->GetTypeString(); + + if ( !V_stricmp( pType, "DmeProjectedLight" ) ) + { + Vector vDir = pElement->GetValue<Vector>( "direction" ); + pElement->RemoveAttribute( "direction" ); + Quaternion q = DirectionToOrientation( vDir ); + pElement->SetValue<Quaternion>( "orientation", q ); + } +} + + +//----------------------------------------------------------------------------- +// Fixes up all elements +//----------------------------------------------------------------------------- +void CImportSFMV6::BuildList( CDmElement *pElement, CUtlRBTree< CDmElement *, int >& list ) +{ + if ( !pElement ) + return; + + if ( list.Find( pElement ) != list.InvalidIndex() ) + return; + + list.Insert( pElement ); + + // Descend to bottom of tree, then do fixup coming back up the tree + for ( CDmAttribute *pAttribute = pElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() ) + { + if ( pAttribute->GetType() == AT_ELEMENT ) + { + CDmElement *pElementAt = pAttribute->GetValueElement<CDmElement>( ); + BuildList( pElementAt, list ); + continue; + } + + if ( pAttribute->GetType() == AT_ELEMENT_ARRAY ) + { + CDmrElementArray<> array( pAttribute ); + int nCount = array.Count(); + for ( int i = 0; i < nCount; ++i ) + { + CDmElement *pChild = array[ i ]; + BuildList( pChild, list ); + } + continue; + } + } +} + +bool CImportSFMV6::DoFixup( CDmElement *pSourceRoot ) +{ + CUtlRBTree< CDmElement *, int > fixlist( 0, 0, DefLessFunc( CDmElement * ) ); + BuildList( pSourceRoot, fixlist ); + for ( int i = fixlist.FirstInorder(); i != fixlist.InvalidIndex() ; i = fixlist.NextInorder( i ) ) + { + // Search and replace in the entire tree! + FixupElement( fixlist[ i ] ); + } + return true; +} diff --git a/dmserializers/importsfmv7.cpp b/dmserializers/importsfmv7.cpp new file mode 100644 index 0000000..a66bf18 --- /dev/null +++ b/dmserializers/importsfmv7.cpp @@ -0,0 +1,144 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "dmserializers.h" +#include "dmebaseimporter.h" +#include "datamodel/idatamodel.h" +#include "datamodel/dmelement.h" +#include "tier1/KeyValues.h" +#include "tier1/utlbuffer.h" +#include "tier1/utlmap.h" +#include <limits.h> + + +//----------------------------------------------------------------------------- +// Format converter +//----------------------------------------------------------------------------- +class CImportSFMV7 : public CSFMBaseImporter +{ + typedef CSFMBaseImporter BaseClass; +public: + CImportSFMV7( char const *formatName, char const *nextFormatName ); + +private: + virtual bool DoFixup( CDmElement *pSourceRoot ); + + + void FixupElement( CDmElement *pElement ); + // Fixes up all elements + void BuildList( CDmElement *pElement, CUtlRBTree< CDmElement *, int >& list ); +}; + + +//----------------------------------------------------------------------------- +// Singleton instance +//----------------------------------------------------------------------------- +static CImportSFMV7 s_ImportSFMV7( "sfm_v7", "sfm_v8" ); + +void InstallSFMV7Importer( IDataModel *pFactory ) +{ + pFactory->AddLegacyUpdater( &s_ImportSFMV7 ); +} + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CImportSFMV7::CImportSFMV7( char const *formatName, char const *nextFormatName ) : + BaseClass( formatName, nextFormatName ) +{ +} + + +//----------------------------------------------------------------------------- +// Fixes up all elements +//----------------------------------------------------------------------------- +void CImportSFMV7::FixupElement( CDmElement *pElement ) +{ + if ( !pElement ) + return; + + const char *pType = pElement->GetTypeString(); + + if ( !V_stricmp( pType, "DmeAnimationSet" ) ) + { + // Add a level of indirection in animation sets + // Modify the type of all controls from DmElement to DmeAnimationSetControl + CDmrElementArray<> srcPresets( pElement, "presets" ); + if ( srcPresets.IsValid() ) + { + CDmrElementArray<> presetGroupArray( pElement, "presetGroups", true ); + CDmElement *pPresetGroup = CreateElement< CDmElement >( "custom", pElement->GetFileId() ); + pPresetGroup->SetType( "DmePresetGroup" ); + CDmrElementArray<> presets( pPresetGroup, "presets", true ); + presetGroupArray.AddToTail( pPresetGroup ); + + int nCount = srcPresets.Count(); + for ( int i = 0; i < nCount; ++i ) + { + CDmElement *pPreset = srcPresets[i]; + if ( pPreset ) + { + pPreset->SetType( "DmePreset" ); + presets.AddToTail( pPreset ); + } + } + + srcPresets.RemoveAll(); + } + pElement->RemoveAttribute( "presets" ); + } +} + + +//----------------------------------------------------------------------------- +// Fixes up all elements +//----------------------------------------------------------------------------- +void CImportSFMV7::BuildList( CDmElement *pElement, CUtlRBTree< CDmElement *, int >& list ) +{ + if ( !pElement ) + return; + + if ( list.Find( pElement ) != list.InvalidIndex() ) + return; + + list.Insert( pElement ); + + // Descend to bottom of tree, then do fixup coming back up the tree + for ( CDmAttribute *pAttribute = pElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() ) + { + if ( pAttribute->GetType() == AT_ELEMENT ) + { + CDmElement *pElementAt = pAttribute->GetValueElement<CDmElement>( ); + BuildList( pElementAt, list ); + continue; + } + + if ( pAttribute->GetType() == AT_ELEMENT_ARRAY ) + { + CDmrElementArray<> array( pAttribute ); + int nCount = array.Count(); + for ( int i = 0; i < nCount; ++i ) + { + CDmElement *pChild = array[ i ]; + BuildList( pChild, list ); + } + continue; + } + } +} + +bool CImportSFMV7::DoFixup( CDmElement *pSourceRoot ) +{ + CUtlRBTree< CDmElement *, int > fixlist( 0, 0, DefLessFunc( CDmElement * ) ); + BuildList( pSourceRoot, fixlist ); + for ( int i = fixlist.FirstInorder(); i != fixlist.InvalidIndex() ; i = fixlist.NextInorder( i ) ) + { + // Search and replace in the entire tree! + FixupElement( fixlist[ i ] ); + } + return true; +} diff --git a/dmserializers/importsfmv8.cpp b/dmserializers/importsfmv8.cpp new file mode 100644 index 0000000..dda78c8 --- /dev/null +++ b/dmserializers/importsfmv8.cpp @@ -0,0 +1,139 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "dmserializers.h" +#include "dmebaseimporter.h" +#include "datamodel/idatamodel.h" +#include "datamodel/dmelement.h" +#include "tier1/KeyValues.h" +#include "tier1/utlbuffer.h" +#include "tier1/utlmap.h" +#include <limits.h> + + +//----------------------------------------------------------------------------- +// Format converter +//----------------------------------------------------------------------------- +class CImportSFMV8 : public CSFMBaseImporter +{ + typedef CSFMBaseImporter BaseClass; +public: + CImportSFMV8( const char *formatName, const char *nextFormatName ); + +private: + virtual bool DoFixup( CDmElement *pSourceRoot ); + + + void FixupElement( CDmElement *pElement ); + // Fixes up all elements + void BuildList( CDmElement *pElement, CUtlRBTree< CDmElement *, int >& list ); +}; + + +//----------------------------------------------------------------------------- +// Singleton instance +//----------------------------------------------------------------------------- +static CImportSFMV8 s_ImportSFMV8( "sfm_v8", "sfm_v9" ); + +void InstallSFMV8Importer( IDataModel *pFactory ) +{ + pFactory->AddLegacyUpdater( &s_ImportSFMV8 ); +} + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CImportSFMV8::CImportSFMV8( const char *formatName, const char *nextFormatName ) : + BaseClass( formatName, nextFormatName ) +{ +} + + +//----------------------------------------------------------------------------- +// Fixes up all elements +//----------------------------------------------------------------------------- +void CImportSFMV8::FixupElement( CDmElement *pElement ) +{ + if ( !pElement ) + return; + + const char *pType = pElement->GetTypeString(); + + if ( !V_stricmp( pType, "DmeAnimationSet" ) ) + { + // Remove 'midpoint' from all controls, and + // Add 'defaultBalance' and 'defaultMultilevel' to all non-transform controls + CDmrElementArray<> srcControls( pElement, "controls" ); + if ( srcControls.IsValid() ) + { + int nCount = srcControls.Count(); + for ( int i = 0; i < nCount; ++i ) + { + CDmElement *pControl = srcControls[i]; + if ( pControl ) + { + if ( !pControl->GetValue<bool>( "transform" ) ) + { + pControl->InitValue( "defaultBalance", 0.5f ); + pControl->InitValue( "defaultMultilevel", 0.5f ); + pControl->RemoveAttribute( "midpoint" ); + } + } + } + } + } +} + + +//----------------------------------------------------------------------------- +// Fixes up all elements +//----------------------------------------------------------------------------- +void CImportSFMV8::BuildList( CDmElement *pElement, CUtlRBTree< CDmElement *, int >& list ) +{ + if ( !pElement ) + return; + + if ( list.Find( pElement ) != list.InvalidIndex() ) + return; + + list.Insert( pElement ); + + // Descend to bottom of tree, then do fixup coming back up the tree + for ( CDmAttribute *pAttribute = pElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() ) + { + if ( pAttribute->GetType() == AT_ELEMENT ) + { + CDmElement *pElementAt = pAttribute->GetValueElement<CDmElement>( ); + BuildList( pElementAt, list ); + continue; + } + + if ( pAttribute->GetType() == AT_ELEMENT_ARRAY ) + { + CDmrElementArray<> array( pAttribute ); + int nCount = array.Count(); + for ( int i = 0; i < nCount; ++i ) + { + CDmElement *pChild = array[ i ]; + BuildList( pChild, list ); + } + continue; + } + } +} + +bool CImportSFMV8::DoFixup( CDmElement *pSourceRoot ) +{ + CUtlRBTree< CDmElement *, int > fixlist( 0, 0, DefLessFunc( CDmElement * ) ); + BuildList( pSourceRoot, fixlist ); + for ( int i = fixlist.FirstInorder(); i != fixlist.InvalidIndex() ; i = fixlist.NextInorder( i ) ) + { + // Search and replace in the entire tree! + FixupElement( fixlist[ i ] ); + } + return true; +} diff --git a/dmserializers/importsfmv9.cpp b/dmserializers/importsfmv9.cpp new file mode 100644 index 0000000..6a5fbf7 --- /dev/null +++ b/dmserializers/importsfmv9.cpp @@ -0,0 +1,142 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: fixed "color" attribute of lights to be of type Color, rather than Vector4 +// this should have been put in a *long* time ago, but I somehow missed creating the updater between 3 and 4 +// fortunately, since all updates happen on untyped elements, it's reasonably safe to do this out of order +// +//============================================================================= + +#include "dmserializers.h" +#include "dmebaseimporter.h" +#include "datamodel/idatamodel.h" +#include "datamodel/dmelement.h" +#include "tier1/utlbuffer.h" +#include "tier1/utlmap.h" +#include <limits.h> + + +//----------------------------------------------------------------------------- +// Format converter +//----------------------------------------------------------------------------- +class CImportSFMV9 : public CSFMBaseImporter +{ + typedef CSFMBaseImporter BaseClass; +public: + CImportSFMV9( const char *formatName, const char *nextFormatName ); + +private: + virtual bool DoFixup( CDmElement *pSourceRoot ); + + + void FixupElement( CDmElement *pElement ); + // Fixes up all elements + void BuildList( CDmElement *pElement, CUtlRBTree< CDmElement *, int >& list ); +}; + + +//----------------------------------------------------------------------------- +// Singleton instance +//----------------------------------------------------------------------------- +static CImportSFMV9 s_ImportSFMV9( "sfm_v9", "sfm_v10" ); + +void InstallSFMV9Importer( IDataModel *pFactory ) +{ + pFactory->AddLegacyUpdater( &s_ImportSFMV9 ); +} + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CImportSFMV9::CImportSFMV9( const char *formatName, const char *nextFormatName ) : +BaseClass( formatName, nextFormatName ) +{ +} + + +//----------------------------------------------------------------------------- +// Fixes up all elements +//----------------------------------------------------------------------------- +void CImportSFMV9::FixupElement( CDmElement *pElement ) +{ + if ( !pElement ) + return; + + const char *pType = pElement->GetTypeString(); + if ( !V_stricmp( pType, "DmeLight" ) || + !V_stricmp( pType, "DmeDirectionalLight" ) || + !V_stricmp( pType, "DmeProjectedLight" ) || + !V_stricmp( pType, "DmePointLight" ) || + !V_stricmp( pType, "DmeSpotLight" ) || + !V_stricmp( pType, "DmeAmbientLight" ) ) + { + const CDmAttribute *pOldAttr = pElement->GetAttribute( "color", AT_VECTOR4 ); + if ( !pOldAttr ) + return; + + Color color; + + { // scoping this section of code since vecColor is invalid after RemoveAttribute + const Vector4D &vecColor = pOldAttr->GetValue< Vector4D >(); + for ( int i = 0; i < 4; ++i ) + { + color[ i ] = ( int )clamp( vecColor[ i ], 0.0f, 255.0f ); + } + + pElement->RemoveAttribute( "color" ); + } + + CDmAttribute *pNewAttr = pElement->AddAttribute( "color", AT_COLOR ); + pNewAttr->SetValue( color ); + } +} + + +//----------------------------------------------------------------------------- +// Fixes up all elements +//----------------------------------------------------------------------------- +void CImportSFMV9::BuildList( CDmElement *pElement, CUtlRBTree< CDmElement *, int >& list ) +{ + if ( !pElement ) + return; + + if ( list.Find( pElement ) != list.InvalidIndex() ) + return; + + list.Insert( pElement ); + + // Descend to bottom of tree, then do fixup coming back up the tree + for ( CDmAttribute *pAttribute = pElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() ) + { + if ( pAttribute->GetType() == AT_ELEMENT ) + { + CDmElement *pElementAt = pAttribute->GetValueElement<CDmElement>( ); + BuildList( pElementAt, list ); + continue; + } + + if ( pAttribute->GetType() == AT_ELEMENT_ARRAY ) + { + CDmrElementArray<> array( pAttribute ); + int nCount = array.Count(); + for ( int i = 0; i < nCount; ++i ) + { + CDmElement *pChild = array[ i ]; + BuildList( pChild, list ); + } + continue; + } + } +} + +bool CImportSFMV9::DoFixup( CDmElement *pSourceRoot ) +{ + CUtlRBTree< CDmElement *, int > fixlist( 0, 0, DefLessFunc( CDmElement * ) ); + BuildList( pSourceRoot, fixlist ); + for ( int i = fixlist.FirstInorder(); i != fixlist.InvalidIndex() ; i = fixlist.NextInorder( i ) ) + { + // Search and replace in the entire tree! + FixupElement( fixlist[ i ] ); + } + return true; +} diff --git a/dmserializers/importvmf.cpp b/dmserializers/importvmf.cpp new file mode 100644 index 0000000..7f57c6d --- /dev/null +++ b/dmserializers/importvmf.cpp @@ -0,0 +1,629 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "importkeyvaluebase.h" +#include "dmserializers.h" +#include "datamodel/idatamodel.h" +#include "datamodel/dmelement.h" +#include "tier1/KeyValues.h" +#include "tier1/utlbuffer.h" +#include "datamodel/dmattribute.h" + + +//----------------------------------------------------------------------------- +// Serialization class for VMF files (map files) +//----------------------------------------------------------------------------- +class CImportVMF : public CImportKeyValueBase +{ +public: + virtual const char *GetName() const { return "vmf"; } + virtual const char *GetDescription() const { return "Valve Map File"; } + virtual int GetCurrentVersion() const { return 0; } // doesn't store a version + + bool Serialize( CUtlBuffer &outBuf, CDmElement *pRoot ); + CDmElement* UnserializeFromKeyValues( KeyValues *pKeyValues ); + +private: + // Reads a single entity + bool UnserializeEntityKey( CDmAttribute *pEntities, KeyValues *pKeyValues ); + + // Reads entity editor keys + bool UnserializeEntityEditorKey( CDmAttribute *pEditor, KeyValues *pKeyValues ); + + // Reads keys that we currently do nothing with + bool UnserializeUnusedKeys( DmElementHandle_t hOther, KeyValues *pKeyValues ); + + // Writes out all everything other than entities + bool SerializeOther( CUtlBuffer &buf, CDmAttribute *pOther, const char **ppFilter = 0 ); + + // Writes out all entities + bool SerializeEntities( CUtlBuffer &buf, CDmAttribute *pEntities ); + + // Writes out a single attribute recursively + bool SerializeAttribute( CUtlBuffer &buf, CDmAttribute *pAttribute, bool bElementArrays ); + + // Writes entity editor keys + bool SerializeEntityEditorKey( CUtlBuffer &buf, DmElementHandle_t hEditor ); + + // Updates the max hammer id + void UpdateMaxHammerId( KeyValues *pKeyValue ); + + // Max id read from the file + int m_nMaxHammerId; +}; + + +//----------------------------------------------------------------------------- +// Singleton instance +//----------------------------------------------------------------------------- +static CImportVMF s_ImportVMF; + +void InstallVMFImporter( IDataModel *pFactory ) +{ + pFactory->AddSerializer( &s_ImportVMF ); +} + + +//----------------------------------------------------------------------------- +// Deals with poorly-named key values for the DME system +//----------------------------------------------------------------------------- +static const char *s_pKeyRemapNames[][2] = +{ + { "id", "__id" }, + { "name", "__name" }, + { "type", "__type" }, + { NULL, NULL }, +}; + + +//----------------------------------------------------------------------------- +// Gets remap name for unserialization/serailzation +//----------------------------------------------------------------------------- +static const char *GetRemapName( const char *pName, bool bSerialization ) +{ + for ( int i = 0; s_pKeyRemapNames[i][0]; ++i ) + { + if ( !Q_stricmp( pName, s_pKeyRemapNames[i][bSerialization] ) ) + return s_pKeyRemapNames[i][1 - bSerialization]; + } + return pName; +} + + +//----------------------------------------------------------------------------- +// Writes out a single attribute recursively +//----------------------------------------------------------------------------- +bool CImportVMF::SerializeAttribute( CUtlBuffer &buf, CDmAttribute *pAttribute, bool bElementArrays ) +{ + if ( pAttribute->IsFlagSet( FATTRIB_STANDARD | FATTRIB_DONTSAVE ) ) + return true; + + const char *pFieldName = GetRemapName( pAttribute->GetName(), true ); + if ( !Q_stricmp( pFieldName, "editorType" ) ) + return true; + + if ( !IsArrayType( pAttribute->GetType() ) ) + { + if ( !bElementArrays ) + { + buf.Printf( "\"%s\" ", pFieldName ); + if ( pAttribute->GetType() != AT_STRING ) + { + buf.Printf( "\"" ); + } + g_pDataModel->SetSerializationDelimiter( GetCStringCharConversion() ); + pAttribute->Serialize( buf ); + g_pDataModel->SetSerializationDelimiter( NULL ); + if ( pAttribute->GetType() != AT_STRING ) + { + buf.Printf( "\"" ); + } + buf.Printf( "\n" ); + } + } + else + { + if ( bElementArrays ) + { + Assert( pAttribute->GetType() == AT_ELEMENT_ARRAY ); + if ( !SerializeOther( buf, pAttribute ) ) + return false; + } + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Writes out all everything other than entities +//----------------------------------------------------------------------------- +bool CImportVMF::SerializeOther( CUtlBuffer &buf, CDmAttribute *pOther, const char **ppFilter ) +{ + CDmrElementArray<> array( pOther ); + int nCount = array.Count(); + for ( int i = 0; i < nCount; ++i ) + { + CDmElement *pElement = array[i]; + const char *pElementName = pElement->GetName(); + if ( ppFilter ) + { + int j; + for ( j = 0; ppFilter[j]; ++j ) + { + if ( !Q_stricmp( pElementName, ppFilter[j] ) ) + break; + } + + if ( !ppFilter[j] ) + continue; + } + + int nLen = Q_strlen( pElementName ) + 1; + char *pTemp = (char*)_alloca( nLen ); + Q_strncpy( pTemp, pElementName, nLen ); + Q_strlower( pTemp ); + buf.Printf( "%s\n", pTemp ); + buf.Printf( "{\n" ); + buf.PushTab(); + + // Normal attributes first + for( CDmAttribute *pAttribute = pElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() ) + { + if ( !SerializeAttribute( buf, pAttribute, false ) ) + return false; + } + + // Subkeys later + for( CDmAttribute *pAttribute = pElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() ) + { + if ( !SerializeAttribute( buf, pAttribute, true ) ) + return false; + } + + buf.PopTab(); + buf.Printf( "}\n" ); + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Writes entity editor keys +//----------------------------------------------------------------------------- +bool CImportVMF::SerializeEntityEditorKey( CUtlBuffer &buf, DmElementHandle_t hEditor ) +{ + CDmElement *pEditorElement = g_pDataModel->GetElement( hEditor ); + if ( !pEditorElement ) + return true; + + buf.Printf( "editor\n" ); + buf.Printf( "{\n" ); + buf.PushTab(); + + { + CDmAttribute *pAttribute = pEditorElement->GetAttribute( "color" ); + if ( pAttribute ) + { + Color c = pAttribute->GetValue<Color>(); + buf.Printf( "\"color\" \"%d %d %d\"\n", c.r(), c.g(), c.b() ); + } + } + PrintIntAttribute( pEditorElement, buf, "id" ); // FIXME - id is a DmObjectId_t!!! This should never print anything! + PrintStringAttribute( pEditorElement, buf, "comments" ); + PrintBoolAttribute( pEditorElement, buf, "visgroupshown" ); + PrintBoolAttribute( pEditorElement, buf, "visgroupautoshown" ); + + for ( CDmAttribute *pAttribute = pEditorElement->FirstAttribute(); pAttribute != NULL; pAttribute = pAttribute->NextAttribute() ) + { + if ( pAttribute->IsFlagSet( FATTRIB_STANDARD | FATTRIB_DONTSAVE ) ) + continue; + + const char *pKeyName = pAttribute->GetName(); + if ( Q_stricmp( pKeyName, "color" ) && Q_stricmp( pKeyName, "id" ) && + Q_stricmp( pKeyName, "comments" ) && Q_stricmp( pKeyName, "visgroupshown" ) && + Q_stricmp( pKeyName, "visgroupautoshown" ) ) + { + PrintStringAttribute( pEditorElement, buf, pKeyName ); + } + } + + buf.PopTab(); + buf.Printf( "}\n" ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Writes out all entities +//----------------------------------------------------------------------------- +bool CImportVMF::SerializeEntities( CUtlBuffer &buf, CDmAttribute *pEntities ) +{ + // FIXME: Make this serialize in the order in which it appears in the FGD + // to minimize diffs + CDmrElementArray<> array( pEntities ); + + int nCount = array.Count(); + for ( int i = 0; i < nCount; ++i ) + { + CDmElement *pElement = array[i]; + buf.Printf( "entity\n" ); + buf.Printf( "{\n" ); + buf.PushTab(); + buf.Printf( "\"id\" \"%s\"\n", pElement->GetName() ); + + for( CDmAttribute *pAttribute = pElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() ) + { + // Do 'editor' at the end to preserve ordering and not make terrible diffs + if ( !Q_stricmp( pAttribute->GetName(), "editor" ) ) + continue; + + if ( !SerializeAttribute( buf, pAttribute, false ) ) + return false; + } + + for( CDmAttribute *pAttribute = pElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() ) + { + // Do 'editor' at the end to preserve ordering and not make terrible diffs + if ( !Q_stricmp( pAttribute->GetName(), "editor" ) ) + continue; + + if ( !SerializeAttribute( buf, pAttribute, true ) ) + return false; + } + + // Do the 'editor' + CDmAttribute *pEditor = pElement->GetAttribute( "editor" ); + if ( pEditor ) + { + SerializeEntityEditorKey( buf, pEditor->GetValue<DmElementHandle_t>() ); + } + + buf.PopTab(); + buf.Printf( "}\n" ); + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Writes out a new VMF file +//----------------------------------------------------------------------------- +bool CImportVMF::Serialize( CUtlBuffer &buf, CDmElement *pRoot ) +{ + // This is done in this strange way (namely, serializing other twice) to minimize diffs + const char *pOtherFilter1[] = + { + "versioninfo", "visgroups", "viewsettings", "world", NULL + }; + + const char *pOtherFilter2[] = + { + "cameras", "cordon", "hidden", NULL + }; + + CDmAttribute *pOther = pRoot->GetAttribute( "other" ); + if ( pOther && pOther->GetType() == AT_ELEMENT_ARRAY ) + { + if ( !SerializeOther( buf, pOther, pOtherFilter1 ) ) + return false; + } + + // Serialize entities + CDmAttribute *pEntities = pRoot->GetAttribute( "entities" ); + if ( pEntities && pEntities->GetType() == AT_ELEMENT_ARRAY ) + { + if ( !SerializeEntities( buf, pEntities ) ) + return false; + } + + if ( pOther && pOther->GetType() == AT_ELEMENT_ARRAY ) + { + if ( !SerializeOther( buf, pOther, pOtherFilter2 ) ) + return false; + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Updates the max hammer id +//----------------------------------------------------------------------------- +void CImportVMF::UpdateMaxHammerId( KeyValues *pField ) +{ + if ( !Q_stricmp( pField->GetName(), "id" ) ) + { + int nId = atoi( pField->GetString() ); + if ( nId > m_nMaxHammerId ) + { + m_nMaxHammerId = nId; + } + } +} + + +//----------------------------------------------------------------------------- +// Reads entity editor keys +//----------------------------------------------------------------------------- +bool CImportVMF::UnserializeEntityEditorKey( CDmAttribute *pEditorAttribute, KeyValues *pKeyValues ) +{ + CDmElement *pEditor; + DmElementHandle_t hEditor = pEditorAttribute->GetValue<DmElementHandle_t>(); + if ( hEditor == DMELEMENT_HANDLE_INVALID ) + { + pEditor = CreateDmElement( "DmElement", "editor", NULL );; + if ( !pEditor ) + return false; + hEditor = pEditor->GetHandle(); + pEditorAttribute->SetValue( hEditor ); + } + else + { + pEditor = g_pDataModel->GetElement( hEditor ); + } + + int r, g, b; + if ( sscanf( pKeyValues->GetString( "color", "" ), "%d %d %d", &r, &g, &b ) == 3 ) + { + Color c( r, g, b, 255 ); + if ( !pEditor->SetValue( "color", c ) ) + return false; + } + KeyValues *pIdKey = pKeyValues->FindKey( "id" ); + if ( pIdKey ) + { + UpdateMaxHammerId( pIdKey ); + } + AddIntAttribute( pEditor, pKeyValues, "id" ); + AddStringAttribute( pEditor, pKeyValues, "comments" ); + AddBoolAttribute( pEditor, pKeyValues, "visgroupshown" ); + AddBoolAttribute( pEditor, pKeyValues, "visgroupautoshown" ); + + for ( KeyValues *pUserKey = pKeyValues->GetFirstValue(); pUserKey != NULL; pUserKey = pUserKey->GetNextValue() ) + { + const char *pKeyName = pUserKey->GetName(); + if ( Q_stricmp( pKeyName, "color" ) && Q_stricmp( pKeyName, "id" ) && + Q_stricmp( pKeyName, "comments" ) && Q_stricmp( pKeyName, "visgroupshown" ) && + Q_stricmp( pKeyName, "visgroupautoshown" ) ) + { + AddStringAttribute( pEditor, pKeyValues, pKeyName ); + } + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Reads a single entity +//----------------------------------------------------------------------------- +bool CImportVMF::UnserializeEntityKey( CDmAttribute *pEntities, KeyValues *pKeyValues ) +{ + CDmElement *pEntity = CreateDmElement( "DmeVMFEntity", pKeyValues->GetString( "id", "-1" ), NULL ); + if ( !pEntity ) + return false; + + CDmrElementArray<> array( pEntities ); + array.AddToTail( pEntity ); + + // Each act busy needs to have an editortype associated with it so it displays nicely in editors + pEntity->SetValue( "editorType", "vmfEntity" ); + + const char *pClassName = pKeyValues->GetString( "classname", NULL ); + if ( !pClassName ) + return false; + + // Read the actual fields + for ( KeyValues *pField = pKeyValues->GetFirstValue(); pField != NULL; pField = pField->GetNextValue() ) + { + // FIXME: Knowing the FGD here would be useful for type determination. + // Look up the field by name based on class name + // In the meantime, just use the keyvalues type? + char pFieldName[512]; + Q_strncpy( pFieldName, pField->GetName(), sizeof(pFieldName) ); + Q_strlower( pFieldName ); + + // Don't do id: it's used as the name + // Not to mention it's a protected name + if ( !Q_stricmp( pFieldName, "id" ) ) + { + UpdateMaxHammerId( pField ); + continue; + } + + // Type, name, and editortype are protected names + Assert( Q_stricmp( pFieldName, "type" ) && Q_stricmp( pFieldName, "name" ) && Q_stricmp( pFieldName, "editortype" ) ); + + switch( pField->GetDataType() ) + { + case KeyValues::TYPE_INT: + if ( !AddIntAttributeFlags( pEntity, pKeyValues, pFieldName, FATTRIB_USERDEFINED ) ) + return false; + break; + + case KeyValues::TYPE_FLOAT: + if ( !AddFloatAttributeFlags( pEntity, pKeyValues, pFieldName, FATTRIB_USERDEFINED ) ) + return false; + break; + + case KeyValues::TYPE_STRING: + { + const char* pString = pField->GetString(); + if (!pString || !pString[0]) + return false; + + // Look for vectors + Vector4D v; + if ( sscanf( pString, "%f %f %f %f", &v.x, &v.y, &v.z, &v.w ) == 4 ) + { + if ( !pEntity->SetValue( pFieldName, v ) ) + return false; + CDmAttribute *pAttribute = pEntity->GetAttribute( pFieldName ); + pAttribute->AddFlag( FATTRIB_USERDEFINED ); + } + else if ( sscanf( pString, "%f %f %f", &v.x, &v.y, &v.z ) == 3 ) + { + if ( !pEntity->SetValue( pFieldName, v.AsVector3D() ) ) + { + QAngle ang( v.x, v.y, v.z ); + if ( !pEntity->SetValue( pFieldName, ang ) ) + return false; + } + CDmAttribute *pAttribute = pEntity->GetAttribute( pFieldName ); + pAttribute->AddFlag( FATTRIB_USERDEFINED ); + } + else + { + if ( !AddStringAttributeFlags( pEntity, pKeyValues, pFieldName, FATTRIB_USERDEFINED ) ) + return false; + } + } + break; + } + } + + // Read the subkeys + CDmAttribute *pEditor = pEntity->AddAttribute( "editor", AT_ELEMENT ); + CDmrElementArray<> otherKeys( pEntity->AddAttribute( "other", AT_ELEMENT_ARRAY ) ); + for ( KeyValues *pSubKey = pKeyValues->GetFirstTrueSubKey(); pSubKey != NULL; pSubKey = pSubKey->GetNextTrueSubKey() ) + { + bool bOk = false; + if ( !Q_stricmp( pSubKey->GetName(), "editor" ) ) + { + bOk = UnserializeEntityEditorKey( pEditor, pSubKey ); + } + else + { + // We don't currently do anything with the other keys + CDmElement *pOther = CreateDmElement( "DmElement", pSubKey->GetName(), NULL ); + otherKeys.AddToTail( pOther ); + bOk = UnserializeUnusedKeys( pOther->GetHandle(), pSubKey ); + } + + if ( !bOk ) + return false; + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Reads keys that we currently do nothing with +//----------------------------------------------------------------------------- +bool CImportVMF::UnserializeUnusedKeys( DmElementHandle_t hOther, KeyValues *pKeyValues ) +{ + CDmElement *pOther = g_pDataModel->GetElement( hOther ); + + // Read the actual fields + for ( KeyValues *pField = pKeyValues->GetFirstValue(); pField != NULL; pField = pField->GetNextValue() ) + { + UpdateMaxHammerId( pField ); + const char *pFieldName = GetRemapName( pField->GetName(), false ); + pOther->SetValue( pFieldName, pField->GetString() ); + } + + // Read the subkeys + CDmrElementArray<> subKeys( pOther->AddAttribute( "subkeys", AT_ELEMENT_ARRAY ) ); + for ( KeyValues *pSubKey = pKeyValues->GetFirstTrueSubKey(); pSubKey != NULL; pSubKey = pSubKey->GetNextTrueSubKey() ) + { + CDmElement *pSubElement = CreateDmElement( "DmElement", pSubKey->GetName(), NULL ); + subKeys.AddToTail( pSubElement ); + if ( !UnserializeUnusedKeys( pSubElement->GetHandle(), pSubKey ) ) + return false; + } + return true; +} + + +/* +//----------------------------------------------------------------------------- +// Reads the cordon data +//----------------------------------------------------------------------------- +bool CImportVMF::UnserializeCordonKey( IDmAttributeElement *pCordon, KeyValues *pKeyValues ) +{ + DmElementHandle_t hCordon = pCordon->GetValue().Get(); + if ( hCordon == DMELEMENT_HANDLE_INVALID ) + { + hCordon = CreateDmElement( "DmElement", "cordon", NULL ); + if ( hCordon == DMELEMENT_HANDLE_INVALID ) + return false; + pCordon->SetValue( hCordon ); + } + + AddBoolAttribute( hCordon, pKeyValues, "active" ); + + Vector v; + if ( sscanf( pKeyValues->GetString( "mins", "" ), "(%f %f %f)", &v.x, &v.y, &v.z ) == 3 ) + { + if ( !DmElementAddAttribute( hCordon, "mins", v ) ) + return false; + } + if ( sscanf( pKeyValues->GetString( "maxs", "" ), "(%f %f %f)", &v.x, &v.y, &v.z ) == 3 ) + { + if ( !DmElementAddAttribute( hCordon, "maxs", v ) ) + return false; + } + return true; +} +*/ + + +//----------------------------------------------------------------------------- +// Main entry point for the unserialization +//----------------------------------------------------------------------------- +CDmElement* CImportVMF::UnserializeFromKeyValues( KeyValues *pKeyValues ) +{ + m_nMaxHammerId = 0; + + // Create the main element + CDmElement *pElement = CreateDmElement( "DmElement", "VMF", NULL ); + if ( !pElement ) + return NULL; + + // Each vmf needs to have an editortype associated with it so it displays nicely in editors + pElement->SetValue( "editorType", "VMF" ); + + // The VMF is a series of keyvalue blocks; either + // 'entity', 'cameras', 'cordon', 'world', 'versioninfo', or 'viewsettings' + CDmAttribute *pEntityArray = pElement->AddAttribute( "entities", AT_ELEMENT_ARRAY ); + + // All main keys are root keys + CDmrElementArray<> otherKeys( pElement->AddAttribute( "other", AT_ELEMENT_ARRAY ) ); + for ( ; pKeyValues != NULL; pKeyValues = pKeyValues->GetNextKey() ) + { + bool bOk = false; + if ( !Q_stricmp( pKeyValues->GetName(), "entity" ) ) + { + bOk = UnserializeEntityKey( pEntityArray, pKeyValues ); + } + else + { + // We don't currently do anything with + CDmElement *pOther = CreateDmElement( "DmElement", pKeyValues->GetName(), NULL ); + otherKeys.AddToTail( pOther ); + bOk = UnserializeUnusedKeys( pOther->GetHandle(), pKeyValues ); + } + + if ( !bOk ) + { + Warning( "Error importing VMF element %s\n", pKeyValues->GetName() ); + return NULL; + } + } + + // Resolve all element references recursively + RecursivelyResolveElement( pElement ); + + // Add the max id read in from the file to the root entity + pElement->SetValue( "maxHammerId", m_nMaxHammerId ); + + return pElement; +} diff --git a/dmserializers/importvmt.cpp b/dmserializers/importvmt.cpp new file mode 100644 index 0000000..bd29a52 --- /dev/null +++ b/dmserializers/importvmt.cpp @@ -0,0 +1,738 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "importkeyvaluebase.h" +#include "dmserializers.h" +#include "datamodel/idatamodel.h" +#include "datamodel/dmelement.h" +#include "tier1/KeyValues.h" +#include "tier1/utlbuffer.h" +#include "datamodel/dmattribute.h" +#include "filesystem.h" +#include "tier2/tier2.h" + + +//----------------------------------------------------------------------------- +// Serialization class for Key Values +//----------------------------------------------------------------------------- +class CImportVMT : public CImportKeyValueBase +{ +public: + virtual const char *GetName() const { return "vmt"; } + virtual const char *GetDescription() const { return "Valve Material File"; } + virtual int GetCurrentVersion() const { return 0; } // doesn't store a version + + bool Serialize( CUtlBuffer &outBuf, CDmElement *pRoot ); + CDmElement* UnserializeFromKeyValues( KeyValues *pKeyValues ); + +private: + // Unserialize fallbacks + bool UnserializeFallbacks( CDmElement *pRoot, KeyValues *pFallbackKeyValues ); + + // Unserialize proxies + bool UnserializeProxies( CDmElement *pRoot, KeyValues *pKeyValues ); + + // Creates a shader parameter from a key value + bool UnserializeShaderParam( CDmElement *pRoot, KeyValues* pKeyValue ); + + // Creates a matrix material var + bool CreateMatrixMaterialVarFromKeyValue( CDmElement *pRoot, const char *pParamName, const char *pString ); + + // Creates a vector shader parameter + bool CreateVectorMaterialVarFromKeyValue( CDmElement *pRoot, const char *pParamName, const char *pString ); + + // Writes out a single shader parameter + bool SerializeShaderParameter( CUtlBuffer &buf, CDmAttribute *pAttribute ); + + // Writes out all shader parameters + bool SerializeShaderParameters( CUtlBuffer &buf, CDmElement *pRoot ); + + // Writes out all shader fallbacks + bool SerializeFallbacks( CUtlBuffer &buf, CDmElement *pRoot ); + + // Writes out all material proxies + bool SerializeProxies( CUtlBuffer &buf, CDmElement *pRoot ); + + // Handle patch files + void ExpandPatchFile( KeyValues *pKeyValues ); +}; + + +//----------------------------------------------------------------------------- +// Singleton instance +//----------------------------------------------------------------------------- +static CImportVMT s_ImportVMT; + +void InstallVMTImporter( IDataModel *pFactory ) +{ + pFactory->AddSerializer( &s_ImportVMT ); +} + + +//----------------------------------------------------------------------------- +// Writes out a single shader parameter +//----------------------------------------------------------------------------- +bool CImportVMT::SerializeShaderParameter( CUtlBuffer &buf, CDmAttribute *pAttribute ) +{ + // We have a shader parameter at this point. + switch ( pAttribute->GetType() ) + { + case AT_INT: + buf.Printf( "\"%s\" \"%d\"\n", pAttribute->GetName(), pAttribute->GetValue<int>( ) ); + break; + + case AT_BOOL: + buf.Printf( "\"%s\" \"%d\"\n", pAttribute->GetName(), pAttribute->GetValue<bool>( ) ); + break; + + case AT_FLOAT: + buf.Printf( "\"%s\" \"%f\"\n", pAttribute->GetName(), pAttribute->GetValue<float>( ) ); + break; + + case AT_STRING: + buf.Printf( "\"%s\" \"%s\"\n", pAttribute->GetName(), pAttribute->GetValue<CUtlString>( ).Get() ); + break; + + case AT_VECTOR2: + { + const Vector2D &vec = pAttribute->GetValue<Vector2D>( ); + buf.Printf( "\"%s\" \"[ %f %f ]\"\n", pAttribute->GetName(), vec.x, vec.y ); + } + break; + + case AT_VECTOR3: + { + const Vector &vec = pAttribute->GetValue<Vector>( ); + buf.Printf( "\"%s\" \"[ %f %f %f ]\"\n", pAttribute->GetName(), vec.x, vec.y, vec.z ); + } + break; + + case AT_VECTOR4: + { + const Vector4D &vec = pAttribute->GetValue<Vector4D>( ); + buf.Printf( "\"%s\" \"[ %f %f %f %f ]\"\n", pAttribute->GetName(), vec.x, vec.y, vec.z, vec.w ); + } + break; + + case AT_COLOR: + { + // NOTE: VMTs only support 3 component color (no alpha) + const Color &color = pAttribute->GetValue<Color>( ); + buf.Printf( "\"%s\" \"{ %d %d %d }\"\n", pAttribute->GetName(), color.r(), color.g(), color.b() ); + } + break; + + case AT_VMATRIX: + { + const VMatrix &mat = pAttribute->GetValue<VMatrix>( ); + buf.Printf( "\"%s\" \"[ %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f ]\"\n", pAttribute->GetName(), + mat[0][0], mat[0][1], mat[0][2], mat[0][3], + mat[1][0], mat[1][1], mat[1][2], mat[1][3], + mat[2][0], mat[2][1], mat[2][2], mat[2][3], + mat[3][0], mat[3][1], mat[3][2], mat[3][3] ); + } + break; + + default: + Warning( "Attempted to serialize an unsupported shader parameter type %s (%s)\n", + pAttribute->GetName(), g_pDataModel->GetAttributeNameForType( pAttribute->GetType() ) ); + return false; + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Writes out all shader parameters +//----------------------------------------------------------------------------- +bool CImportVMT::SerializeShaderParameters( CUtlBuffer &buf, CDmElement *pRoot ) +{ + for ( CDmAttribute *pAttribute = pRoot->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() ) + { + // Skip the standard attributes + if ( pAttribute->IsFlagSet( FATTRIB_STANDARD ) ) + continue; + + // Skip the shader name + const char *pName = pAttribute->GetName(); + if ( !Q_stricmp( pAttribute->GetName(), "shader" ) ) + continue; + + // Names that don't start with a $ or a % are not shader parameters + if ( pName[0] != '$' && pName[0] != '%' ) + continue; + + // Skip element array children; we'll handle them separately. + if ( pAttribute->GetType() == AT_ELEMENT_ARRAY ) + continue; + + // Write out the shader parameter + if ( !SerializeShaderParameter( buf, pAttribute ) ) + return false; + } + return true; +} + + +//----------------------------------------------------------------------------- +// Writes out all shader fallbacks +//----------------------------------------------------------------------------- +bool CImportVMT::SerializeFallbacks( CUtlBuffer &buf, CDmElement *pRoot ) +{ + if ( !pRoot->HasAttribute( "fallbacks" ) ) + return true; + + CDmAttribute *pFallbacks = pRoot->GetAttribute( "fallbacks" ); + if ( pFallbacks->GetType() != AT_ELEMENT_ARRAY ) + return false; + + CDmrElementArray<> array( pFallbacks ); + int nCount = array.Count(); + for ( int i = 0; i < nCount; ++i ) + { + CDmElement *pFallback = array[i]; + Assert( pFallback ); + + PrintStringAttribute( pFallback, buf, "shader", false, true ); + buf.Printf( "{\n" ); + buf.PushTab(); + if ( !SerializeShaderParameters( buf, pFallback ) ) + return false; + buf.PopTab(); + buf.Printf( "}\n" ); + } + return true; +} + + +//----------------------------------------------------------------------------- +// Writes out all material proxies +//----------------------------------------------------------------------------- +bool CImportVMT::SerializeProxies( CUtlBuffer &buf, CDmElement *pRoot ) +{ + if ( !pRoot->HasAttribute( "proxies" ) ) + return true; + + CDmAttribute *pProxies = pRoot->GetAttribute( "proxies" ); + if ( pProxies->GetType() != AT_ELEMENT_ARRAY ) + return false; + + CDmrElementArray<> array( pProxies ); + int nCount = array.Count(); + if ( nCount == 0 ) + return true; + + buf.Printf( "\"Proxies\"\n" ); + buf.Printf( "{\n" ); + buf.PushTab(); + for ( int i = 0; i < nCount; ++i ) + { + CDmElement *pProxy = array[i]; + Assert( pProxy ); + + PrintStringAttribute( pProxy, buf, "proxyType", false, true ); + buf.Printf( "{\n" ); + buf.PushTab(); + if ( !SerializeShaderParameters( buf, pProxy ) ) + return false; + buf.PopTab(); + buf.Printf( "}\n" ); + } + buf.PopTab(); + buf.Printf( "}\n" ); + return true; +} + + +//----------------------------------------------------------------------------- +// Writes out a new vmt file +//----------------------------------------------------------------------------- +bool CImportVMT::Serialize( CUtlBuffer &buf, CDmElement *pRoot ) +{ + PrintStringAttribute( pRoot, buf, "shader", false, true ); + buf.Printf( "{\n" ); + buf.PushTab(); + + if ( !SerializeShaderParameters( buf, pRoot ) ) + return false; + + if ( !SerializeFallbacks( buf, pRoot ) ) + return false; + + if ( !SerializeProxies( buf, pRoot ) ) + return false; + + buf.PopTab(); + buf.Printf( "}\n" ); + return true; +} + + +//----------------------------------------------------------------------------- +// Parser utilities +//----------------------------------------------------------------------------- +static inline bool IsWhitespace( char c ) +{ + return c == ' ' || c == '\t'; +} + +static inline bool IsEndline( char c ) +{ + return c == '\n' || c == '\0'; +} + +static inline bool IsVector( char const* v ) +{ + while (IsWhitespace(*v)) + { + ++v; + if (IsEndline(*v)) + return false; + } + return *v == '[' || *v == '{'; +} + + +//----------------------------------------------------------------------------- +// Creates a vector material var +//----------------------------------------------------------------------------- +int ParseVectorFromKeyValueString( const char *pParamName, const char* pScan, const char *pMaterialName, float vecVal[4] ) +{ + bool divideBy255 = false; + + // skip whitespace + while( IsWhitespace(*pScan) ) + { + ++pScan; + } + + if( *pScan == '{' ) + { + divideBy255 = true; + } + else + { + Assert( *pScan == '[' ); + } + + // skip the '[' + ++pScan; + int i; + for( i = 0; i < 4; i++ ) + { + // skip whitespace + while( IsWhitespace(*pScan) ) + { + ++pScan; + } + + if( IsEndline(*pScan) || *pScan == ']' || *pScan == '}' ) + { + if (*pScan != ']' && *pScan != '}') + { + Warning( "Warning in .VMT file (%s): no ']' or '}' found in vector key \"%s\".\n" + "Did you forget to surround the vector with \"s?\n", pMaterialName, pParamName ); + } + + // allow for vec2's, etc. + vecVal[i] = 0.0f; + break; + } + + char* pEnd; + + vecVal[i] = strtod( pScan, &pEnd ); + if (pScan == pEnd) + { + Warning( "Error in .VMT file: error parsing vector element \"%s\" in \"%s\"\n", pParamName, pMaterialName ); + return 0; + } + + pScan = pEnd; + } + + if( divideBy255 ) + { + vecVal[0] *= ( 1.0f / 255.0f ); + vecVal[1] *= ( 1.0f / 255.0f ); + vecVal[2] *= ( 1.0f / 255.0f ); + vecVal[3] *= ( 1.0f / 255.0f ); + } + + return i; +} + + +//----------------------------------------------------------------------------- +// Sets shader parameter attributes +//----------------------------------------------------------------------------- +template< class T > +inline bool SetShaderParamAttribute( CDmElement *pElement, const char *pAttributeName, const T &value ) +{ + if ( !pElement ) + return false; + + if ( !pElement->SetValue( pAttributeName, value ) ) + return false; + + CDmAttribute *pAttribute = pElement->GetAttribute( pAttributeName ); + pAttribute->AddFlag( FATTRIB_USERDEFINED ); + return true; +} + +inline bool SetShaderParamAttribute( CDmElement *pElement, const char *pAttributeName, const char *value ) +{ + if ( !pElement ) + return false; + + if ( !pElement->SetValue( pAttributeName, value ) ) + return false; + + CDmAttribute *pAttribute = pElement->GetAttribute( pAttributeName ); + pAttribute->AddFlag( FATTRIB_USERDEFINED ); + return true; +} + + +//----------------------------------------------------------------------------- +// Creates a vector shader parameter +//----------------------------------------------------------------------------- +bool CImportVMT::CreateVectorMaterialVarFromKeyValue( CDmElement *pElement, const char *pParamName, const char *pString ) +{ + Vector4D vecVal; + int nDim = ParseVectorFromKeyValueString( pParamName, pString, FileName(), vecVal.Base() ); + if ( nDim == 0 ) + return false; + + // Create the variable! + switch ( nDim ) + { + case 1: + return SetShaderParamAttribute( pElement, pParamName, vecVal[0] ); + case 2: + return SetShaderParamAttribute( pElement, pParamName, vecVal.AsVector2D() ); + case 3: + return SetShaderParamAttribute( pElement, pParamName, vecVal.AsVector3D() ); + case 4: + return SetShaderParamAttribute( pElement, pParamName, vecVal ); + } + + return false; +} + + +//----------------------------------------------------------------------------- +// Creates a matrix shader parameter +//----------------------------------------------------------------------------- +bool CImportVMT::CreateMatrixMaterialVarFromKeyValue( CDmElement *pElement, const char *pParamName, const char *pScan ) +{ + // Matrices can be specified one of two ways: + // [ # # # # # # # # # # # # # # # # ] + // or + // center # # scale # # rotate # translate # # + + VMatrix mat; + int count = sscanf( pScan, " [ %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f ]", + &mat.m[0][0], &mat.m[0][1], &mat.m[0][2], &mat.m[0][3], + &mat.m[1][0], &mat.m[1][1], &mat.m[1][2], &mat.m[1][3], + &mat.m[2][0], &mat.m[2][1], &mat.m[2][2], &mat.m[2][3], + &mat.m[3][0], &mat.m[3][1], &mat.m[3][2], &mat.m[3][3] ); + if (count == 16) + { + return SetShaderParamAttribute( pElement, pParamName, mat ); + } + + Vector2D scale, center; + float angle; + Vector2D translation; + count = sscanf( pScan, " center %f %f scale %f %f rotate %f translate %f %f", + ¢er.x, ¢er.y, &scale.x, &scale.y, &angle, &translation.x, &translation.y ); + if (count != 7) + return false; + + VMatrix temp; + MatrixBuildTranslation( mat, -center.x, -center.y, 0.0f ); + MatrixBuildScale( temp, scale.x, scale.y, 1.0f ); + MatrixMultiply( temp, mat, mat ); + MatrixBuildRotateZ( temp, angle ); + MatrixMultiply( temp, mat, mat ); + MatrixBuildTranslation( temp, center.x + translation.x, center.y + translation.y, 0.0f ); + MatrixMultiply( temp, mat, mat ); + + // Create the variable! + return SetShaderParamAttribute( pElement, pParamName, mat ); +} + + +//----------------------------------------------------------------------------- +// Creates a shader parameter from a key value +//----------------------------------------------------------------------------- +bool CImportVMT::UnserializeShaderParam( CDmElement *pRoot, KeyValues* pKeyValues ) +{ + char pParamName[512]; + Q_strncpy( pParamName, pKeyValues->GetName(), sizeof(pParamName) ); + Q_strlower( pParamName ); + + switch( pKeyValues->GetDataType() ) + { + case KeyValues::TYPE_INT: + return SetShaderParamAttribute( pRoot, pParamName, pKeyValues->GetInt() ); + + case KeyValues::TYPE_FLOAT: + return SetShaderParamAttribute( pRoot, pParamName, pKeyValues->GetFloat() ); + + case KeyValues::TYPE_STRING: + { + char const* pString = pKeyValues->GetString(); + + // Only valid if it's a texture attribute + if ( !pString || !pString[0] ) + return SetShaderParamAttribute( pRoot, pParamName, pString ); + + // Look for matrices + if ( CreateMatrixMaterialVarFromKeyValue( pRoot, pParamName, pString ) ) + return true; + + // Look for vectors + if ( !IsVector( pString ) ) + return SetShaderParamAttribute( pRoot, pParamName, pString ); + + // Parse the string as a vector... + return CreateVectorMaterialVarFromKeyValue( pRoot, pParamName, pString ); + } + } + + return false; +} + + +//----------------------------------------------------------------------------- +// Unserialize proxies +//----------------------------------------------------------------------------- +bool CImportVMT::UnserializeProxies( CDmElement *pElement, KeyValues *pKeyValues ) +{ + // Create a child element array to contain all material proxies + CDmAttribute *pProxies = pElement->AddAttribute( "proxies", AT_ELEMENT_ARRAY ); + if ( !pProxies ) + return false; + + CDmrElementArray<> array( pProxies ); + + // Proxies are a list of sub-keys, the name is the proxy name, subkeys are values + for ( KeyValues *pProxy = pKeyValues->GetFirstTrueSubKey(); pProxy != NULL; pProxy = pProxy->GetNextTrueSubKey() ) + { + CDmElement *pProxyElement = CreateDmElement( "DmElement", pProxy->GetName(), NULL ); + array.AddToTail( pProxyElement ); + pProxyElement->SetValue( "proxyType", pKeyValues->GetName() ); + pProxyElement->SetValue( "editorType", "vmtProxy" ); + + // Normal keys are proxy parameters + for ( KeyValues *pProxyParam = pProxy->GetFirstValue(); pProxyParam != NULL; pProxyParam = pProxyParam->GetNextValue() ) + { + switch( pProxyParam->GetDataType() ) + { + case KeyValues::TYPE_INT: + pProxyElement->SetValue( pProxyParam->GetName(), pProxyParam->GetInt() ); + return true; + + case KeyValues::TYPE_FLOAT: + pProxyElement->SetValue( pProxyParam->GetName(), pProxyParam->GetFloat() ); + return true; + + case KeyValues::TYPE_STRING: + pProxyElement->SetValue( pProxyParam->GetName(), pProxyParam->GetString() ); + return true; + + default: + Warning( "Unhandled proxy keyvalues type (proxy %s var %s)\n", pProxy->GetName(), pProxyParam->GetName() ); + return false; + } + } + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Unserialize fallbacks +//----------------------------------------------------------------------------- +bool CImportVMT::UnserializeFallbacks( CDmElement *pElement, KeyValues *pFallbackKeyValues ) +{ + // Create a child element array to contain all material proxies + CDmAttribute *pFallbacks = pElement->AddAttribute( "fallbacks", AT_ELEMENT_ARRAY ); + if ( !pFallbacks ) + return false; + + CDmrElementArray<> array( pFallbacks ); + + CDmElement *pFallback = CreateDmElement( "DmElement", pFallbackKeyValues->GetName(), NULL ); + array.AddToTail( pFallback ); + pFallback->SetValue( "editorType", "vmtFallback" ); + + // Normal keys are shader parameters + for ( KeyValues *pShaderParam = pFallbackKeyValues->GetFirstValue(); pShaderParam != NULL; pShaderParam = pShaderParam->GetNextValue() ) + { + if ( !UnserializeShaderParam( pFallback, pShaderParam ) ) + { + Warning( "Error importing vmt shader parameter %s\n", pShaderParam->GetName() ); + return NULL; + } + } + + return true; +} + + +//----------------------------------------------------------------------------- +// VMT parser +//----------------------------------------------------------------------------- +void InsertKeyValues( KeyValues& dst, KeyValues& src, bool bCheckForExistence ) +{ + KeyValues *pSrcVar = src.GetFirstSubKey(); + while( pSrcVar ) + { + if ( !bCheckForExistence || dst.FindKey( pSrcVar->GetName() ) ) + { + switch( pSrcVar->GetDataType() ) + { + case KeyValues::TYPE_STRING: + dst.SetString( pSrcVar->GetName(), pSrcVar->GetString() ); + break; + case KeyValues::TYPE_INT: + dst.SetInt( pSrcVar->GetName(), pSrcVar->GetInt() ); + break; + case KeyValues::TYPE_FLOAT: + dst.SetFloat( pSrcVar->GetName(), pSrcVar->GetFloat() ); + break; + case KeyValues::TYPE_PTR: + dst.SetPtr( pSrcVar->GetName(), pSrcVar->GetPtr() ); + break; + } + } + pSrcVar = pSrcVar->GetNextKey(); + } + + if( bCheckForExistence ) + { + for( KeyValues *pScan = dst.GetFirstTrueSubKey(); pScan; pScan = pScan->GetNextTrueSubKey() ) + { + KeyValues *pTmp = src.FindKey( pScan->GetName() ); + if( !pTmp ) + continue; + // make sure that this is a subkey. + if( pTmp->GetDataType() != KeyValues::TYPE_NONE ) + continue; + InsertKeyValues( *pScan, *pTmp, bCheckForExistence ); + } + } +} + + +//----------------------------------------------------------------------------- +// Handle patch files +//----------------------------------------------------------------------------- +void CImportVMT::ExpandPatchFile( KeyValues *pKeyValues ) +{ + int count = 0; + while( count < 10 && stricmp( pKeyValues->GetName(), "patch" ) == 0 ) + { +// WriteKeyValuesToFile( "patch.txt", keyValues ); + const char *pIncludeFileName = pKeyValues->GetString( "include" ); + if( pIncludeFileName ) + { + KeyValues * includeKeyValues = new KeyValues( "vmt" ); + bool success = includeKeyValues->LoadFromFile( g_pFullFileSystem, pIncludeFileName, IsX360() ? "GAME" : NULL ); + if( success ) + { + KeyValues *pInsertSection = pKeyValues->FindKey( "insert" ); + if( pInsertSection ) + { + InsertKeyValues( *includeKeyValues, *pInsertSection, false ); + } + + KeyValues *pReplaceSection = pKeyValues->FindKey( "replace" ); + if( pReplaceSection ) + { + InsertKeyValues( *includeKeyValues, *pReplaceSection, true ); + } + + *pKeyValues = *includeKeyValues; + includeKeyValues->deleteThis(); + // Could add other commands here, like "delete", "rename", etc. + } + else + { + includeKeyValues->deleteThis(); + return; + } + } + else + { + return; + } + count++; + } + if( count >= 10 ) + { + Warning( "Infinite recursion in patch file?\n" ); + } +} + + +//----------------------------------------------------------------------------- +// Main entry point for the unserialization +//----------------------------------------------------------------------------- +CDmElement* CImportVMT::UnserializeFromKeyValues( KeyValues *pKeyValues ) +{ + ExpandPatchFile( pKeyValues ); + + // Create the main element + CDmElement *pRoot = CreateDmElement( "DmElement", "VMT", NULL ); + if ( !pRoot ) + return NULL; + + // Each material needs to have an editortype associated with it so it displays nicely in editors + pRoot->SetValue( "editorType", "vmt" ); + + // Each material needs a proxy list and a fallback list + if ( !pRoot->AddAttribute( "proxies", AT_ELEMENT_ARRAY ) ) + return NULL; + if ( !pRoot->AddAttribute( "fallbacks", AT_ELEMENT_ARRAY ) ) + return NULL; + + // The keyvalues name is the shader name + pRoot->SetValue( "shader", pKeyValues->GetName() ); + + // Normal keys are shader parameters + for ( KeyValues *pShaderParam = pKeyValues->GetFirstValue(); pShaderParam != NULL; pShaderParam = pShaderParam->GetNextValue() ) + { + if ( !UnserializeShaderParam( pRoot, pShaderParam ) ) + { + Warning( "Error importing vmt shader parameter %s\n", pShaderParam->GetName() ); + return NULL; + } + } + + // Subkeys are either proxies or fallbacks + for ( KeyValues *pSubKey = pKeyValues->GetFirstTrueSubKey(); pSubKey != NULL; pSubKey = pSubKey->GetNextTrueSubKey() ) + { + if ( !Q_stricmp( pSubKey->GetName(), "Proxies" ) ) + { + UnserializeProxies( pRoot, pSubKey ); + } + else + { + UnserializeFallbacks( pRoot, pSubKey ); + } + } + + // Resolve all element references recursively + RecursivelyResolveElement( pRoot ); + + return pRoot; +} |