diff options
Diffstat (limited to 'movieobjects/dmeparticlesystemdefinition.cpp')
| -rw-r--r-- | movieobjects/dmeparticlesystemdefinition.cpp | 598 |
1 files changed, 598 insertions, 0 deletions
diff --git a/movieobjects/dmeparticlesystemdefinition.cpp b/movieobjects/dmeparticlesystemdefinition.cpp new file mode 100644 index 0000000..d279d44 --- /dev/null +++ b/movieobjects/dmeparticlesystemdefinition.cpp @@ -0,0 +1,598 @@ +//========= 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 ); + } +} + + |