|
|
//====== Copyright � 1996-2004, Valve Corporation, All rights reserved. =======
//
// Purpose:
//
//=============================================================================
#include "importkeyvaluebase.h"
#include "dmserializers.h"
#include "datamodel/idatamodel.h"
#include "datamodel/dmelement.h"
#include "datamodel/dmattributevar.h"
#include "tier1/KeyValues.h"
#include "tier1/UtlBuffer.h"
#include "datamodel/dmattribute.h"
#include "filesystem.h"
#include "tier2/tier2.h"
#include "materialobjects/amalgtexturevars.h"
//-----------------------------------------------------------------------------
// Serialization class for make sheet files
//-----------------------------------------------------------------------------
class CImportMKS : public IDmSerializer { public: virtual const char *GetName() const { return "mks"; } virtual const char *GetDescription() const { return "Valve Make Sheet File"; } virtual bool IsBinaryFormat() const { return false; } virtual bool StoresVersionInFile() const { return false; } virtual int GetCurrentVersion() const { return 0; } // doesn't store a version
virtual const char *GetImportedFormat() const { return "mks"; } virtual int GetImportedVersion() const { return 1; }
bool Serialize( CUtlBuffer &outBuf, CDmElement *pRoot ); // Read from the UtlBuffer, return true if successful, and return the read-in root in ppRoot.
bool Unserialize( CUtlBuffer &buf, const char *pEncodingName, int nEncodingVersion, const char *pSourceFormatName, int nSourceFormatVersion, DmFileId_t fileid, DmConflictResolution_t idConflictResolution, CDmElement **ppRoot );
private:
CDmElement *CreateDmeAmalgamatedTexture( const char *pName ); CDmElement *CreateDmeSequence( const char *pName ); CDmElement *CreateDmeSequenceFrame( const char *pName ); CDmElement *CreateDmeSheetImage( const char *pImageName );
void SetCurrentSequenceClamp( bool bState );
int ParsePackingMode( char *word ); bool SetPackingMode( int eMode );
int ParseSequenceType( char *word ); bool ValidateSequenceType( int eMode, char *word ); bool CreateNewSequence( int mode );
void ParseFrameImages( CUtlVector<char *> &words, CUtlVector<char *> &outImageNames ); bool CreateNewFrame( CUtlVector<char *> &imageNames, float ftime );
bool ValidateImagePacking( CDmElement *pBitmap, char *pImageName ); CDmElement *FindSequence( CDmrElementArray< CDmElement > &mapsequences, int index ); CDmElement *FindImage( const char *pFrameName ); void AddImage( CDmElement *newSequenceEntry, char *pImageName );
CDmElement *m_pRoot; int m_NumActualLinesRead; CDmElement *m_pCurrentSequence; DmFileId_t m_Fileid;
int m_SequenceCount; };
//-----------------------------------------------------------------------------
// Singleton instance
//-----------------------------------------------------------------------------
static CImportMKS s_ImportMKS;
void InstallMKSImporter( IDataModel *pFactory ) { pFactory->AddSerializer( &s_ImportMKS ); }
//-----------------------------------------------------------------------------
// Writes out a new vmt file
//-----------------------------------------------------------------------------
bool CImportMKS::Serialize( CUtlBuffer &buf, CDmElement *pRoot ) { //PrintStringAttribute( pRoot, buf, "shader", false, true );
buf.Printf( "{\n" ); buf.PushTab();
//if ( !SerializeShaderParameter( buf, pRoot ) )
// return false;
buf.PopTab(); buf.Printf( "}\n" ); return true; }
//--------------------------------------------------
// Helper functions
//--------------------------------------------------
static void ApplyMacros( char * in_buf ) { CUtlVector<char *> Words; V_SplitString( in_buf, " ", Words); if ( ( Words.Count() == 4 ) && (! stricmp( Words[0],"ga_frame") ) ) { // ga_frame frm1 frm2 n -> frame frm1{r=a},frm1{g=a},frm1{b=a},frm2{a=a} n
sprintf( in_buf, "frame %s{r=0},%s{g=a},%s{b=0},%s{a=a} %s", Words[1], Words[1], Words[1], Words[2], Words[3] ); } Words.PurgeAndDeleteElements(); } static char *MoveToStart( char *pLineBuffer ) { // Kill newline '\n'
char *pChop = strchr( pLineBuffer, '\n' ); if ( pChop ) *pChop = 0;
// Kill '//' remove comment lines.
char *comment = Q_strstr( pLineBuffer, "//" ); if ( comment ) *comment = 0;
// Move to start of non-whitespace
char *in_str = pLineBuffer; while( ( in_str[0]==' ' ) || ( in_str[0]=='\t') ) in_str++;
return in_str; }
//--------------------------------------------------
// Parse out the packing mode
//--------------------------------------------------
int CImportMKS::ParsePackingMode( char *word ) { // Read in the packing mode requested.
int eRequestedMode = PCKM_INVALID;
if ( !stricmp( word, "flat" ) || !stricmp( word, "rgba" ) ) { eRequestedMode = PCKM_FLAT; } else if ( !stricmp( word, "rgb+a" ) ) { eRequestedMode = PCKM_RGB_A; } if ( eRequestedMode == PCKM_INVALID ) { Warning( "*** line %d: invalid packmode specified, allowed values are 'rgba' or 'rgb+a'!\n", m_NumActualLinesRead ); }
return eRequestedMode; }
//--------------------------------------------------
// Parse out the sequence type
//--------------------------------------------------
int CImportMKS::ParseSequenceType( char *word ) { int eMode = SQM_ALPHA_INVALID;
char const *szSeqType = StringAfterPrefix( word, "sequence" ); if ( !stricmp( szSeqType, "" ) || !stricmp( szSeqType, "-rgba" ) ) { eMode = SQM_RGBA; } else if ( !stricmp( szSeqType, "-rgb" ) ) { eMode = SQM_RGB; } else if ( !stricmp( szSeqType, "-a" ) ) { eMode = SQM_ALPHA; } else { Warning( "*** line %d: invalid sequence type '%s', allowed 'sequence-rgba' or 'sequence-rgb' or 'sequence-a'!\n", m_NumActualLinesRead, word ); }
return eMode; }
//--------------------------------------------------
// Functions to set attribute values
//--------------------------------------------------
void CImportMKS::SetCurrentSequenceClamp( bool bState ) { Warning( "Attempting to set clamp when there is no current sequence!\n" ); if ( m_pCurrentSequence ) { CDmAttribute *pClamp= m_pCurrentSequence->GetAttribute( "clamp" ); Assert( pClamp ); pClamp->SetValue< bool >( bState ); } }
bool CImportMKS::SetPackingMode( int eMode ) { CDmAttribute *pCurrentPackingModeAttr = m_pRoot->GetAttribute( "packmode" ); Assert( pCurrentPackingModeAttr ); int currentPackingMode = pCurrentPackingModeAttr->GetValue< int >();
CDmrElementArray< CDmElement > sequences( m_pRoot, "sequences", true );
// Assign the packing mode read in to member var.
if ( !sequences.Count() ) { pCurrentPackingModeAttr->SetValue< int >( eMode ); } else if ( currentPackingMode != eMode ) { // Allow special changes:
// flat -> rgb+a
if ( currentPackingMode == PCKM_FLAT && eMode == PCKM_RGB_A ) { Msg( "Warning changing packing mode when %d sequences already defined. This may not be serialized correctly.\n", sequences.Count() ); pCurrentPackingModeAttr->SetValue< int >( eMode ); } // everything else
else { Msg( "*** line error: incompatible packmode change when %d sequences already defined!\n", sequences.Count() ); return false; } }
return true; }
//--------------------------------------------------
// Validation
//--------------------------------------------------
bool CImportMKS::ValidateSequenceType( int eMode, char *word ) { CDmAttribute *pCurrentPackingModeAttr = m_pRoot->GetAttribute( "packmode" ); Assert( pCurrentPackingModeAttr ); int currentPackingMode = pCurrentPackingModeAttr->GetValue< int >();
switch ( currentPackingMode ) { case PCKM_FLAT: switch ( eMode ) { case SQM_RGBA: break; default: Msg( "*** line error: invalid sequence type '%s', packing 'flat' allows only 'sequence-rgba'!\n", word ); return false; } break; case PCKM_RGB_A: switch ( eMode ) { case SQM_RGB: case SQM_ALPHA: break; default: return false; } break; default: Warning( "Invalid packing mode!" ); return false; }
return true; }
//--------------------------------------------------
// Validate that image packing is correct
//--------------------------------------------------
bool CImportMKS::ValidateImagePacking( CDmElement *pBitmap, char *pImageName ) { CDmAttribute *pCurrentPackingModeAttr = m_pRoot->GetAttribute( "packmode" ); Assert( pCurrentPackingModeAttr ); int currentPackingMode = pCurrentPackingModeAttr->GetValue< int >();
if ( currentPackingMode == PCKM_RGB_A ) { CDmrElementArray< CDmElement > mapsequences( pBitmap, "mapsequences", true ); for ( uint16 idx = 0; idx < mapsequences.Count(); ++idx ) { CDmElement *pSeq = FindSequence( mapsequences, idx );
Assert( pSeq );
CDmAttribute *pSequenceNumberAttr = pSeq->GetAttribute( "sequencenumber" ); Assert( pSequenceNumberAttr ); int sequenceNumber = pSequenceNumberAttr->GetValue<int>();
CDmAttribute *pModeAttr = pSeq->GetAttribute( "mode" ); Assert( pModeAttr ); int mode = pModeAttr->GetValue<int>();
CDmAttribute *pCurrentSequenceNumberAttr = m_pCurrentSequence->GetAttribute( "sequencenumber" ); Assert( pCurrentSequenceNumberAttr ); int currentSequenceNumber = pCurrentSequenceNumberAttr->GetValue<int>();
CDmAttribute *pCurrentModeAttr = m_pCurrentSequence->GetAttribute( "mode" ); Assert( pCurrentModeAttr ); int currentMode = pCurrentModeAttr->GetValue<int>();
if ( ( mode != SQM_RGBA ) && ( mode != currentMode ) ) { Msg( "*** line error: 'rgb+a' packing cannot pack image '%s' belonging to sequences %d and %d!\n", pImageName, sequenceNumber, currentSequenceNumber );
return false; } } }
return true; }
//--------------------------------------------------
// Functions to create dme elements
//--------------------------------------------------
CDmElement *CImportMKS::CreateDmeAmalgamatedTexture( const char *pName ) { DmElementHandle_t hElement = g_pDataModel->CreateElement( "DmeAmalgamatedTexture", "CDmeAmalgamatedTexture", m_Fileid ); if ( hElement == DMELEMENT_HANDLE_INVALID ) { Warning( "Element uses unknown element type %s\n", "CDmeAmalgamatedTexture" ); return NULL; }
CDmElement *pElement = g_pDataModel->GetElement( hElement ); if ( !pElement ) return NULL;
// Base members
if ( !pElement->AddAttribute( "images", AT_ELEMENT_ARRAY ) ) return NULL; if ( !pElement->AddAttribute( "packmode", AT_INT ) ) return NULL; if ( !pElement->AddAttribute( "width", AT_INT ) ) return NULL; if ( !pElement->AddAttribute( "height", AT_INT ) ) return NULL;
return pElement; }
CDmElement *CImportMKS::CreateDmeSequence( const char *pName ) { DmElementHandle_t hElement = g_pDataModel->CreateElement( "DmeSheetSequence", pName, m_Fileid ); if ( hElement == DMELEMENT_HANDLE_INVALID ) { Warning( "Element uses unknown element type %s\n", "CDmeSheetSequence" ); return false; }
CDmElement *pElement = g_pDataModel->GetElement( hElement ); if ( !pElement ) return NULL;
if ( !pElement->AddAttribute( "sequencenumber", AT_INT ) ) return false; if ( !pElement->AddAttribute( "clamp", AT_BOOL ) ) return false; if ( !pElement->AddAttribute( "mode", AT_INT ) ) return false; if ( !pElement->AddAttribute( "frames", AT_ELEMENT_ARRAY ) ) return false;
CDmAttribute *pClapAttr = pElement->GetAttribute( "clamp" ); Assert( pClapAttr ); pClapAttr->SetValue< bool >( true );
CDmAttribute *pModeAttr = pElement->GetAttribute( "mode" ); Assert( pModeAttr ); pModeAttr->SetValue< int >( SQM_RGBA );
return pElement; }
CDmElement *CImportMKS::CreateDmeSequenceFrame( const char *pName ) { DmElementHandle_t hElement = g_pDataModel->CreateElement( "DmeSheetSequenceFrame", pName, m_Fileid ); if ( hElement == DMELEMENT_HANDLE_INVALID ) { Warning( "Element uses unknown element type %s\n", "CDmeSheetSequenceFrame" ); return false; }
CDmElement *pElement = g_pDataModel->GetElement( hElement ); if ( !pElement ) return NULL;
if ( !pElement->AddAttribute( "sheetimages", AT_ELEMENT_ARRAY ) ) return false; if ( !pElement->AddAttribute( "displaytime", AT_FLOAT ) ) return false;
return pElement; }
CDmElement *CImportMKS::CreateDmeSheetImage( const char *pImageName ) { DmElementHandle_t hElement = g_pDataModel->CreateElement( "DmeSheetImage", pImageName, m_Fileid ); if ( hElement == DMELEMENT_HANDLE_INVALID ) { Warning("Element uses unknown element type %s\n", "CDmeSheetImage" ); return false; }
CDmElement *pElement = g_pDataModel->GetElement( hElement ); if ( !pElement ) return NULL;
if ( !pElement->AddAttribute( "xcoord", AT_INT ) ) return NULL; if ( !pElement->AddAttribute( "ycoord", AT_INT ) ) return NULL;
return pElement; }
//---------------------------------------------------------------
// Functions to put this all together
//---------------------------------------------------------------
bool CImportMKS::CreateNewSequence( int mode ) { m_pCurrentSequence = CreateDmeSequence( "CDmeSheetSequence" ); if ( !m_pCurrentSequence ) return false;
CDmAttribute *pSeqNoAttr = m_pCurrentSequence->GetAttribute( "sequencenumber" ); Assert( pSeqNoAttr ); pSeqNoAttr->SetValue< int >( m_SequenceCount ); m_SequenceCount++;
CDmAttribute *pSeqType = m_pCurrentSequence->GetAttribute( "mode" ); Assert( pSeqType ); pSeqType->SetValue< int >( mode );
CDmrElementArray< CDmElement > sequences( m_pRoot, "sequences", true ); sequences.AddToTail( m_pCurrentSequence );
return true; }
bool CImportMKS::CreateNewFrame( CUtlVector<char *> &imageNames, float ftime ) { CDmElement *pNewFrame = CreateDmeSequenceFrame( "CDmeSheetSequenceFrame" ); if ( !pNewFrame ) return false;
CDmAttribute *pDisplayTimeAttr = pNewFrame->GetAttribute( "displaytime" ); Assert( pDisplayTimeAttr ); pDisplayTimeAttr->SetValue< float >( ftime );
for ( int i = 0; i < imageNames.Count(); ++i ) { Assert( imageNames.Count() <= MAX_IMAGES_PER_FRAME ); AddImage( pNewFrame, imageNames[i] ); }
CDmrElementArray< CDmElement > currentFrames( m_pCurrentSequence->GetAttribute( "frames" ) ); currentFrames.AddToTail( pNewFrame );
return true; }
CDmElement *CImportMKS::FindImage( const char *pFrameName ) { CDmrElementArray< CDmElement > images = m_pRoot->GetAttribute( "images" ); int nCount = images.Count(); for ( int i = 0; i < nCount; ++i ) { if ( !Q_stricmp( pFrameName, images[i]->GetName() ) ) return images[i]; } return NULL; }
CDmElement *CImportMKS::FindSequence( CDmrElementArray< CDmElement > &mapsequences, int index ) { if ( index < mapsequences.Count() ) { return mapsequences[index]; } return NULL; }
void CImportMKS::AddImage( CDmElement *pSequenceEntry, char *pImageName ) { // Store the image in the image list, this is a string - bitmap mapping.
CDmElement *pBitmap = FindImage( pImageName ); if ( !pBitmap ) { CDmElement *pBitmap = CreateDmeSheetImage( pImageName ); if ( !pBitmap ) return;
CDmrElementArray< CDmElement > images = m_pRoot->GetAttribute( "images" ); images.AddToTail( pBitmap ); }
pBitmap = FindImage( pImageName ); Assert( pBitmap );
CDmrElementArray< CDmElement > sheetImages = pSequenceEntry->GetAttribute( "sheetimages" ); sheetImages.AddToTail( pBitmap );
if ( !ValidateImagePacking( pBitmap, pImageName ) ) { Warning( "Image packing validation failed!" ); }
CDmrElementArray< CDmElement > mapSequences( pBitmap, "mapsequences", true ); mapSequences.AddToTail( m_pCurrentSequence ); }
void CImportMKS::ParseFrameImages( CUtlVector<char *> &words, CUtlVector<char *> &outImageNames ) { for ( int i = 0; i < words.Count() - 2; i++ ) { char *fnamebuf = words[i+1]; outImageNames.AddToTail( fnamebuf ); } }
//-----------------------------------------------------------------------------
// Main entry point for the unserialization
//-----------------------------------------------------------------------------
bool CImportMKS::Unserialize( CUtlBuffer &buf, const char *pEncodingName, int nEncodingVersion, const char *pSourceFormatName, int nSourceFormatVersion, DmFileId_t fileid, DmConflictResolution_t idConflictResolution, CDmElement **ppRoot ) { *ppRoot = NULL; m_Fileid = fileid;
// Create the main element
m_pRoot = CreateDmeAmalgamatedTexture( "CDmeAmalgamatedTexture" ); if ( !m_pRoot ) return false;
*ppRoot = m_pRoot;
// Initial value for this param
m_SequenceCount = 0; bool bSuccess = SetPackingMode( PCKM_FLAT ); if ( !bSuccess ) return false;
char linebuffer[4096]; m_NumActualLinesRead = 0; while ( buf.IsValid() ) { buf.GetLine( linebuffer, sizeof(linebuffer) ); ++m_NumActualLinesRead;
char *in_str = MoveToStart( linebuffer ); if ( in_str[0] == NULL ) continue;
strlwr( in_str ); // send string to lowercase.
ApplyMacros( in_str ); CUtlVector<char *> words; V_SplitString( in_str, " ", words); if ( ( words.Count() == 1) && ( !stricmp( words[0], "loop" ) ) ) { SetCurrentSequenceClamp( false ); } else if ( ( words.Count() == 2 ) && ( !stricmp( words[0], "packmode" ) ) ) { // Read in the packing mode requested.
int eRequestedMode = ParsePackingMode( words[1] ); if ( ( eRequestedMode == PCKM_INVALID ) || !SetPackingMode( eRequestedMode ) ) { Warning( "Unable to set packing mode." ); return NULL; } } else if ( ( words.Count() == 2) && StringHasPrefix( words[0], "sequence" ) ) { int seq_no = atoi( words[1] ); if ( seq_no != m_SequenceCount ) { Warning( "Sequence number mismatch.\n" ); } // Figure out the sequence type
int mode = ParseSequenceType( words[0] ); if ( ( mode == SQM_ALPHA_INVALID ) || !ValidateSequenceType( mode, words[0] ) ) { Warning( "Invalid sequence type.\n" ); return NULL; } bool bSuccess = CreateNewSequence( mode ); if ( !bSuccess ) { Warning( "Unable to create new sequence.\n" ); return NULL; } } else if ( ( words.Count() >= 3) && (! stricmp( words[0], "frame" ) ) ) { if ( m_pCurrentSequence ) { float ftime = atof( words[ words.Count() - 1 ] ); // Warning( "ftime is %f\n", ftime );
CUtlVector<char *> imageNames; ParseFrameImages( words, imageNames ); bool bSuccess = CreateNewFrame( imageNames, ftime ); if ( !bSuccess ) { Warning( "Unable to create new frame.\n" ); return NULL; } } else { Warning( "Trying to add a frame when there is no current sequence.\n" ); } } else { Warning( "*** line %d: Bad command \"%s\"!\n", m_NumActualLinesRead, in_str ); return NULL; } words.PurgeAndDeleteElements(); }
// Import compiler settings
char pTexFile[MAX_PATH]; const char *pFileName = g_pDataModel->GetFileName( fileid ); Q_strncpy( pTexFile, pFileName, sizeof(pTexFile) ); Q_SetExtension( pTexFile, "txt", sizeof(pTexFile) ); if ( g_pFullFileSystem->FileExists( pTexFile ) ) { CDmElement *pTextureCompileSettings = NULL; if ( !g_pDataModel->RestoreFromFile( pTexFile, NULL, "tex_source1", &pTextureCompileSettings, CR_COPY_NEW ) ) { Warning( "Error reading texture compile settings file \"%s\"!\n", pTexFile ); return NULL; }
pTextureCompileSettings->SetFileId( m_pRoot->GetFileId(), TD_DEEP, true ); m_pRoot->SetValue( "textureCompileSettings", pTextureCompileSettings ); }
return g_pDataModel->UpdateUnserializedElements( pSourceFormatName, nSourceFormatVersion, fileid, idConflictResolution, ppRoot ); }
|