summaryrefslogtreecommitdiff
path: root/movieobjects/dmeparticlesystemdefinition.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'movieobjects/dmeparticlesystemdefinition.cpp')
-rw-r--r--movieobjects/dmeparticlesystemdefinition.cpp598
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 );
+ }
+}
+
+