|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "movieobjects/dmeparticlesystemdefinition.h"
#include "datamodel/dmelementfactoryhelper.h"
#include "movieobjects/dmeeditortypedictionary.h"
#include "toolutils/enginetools_int.h"
#include "tier1/KeyValues.h"
#include "tier1/utlbuffer.h"
#include "tier1/convar.h"
#include "particles/particles.h"
#include "dme_controls/attributeintchoicepanel.h"
#include "dme_controls/attributeboolchoicepanel.h"
#include "dme_controls/attributestringchoicepanel.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Human readable string for the particle functions
//-----------------------------------------------------------------------------
static const char *s_pParticleFuncTypeName[PARTICLE_FUNCTION_COUNT] = { "Renderer", // FUNCTION_RENDERER = 0,
"Operator", // FUNCTION_OPERATOR,
"Initializer", // FUNCTION_INITIALIZER,
"Emitter", // FUNCTION_EMITTER,
"Children", // FUNCTION_CHILDREN,
"ForceGenerator", // FUNCTION_FORCEGENERATOR
"Constraint", // FUNCTION_CONSTRAINT
};
const char *GetParticleFunctionTypeName( ParticleFunctionType_t type ) { return s_pParticleFuncTypeName[type]; }
//-----------------------------------------------------------------------------
// Expose this class to the scene database
//-----------------------------------------------------------------------------
IMPLEMENT_ELEMENT_FACTORY_INSTALL_EXPLICITLY( DmeParticleFunction, CDmeParticleFunction );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDmeParticleFunction::OnConstruction() { m_bSkipNextResolve = false; }
void CDmeParticleFunction::OnDestruction() { DestroyElement( m_hTypeDictionary, TD_DEEP ); }
//-----------------------------------------------------------------------------
// Construct an appropriate editor attribute info
//-----------------------------------------------------------------------------
static void CreateEditorAttributeInfo( CDmeEditorType *pEditorType, const char *pAttributeName, const char *pWidgetInfo ) { if ( !pWidgetInfo ) return;
CCommand parse; parse.Tokenize( pWidgetInfo ); if ( parse.ArgC() == 1 ) { CDmeEditorAttributeInfo *pInfo = CreateElement< CDmeEditorAttributeInfo >( "field info" ); pEditorType->AddAttributeInfo( pAttributeName, pInfo ); pInfo->m_Widget = parse[0]; return; }
if ( parse.ArgC() == 2 ) { CDmeEditorChoicesInfo *pInfo = NULL; if ( !Q_stricmp( parse[0], "intchoice" ) ) { pInfo = CreateElement< CDmeEditorIntChoicesInfo >( "field info" ); }
if ( !Q_stricmp( parse[0], "boolchoice" ) ) { pInfo = CreateElement< CDmeEditorBoolChoicesInfo >( "field info" ); }
if ( !Q_stricmp( parse[0], "stringchoice" ) ) { pInfo = CreateElement< CDmeEditorStringChoicesInfo >( "field info" ); }
if ( !Q_stricmp( parse[0], "elementchoice" ) ) { pInfo = CreateElement< CDmeEditorChoicesInfo >( "field info" ); }
if ( pInfo ) { pInfo->SetChoiceType( parse[1] ); pEditorType->AddAttributeInfo( pAttributeName, pInfo ); pInfo->m_Widget = parse[0]; return; } } }
//-----------------------------------------------------------------------------
// Used for backward compat
//-----------------------------------------------------------------------------
void CDmeParticleFunction::AddMissingFields( const DmxElementUnpackStructure_t *pUnpack ) { DestroyElement( m_hTypeDictionary, TD_DEEP ); m_hTypeDictionary = CreateElement< CDmeEditorTypeDictionary >( "particleFunctionDict" ); CDmeEditorType *pEditorType = CreateElement< CDmeEditorType >( GetTypeString() );
for ( ; pUnpack->m_pAttributeName; ++pUnpack ) { CreateEditorAttributeInfo( pEditorType, pUnpack->m_pAttributeName, (const char *)pUnpack->m_pUserData );
// Can happen if 'name' or 'functionName' is used
if ( HasAttribute( pUnpack->m_pAttributeName ) ) continue;
CDmAttribute *pAttribute = AddAttribute( pUnpack->m_pAttributeName, pUnpack->m_AttributeType ); if ( pUnpack->m_pDefaultString ) { int nLen = Q_strlen( pUnpack->m_pDefaultString ); CUtlBuffer bufParse( pUnpack->m_pDefaultString, nLen, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::READ_ONLY ); pAttribute->Unserialize( bufParse ); } }
m_hTypeDictionary->AddEditorType( pEditorType ); }
//-----------------------------------------------------------------------------
// Sets the particle operator
//-----------------------------------------------------------------------------
void CDmeParticleFunction::UpdateAttributes( const DmxElementUnpackStructure_t *pUnpack ) { // Delete all old attributes
CDmAttribute *pNext; for( CDmAttribute *pAttr = FirstAttribute(); pAttr; pAttr = pNext ) { pNext = pAttr->NextAttribute(); if ( pAttr->IsFlagSet( FATTRIB_EXTERNAL | FATTRIB_STANDARD ) ) continue;
RemoveAttributeByPtr( pAttr ); }
AddMissingFields( pUnpack ); }
//-----------------------------------------------------------------------------
// Marks a particle system as a new instance
// This is basically a workaround to prevent newly-copied particle functions
// from recompiling themselves a zillion times
//-----------------------------------------------------------------------------
void CDmeParticleFunction::MarkNewInstance() { m_bSkipNextResolve = true; }
//-----------------------------------------------------------------------------
// Don't bother resolving during unserialization, the owning def will handle it
//-----------------------------------------------------------------------------
void CDmeParticleFunction::OnElementUnserialized() { BaseClass::OnElementUnserialized(); MarkNewInstance(); }
//-----------------------------------------------------------------------------
// Recompiles the particle system when a change occurs
//-----------------------------------------------------------------------------
void CDmeParticleFunction::Resolve() { BaseClass::Resolve();
if ( m_bSkipNextResolve ) { m_bSkipNextResolve = false; return; }
for( CDmAttribute* pAttr = FirstAttribute(); pAttr; pAttr = pAttr->NextAttribute() ) { if ( !pAttr->IsFlagSet( FATTRIB_DIRTY ) ) continue;
// Find all CDmeParticleSystemDefinitions referring to this function
DmAttributeReferenceIterator_t i = g_pDataModel->FirstAttributeReferencingElement( GetHandle() ); while ( i != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID ) { CDmAttribute *pAttribute = g_pDataModel->GetAttribute( i );
// NOTE: This could cause the same particle system definition to recompile
// multiple times if it refers to the same function multiple times,
// but we don't expect that to happen, so we won't bother checking for it
CDmeParticleSystemDefinition *pDef = CastElement<CDmeParticleSystemDefinition>( pAttribute->GetOwner() ); if ( pDef && pDef->GetFileId() == GetFileId() ) { pDef->RecompileParticleSystem(); } i = g_pDataModel->NextAttributeReferencingElement( i ); } break; } }
//-----------------------------------------------------------------------------
// Returns the editor type dictionary
//-----------------------------------------------------------------------------
CDmeEditorTypeDictionary* CDmeParticleFunction::GetEditorTypeDictionary() { return m_hTypeDictionary; }
//-----------------------------------------------------------------------------
// Expose this class to the scene database
//-----------------------------------------------------------------------------
IMPLEMENT_ELEMENT_FACTORY_INSTALL_EXPLICITLY( DmeParticleOperator, CDmeParticleOperator );
//-----------------------------------------------------------------------------
// Constructor, destructor
//-----------------------------------------------------------------------------
void CDmeParticleOperator::OnConstruction() { m_FunctionName.Init( this, "functionName" ); }
void CDmeParticleOperator::OnDestruction() { }
//-----------------------------------------------------------------------------
// Sets the particle operator
//-----------------------------------------------------------------------------
void CDmeParticleOperator::SetFunction( IParticleOperatorDefinition *pDefinition ) { m_FunctionName = pDefinition->GetName(); const DmxElementUnpackStructure_t *pUnpack = pDefinition->GetUnpackStructure(); UpdateAttributes( pUnpack ); }
const char *CDmeParticleOperator::GetFunctionType() const { return m_FunctionName; }
//-----------------------------------------------------------------------------
// Expose this class to the scene database
//-----------------------------------------------------------------------------
IMPLEMENT_ELEMENT_FACTORY_INSTALL_EXPLICITLY( DmeParticleChild, CDmeParticleChild );
//-----------------------------------------------------------------------------
// Constructor, destructor
//-----------------------------------------------------------------------------
void CDmeParticleChild::OnConstruction() { m_Child.Init( this, "child", FATTRIB_NEVERCOPY ); }
void CDmeParticleChild::OnDestruction() { }
//-----------------------------------------------------------------------------
// Sets the particle system child
//-----------------------------------------------------------------------------
void CDmeParticleChild::SetChildParticleSystem( CDmeParticleSystemDefinition *pDef, IParticleOperatorDefinition *pDefinition ) { // FIXME: Convert system name into a
m_Child = pDef; const DmxElementUnpackStructure_t *pUnpack = pDefinition->GetUnpackStructure(); UpdateAttributes( pUnpack ); }
const char *CDmeParticleChild::GetFunctionType() const { const CDmeParticleSystemDefinition *pChild = m_Child; return pChild ? pChild->GetName() : ""; }
//-----------------------------------------------------------------------------
// Expose this class to the scene database
//-----------------------------------------------------------------------------
IMPLEMENT_ELEMENT_FACTORY_INSTALL_EXPLICITLY( DmeParticleSystemDefinition, CDmeParticleSystemDefinition );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDmeParticleSystemDefinition::OnConstruction() { m_ParticleFunction[FUNCTION_RENDERER].Init( this, "renderers" ); m_ParticleFunction[FUNCTION_OPERATOR].Init( this, "operators" ); m_ParticleFunction[FUNCTION_INITIALIZER].Init( this, "initializers" ); m_ParticleFunction[FUNCTION_EMITTER].Init( this, "emitters" ); m_ParticleFunction[FUNCTION_CHILDREN].Init( this, "children" ); m_ParticleFunction[FUNCTION_FORCEGENERATOR].Init( this, "forces" ); m_ParticleFunction[FUNCTION_CONSTRAINT].Init( this, "constraints" ); m_bPreventNameBasedLookup.Init( this, "preventNameBasedLookup" );
m_hTypeDictionary = CreateElement< CDmeEditorTypeDictionary >( "particleSystemDefinitionDict" ); CDmeEditorType *pEditorType = CreateElement< CDmeEditorType >( "DmeParticleSystemDefinition" );
const DmxElementUnpackStructure_t *pUnpack = g_pParticleSystemMgr->GetParticleSystemDefinitionUnpackStructure(); for ( ; pUnpack->m_pAttributeName; ++pUnpack ) { CreateEditorAttributeInfo( pEditorType, pUnpack->m_pAttributeName, (const char *)pUnpack->m_pUserData );
CDmAttribute *pAttribute = AddAttribute( pUnpack->m_pAttributeName, pUnpack->m_AttributeType ); if ( pUnpack->m_pDefaultString ) { int nLen = Q_strlen( pUnpack->m_pDefaultString ); CUtlBuffer bufParse( pUnpack->m_pDefaultString, nLen, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::READ_ONLY ); pAttribute->Unserialize( bufParse ); } }
m_hTypeDictionary->AddEditorType( pEditorType ); }
void CDmeParticleSystemDefinition::OnDestruction() { DestroyElement( m_hTypeDictionary, TD_DEEP ); }
//-----------------------------------------------------------------------------
// Returns the editor type dictionary
//-----------------------------------------------------------------------------
CDmeEditorTypeDictionary* CDmeParticleSystemDefinition::GetEditorTypeDictionary() { return m_hTypeDictionary; }
//-----------------------------------------------------------------------------
// Remove obsolete attributes
//-----------------------------------------------------------------------------
static void RemoveObsoleteAttributes( CDmElement *pElement, const DmxElementUnpackStructure_t *pUnpack ) { // Delete all obsolete attributes
CDmAttribute *pNext; for( CDmAttribute *pAttr = pElement->FirstAttribute(); pAttr; pAttr = pNext ) { pNext = pAttr->NextAttribute(); if ( pAttr->IsFlagSet( FATTRIB_EXTERNAL | FATTRIB_STANDARD ) ) continue;
bool bFound = false; for ( const DmxElementUnpackStructure_t *pTrav = pUnpack; pTrav->m_pAttributeName; ++pTrav ) { if ( !Q_stricmp( pTrav->m_pAttributeName, pAttr->GetName() ) ) { bFound = true; break; } }
if ( !bFound ) { pElement->RemoveAttributeByPtr( pAttr ); } } }
//-----------------------------------------------------------------------------
// Used for automatic handling of backward compatability
//-----------------------------------------------------------------------------
void CDmeParticleSystemDefinition::OnElementUnserialized() { BaseClass::OnElementUnserialized();
RemoveObsoleteAttributes( this, g_pParticleSystemMgr->GetParticleSystemDefinitionUnpackStructure() );
// Add missing fields that are new
for ( int i = 0; i < PARTICLE_FUNCTION_COUNT; ++i ) { ParticleFunctionType_t type = (ParticleFunctionType_t)i; CUtlVector< IParticleOperatorDefinition *> &list = g_pParticleSystemMgr->GetAvailableParticleOperatorList( type ); int nAvailType = list.Count(); int nCount = GetParticleFunctionCount( type ); for ( int j = 0; j < nCount; ++j ) { CDmeParticleFunction *pFunction = GetParticleFunction( type, j );
if ( i == FUNCTION_CHILDREN ) { RemoveObsoleteAttributes( pFunction, list[0]->GetUnpackStructure() ); pFunction->AddMissingFields( list[0]->GetUnpackStructure() ); continue; }
for ( int k = 0; k < nAvailType; ++k ) { if ( Q_stricmp( pFunction->GetName(), list[k]->GetName() ) ) continue;
RemoveObsoleteAttributes( pFunction, list[k]->GetUnpackStructure() ); pFunction->AddMissingFields( list[k]->GetUnpackStructure() ); break; } } } }
//-----------------------------------------------------------------------------
// Check to see if any attributes changed
//-----------------------------------------------------------------------------
void CDmeParticleSystemDefinition::Resolve() { BaseClass::Resolve(); for( CDmAttribute* pAttr = FirstAttribute(); pAttr; pAttr = pAttr->NextAttribute() ) { if ( pAttr->IsFlagSet( FATTRIB_DIRTY ) ) { RecompileParticleSystem(); break; } } }
//-----------------------------------------------------------------------------
// Add, remove
//-----------------------------------------------------------------------------
CDmeParticleFunction* CDmeParticleSystemDefinition::AddOperator( ParticleFunctionType_t type, const char *pFunctionName ) { CUtlVector< IParticleOperatorDefinition *> &list = g_pParticleSystemMgr->GetAvailableParticleOperatorList( type );
int nCount = list.Count(); for ( int i = 0; i < nCount; ++i ) { if ( Q_stricmp( pFunctionName, list[i]->GetName() ) ) continue;
CDmeParticleOperator *pFunction = CreateElement< CDmeParticleOperator >( pFunctionName, GetFileId() ); m_ParticleFunction[type].AddToTail( pFunction ); pFunction->SetFunction( list[i] ); return pFunction; } return NULL; }
CDmeParticleFunction* CDmeParticleSystemDefinition::AddChild( CDmeParticleSystemDefinition *pChild ) { Assert( pChild );
CUtlVector< IParticleOperatorDefinition *> &list = g_pParticleSystemMgr->GetAvailableParticleOperatorList( FUNCTION_CHILDREN ); Assert( list.Count() == 1 ); CDmeParticleChild *pFunction = CreateElement< CDmeParticleChild >( pChild->GetName(), GetFileId() ); m_ParticleFunction[FUNCTION_CHILDREN].AddToTail( pFunction ); pFunction->SetChildParticleSystem( pChild, list[0] ); return pFunction; }
//-----------------------------------------------------------------------------
// Remove
void CDmeParticleSystemDefinition::RemoveFunction( ParticleFunctionType_t type, CDmeParticleFunction *pFunction ) { int nIndex = FindFunction( type, pFunction ); RemoveFunction( type, nIndex ); }
void CDmeParticleSystemDefinition::RemoveFunction( ParticleFunctionType_t type, int nIndex ) { if ( nIndex >= 0 ) { m_ParticleFunction[type].Remove(nIndex); } }
//-----------------------------------------------------------------------------
// Find
//-----------------------------------------------------------------------------
int CDmeParticleSystemDefinition::FindFunction( ParticleFunctionType_t type, CDmeParticleFunction *pParticleFunction ) { int nCount = m_ParticleFunction[type].Count(); for ( int i = 0; i < nCount; ++i ) { if ( pParticleFunction == m_ParticleFunction[type][i] ) return i; } return -1; }
int CDmeParticleSystemDefinition::FindFunction( ParticleFunctionType_t type, const char *pFunctionName ) { int nCount = m_ParticleFunction[type].Count(); for ( int i = 0; i < nCount; ++i ) { if ( !Q_stricmp( pFunctionName, m_ParticleFunction[type][i]->GetFunctionType() ) ) return i; } return -1; }
//-----------------------------------------------------------------------------
// Iteration
//-----------------------------------------------------------------------------
int CDmeParticleSystemDefinition::GetParticleFunctionCount( ParticleFunctionType_t type ) const { return m_ParticleFunction[type].Count(); }
CDmeParticleFunction *CDmeParticleSystemDefinition::GetParticleFunction( ParticleFunctionType_t type, int nIndex ) { return m_ParticleFunction[type][nIndex]; }
//-----------------------------------------------------------------------------
// Reordering
//-----------------------------------------------------------------------------
void CDmeParticleSystemDefinition::MoveFunctionUp( ParticleFunctionType_t type, CDmeParticleFunction *pElement ) { int nIndex = FindFunction( type, pElement ); if ( nIndex > 0 ) { m_ParticleFunction[type].Swap( nIndex, nIndex - 1 ); } }
void CDmeParticleSystemDefinition::MoveFunctionDown( ParticleFunctionType_t type, CDmeParticleFunction *pElement ) { int nIndex = FindFunction( type, pElement ); int nLastIndex = m_ParticleFunction[type].Count() - 1; if ( nIndex >= 0 && nIndex < nLastIndex ) { m_ParticleFunction[type].Swap( nIndex, nIndex + 1 ); } }
//-----------------------------------------------------------------------------
// Marks a particle system as a new instance
// This is basically a workaround to prevent newly-copied particle functions
// from recompiling themselves a zillion times
//-----------------------------------------------------------------------------
void CDmeParticleSystemDefinition::MarkNewInstance() { for ( int i = 0; i < PARTICLE_FUNCTION_COUNT; ++i ) { int nCount = m_ParticleFunction[i].Count(); for ( int j = 0; j < nCount; ++j ) { m_ParticleFunction[i][j]->MarkNewInstance(); } } }
//-----------------------------------------------------------------------------
// Recompiles the particle system when a change occurs
//-----------------------------------------------------------------------------
void CDmeParticleSystemDefinition::RecompileParticleSystem() { const char *pFileFormat = "pcf"; const char *pEncoding = g_pDataModel->GetDefaultEncoding( pFileFormat ); int nFlags = g_pDataModel->IsEncodingBinary( pEncoding ) ? 0 : CUtlBuffer::TEXT_BUFFER; CUtlBuffer buf( 0, 0, nFlags ); if ( g_pDataModel->Serialize( buf, pEncoding, pFileFormat, GetHandle() ) ) { g_pParticleSystemMgr->ReadParticleConfigFile( buf, true, NULL ); } }
|