diff --git a/Engine/source/T3D/debris.cpp b/Engine/source/T3D/debris.cpp index 3d7554f26..02b475c80 100644 --- a/Engine/source/T3D/debris.cpp +++ b/Engine/source/T3D/debris.cpp @@ -117,6 +117,85 @@ DebrisData::DebrisData() ignoreWater = true; } +//#define TRACK_DEBRIS_DATA_CLONES + +#ifdef TRACK_DEBRIS_DATA_CLONES +static int debris_data_clones = 0; +#endif + +DebrisData::DebrisData(const DebrisData& other, bool temp_clone) : GameBaseData(other, temp_clone) +{ +#ifdef TRACK_DEBRIS_DATA_CLONES + debris_data_clones++; + if (debris_data_clones == 1) + Con::errorf("DebrisData -- Clones are on the loose!"); +#endif + velocity = other.velocity; + velocityVariance = other.velocityVariance; + friction = other.friction; + elasticity = other.elasticity; + lifetime = other.lifetime; + lifetimeVariance = other.lifetimeVariance; + numBounces = other.numBounces; + bounceVariance = other.bounceVariance; + minSpinSpeed = other.minSpinSpeed; + maxSpinSpeed = other.maxSpinSpeed; + explodeOnMaxBounce = other.explodeOnMaxBounce; + staticOnMaxBounce = other.staticOnMaxBounce; + snapOnMaxBounce = other.snapOnMaxBounce; + fade = other.fade; + useRadiusMass = other.useRadiusMass; + baseRadius = other.baseRadius; + gravModifier = other.gravModifier; + terminalVelocity = other.terminalVelocity; + ignoreWater = other.ignoreWater; + shapeName = other.shapeName; + shape = other.shape; // -- TSShape loaded using shapeName + textureName = other.textureName; + explosionId = other.explosionId; // -- for pack/unpack of explosion ptr + explosion = other.explosion; + dMemcpy( emitterList, other.emitterList, sizeof( emitterList ) ); + dMemcpy( emitterIDList, other.emitterIDList, sizeof( emitterIDList ) ); // -- for pack/unpack of emitterList ptrs +} + +DebrisData::~DebrisData() +{ + if (!isTempClone()) + return; + +#ifdef TRACK_DEBRIS_DATA_CLONES + if (debris_data_clones > 0) + { + debris_data_clones--; + if (debris_data_clones == 0) + Con::errorf("DebrisData -- Clones eliminated!"); + } + else + Con::errorf("DebrisData -- Too many clones deleted!"); +#endif +} + +DebrisData* DebrisData::cloneAndPerformSubstitutions(const SimObject* owner, S32 index) +{ + if (!owner || getSubstitutionCount() == 0) + return this; + + DebrisData* sub_debris_db = new DebrisData(*this, true); + performSubstitutions(sub_debris_db, owner, index); + + return sub_debris_db; +} + +void DebrisData::onPerformSubstitutions() +{ + if( shapeName && shapeName[0] != '\0') + { + shape = ResourceManager::get().load(shapeName); + if( bool(shape) == false ) + Con::errorf("DebrisData::onPerformSubstitutions(): failed to load shape \"%s\"", shapeName); + } +} + bool DebrisData::onAdd() { if(!Parent::onAdd()) @@ -458,6 +537,8 @@ Debris::Debris() // Only allocated client side. mNetFlags.set( IsGhost ); + ss_object = 0; + ss_index = 0; } Debris::~Debris() @@ -473,6 +554,12 @@ Debris::~Debris() delete mPart; mPart = NULL; } + + if (mDataBlock && mDataBlock->isTempClone()) + { + delete mDataBlock; + mDataBlock = 0; + } } void Debris::initPersistFields() @@ -502,6 +589,8 @@ bool Debris::onNewDataBlock( GameBaseData *dptr, bool reload ) if( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) ) return false; + if (mDataBlock->isTempClone()) + return true; scriptOnNewDataBlock(); return true; @@ -526,7 +615,7 @@ bool Debris::onAdd() if( mDataBlock->emitterList[i] != NULL ) { ParticleEmitter * pEmitter = new ParticleEmitter; - pEmitter->onNewDataBlock( mDataBlock->emitterList[i], false ); + pEmitter->onNewDataBlock(mDataBlock->emitterList[i]->cloneAndPerformSubstitutions(ss_object, ss_index), false); if( !pEmitter->registerObject() ) { Con::warnf( ConsoleLogEntry::General, "Could not register emitter for particle of class: %s", mDataBlock->getName() ); @@ -805,7 +894,8 @@ void Debris::explode() Point3F explosionPos = getPosition(); Explosion* pExplosion = new Explosion; - pExplosion->onNewDataBlock(mDataBlock->explosion, false); + pExplosion->setSubstitutionData(ss_object, ss_index); + pExplosion->onNewDataBlock(mDataBlock->explosion->cloneAndPerformSubstitutions(ss_object, ss_index), false); MatrixF trans( true ); trans.setPosition( getPosition() ); diff --git a/Engine/source/T3D/debris.h b/Engine/source/T3D/debris.h index 14cbd5e9f..87dcff2e9 100644 --- a/Engine/source/T3D/debris.h +++ b/Engine/source/T3D/debris.h @@ -20,6 +20,11 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// +// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames +// Copyright (C) 2015 Faust Logic, Inc. +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// + #ifndef _DEBRIS_H_ #define _DEBRIS_H_ @@ -97,6 +102,12 @@ struct DebrisData : public GameBaseData DECLARE_CONOBJECT(DebrisData); +public: + /*C*/ DebrisData(const DebrisData&, bool = false); + /*D*/ ~DebrisData(); + DebrisData* cloneAndPerformSubstitutions(const SimObject*, S32 index=0); + virtual void onPerformSubstitutions(); + virtual bool allowSubstitutions() const { return true; } }; //************************************************************************** @@ -165,6 +176,11 @@ public: DECLARE_CONOBJECT(Debris); +private: + SimObject* ss_object; + S32 ss_index; +public: + void setSubstitutionData(SimObject* obj, S32 idx=0) { ss_object = obj; ss_index = idx; } }; diff --git a/Engine/source/T3D/fx/explosion.cpp b/Engine/source/T3D/fx/explosion.cpp index 7eca7f532..0236da6e9 100644 --- a/Engine/source/T3D/fx/explosion.cpp +++ b/Engine/source/T3D/fx/explosion.cpp @@ -24,6 +24,7 @@ // Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames // Copyright (C) 2015 Faust Logic, Inc. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// + #include "platform/platform.h" #include "T3D/fx/explosion.h" @@ -54,6 +55,8 @@ #include "renderInstance/renderPassManager.h" #include "console/engineAPI.h" +#include "sfx/sfxProfile.h" + IMPLEMENT_CONOBJECT(Explosion); ConsoleDocClass( Explosion, @@ -285,6 +288,105 @@ ExplosionData::ExplosionData() lightNormalOffset = 0.1f; } +//#define TRACK_EXPLOSION_DATA_CLONES + +#ifdef TRACK_EXPLOSION_DATA_CLONES +static int explosion_data_clones = 0; +#endif + +ExplosionData::ExplosionData(const ExplosionData& other, bool temp_clone) : GameBaseData(other, temp_clone) +{ +#ifdef TRACK_EXPLOSION_DATA_CLONES + explosion_data_clones++; + if (explosion_data_clones == 1) + Con::errorf("ExplosionData -- Clones are on the loose!"); +#endif + + dtsFileName = other.dtsFileName; + faceViewer = other.faceViewer; + particleDensity = other.particleDensity; + particleRadius = other.particleRadius; + soundProfile = other.soundProfile; + particleEmitter = other.particleEmitter; + particleEmitterId = other.particleEmitterId; // -- for pack/unpack of particleEmitter ptr + explosionScale = other.explosionScale; + playSpeed = other.playSpeed; + explosionShape = other.explosionShape; // -- TSShape loaded using dtsFileName + explosionAnimation = other.explosionAnimation; // -- from explosionShape sequence "ambient" + dMemcpy( emitterList, other.emitterList, sizeof( emitterList ) ); + dMemcpy( emitterIDList, other.emitterIDList, sizeof( emitterIDList ) ); // -- for pack/unpack of emitterList ptrs + dMemcpy( debrisList, other.debrisList, sizeof( debrisList ) ); + dMemcpy( debrisIDList, other.debrisIDList, sizeof( debrisIDList ) ); // -- for pack/unpack of debrisList ptrs + debrisThetaMin = other.debrisThetaMin; + debrisThetaMax = other.debrisThetaMax; + debrisPhiMin = other.debrisPhiMin; + debrisPhiMax = other.debrisPhiMax; + debrisNum = other.debrisNum; + debrisNumVariance = other.debrisNumVariance; + debrisVelocity = other.debrisVelocity; + debrisVelocityVariance = other.debrisVelocityVariance; + dMemcpy( explosionList, other.explosionList, sizeof( explosionList ) ); + dMemcpy( explosionIDList, other.explosionIDList, sizeof( explosionIDList ) ); // -- for pack/unpack of explosionList ptrs + delayMS = other.delayMS; + delayVariance = other.delayVariance; + lifetimeMS = other.lifetimeMS; + lifetimeVariance = other.lifetimeVariance; + offset = other.offset; + dMemcpy( sizes, other.times, sizeof( sizes ) ); + dMemcpy( times, other.times, sizeof( times ) ); + shakeCamera = other.shakeCamera; + camShakeFreq = other.camShakeFreq; + camShakeAmp = other.camShakeAmp; + camShakeDuration = other.camShakeDuration; + camShakeRadius = other.camShakeRadius; + camShakeFalloff = other.camShakeFalloff; + lightStartRadius = other.lightStartRadius; + lightEndRadius = other.lightEndRadius; + lightStartColor = other.lightStartColor; + lightEndColor = other.lightEndColor; + lightStartBrightness = other.lightStartBrightness; + lightEndBrightness = other.lightEndBrightness; + lightNormalOffset = other.lightNormalOffset; + // Note - Explosion calls mDataBlock->getName() in warning messages but + // that should be safe. +} + +ExplosionData::~ExplosionData() +{ + if (!isTempClone()) + return; + + if (soundProfile && soundProfile->isTempClone()) + { + delete soundProfile; + soundProfile = 0; + } + + // particleEmitter, emitterList[*], debrisList[*], explosionList[*] will delete themselves + +#ifdef TRACK_EXPLOSION_DATA_CLONES + if (explosion_data_clones > 0) + { + explosion_data_clones--; + if (explosion_data_clones == 0) + Con::errorf("ExplosionData -- Clones eliminated!"); + } + else + Con::errorf("ExplosionData -- Too many clones deleted!"); +#endif +} + +ExplosionData* ExplosionData::cloneAndPerformSubstitutions(const SimObject* owner, S32 index) +{ + if (!owner || getSubstitutionCount() == 0) + return this; + + ExplosionData* sub_explosion_db = new ExplosionData(*this, true); + performSubstitutions(sub_explosion_db, owner, index); + + return sub_explosion_db; +} + void ExplosionData::initPersistFields() { addField( "explosionShape", TypeShapeFilename, Offset(dtsFileName, ExplosionData), @@ -818,6 +920,10 @@ Explosion::Explosion() mLight = LIGHTMGR->createLightInfo(); mNetFlags.set( IsGhost ); + ss_object = 0; + ss_index = 0; + mDataBlock = 0; + soundProfile_clone = 0; } Explosion::~Explosion() @@ -830,6 +936,18 @@ Explosion::~Explosion() } SAFE_DELETE(mLight); + + if (soundProfile_clone) + { + delete soundProfile_clone; + soundProfile_clone = 0; + } + + if (mDataBlock && mDataBlock->isTempClone()) + { + delete mDataBlock; + mDataBlock = 0; + } } @@ -988,6 +1106,8 @@ bool Explosion::onNewDataBlock( GameBaseData *dptr, bool reload ) if (!mDataBlock || !Parent::onNewDataBlock( dptr, reload )) return false; + if (mDataBlock->isTempClone()) + return true; scriptOnNewDataBlock(); return true; } @@ -1200,7 +1320,8 @@ void Explosion::launchDebris( Point3F &axis ) launchDir *= debrisVel; Debris *debris = new Debris; - debris->setDataBlock( mDataBlock->debrisList[0] ); + debris->setSubstitutionData(ss_object, ss_index); + debris->setDataBlock(mDataBlock->debrisList[0]->cloneAndPerformSubstitutions(ss_object, ss_index)); debris->setTransform( getTransform() ); debris->init( pos, launchDir ); @@ -1228,7 +1349,8 @@ void Explosion::spawnSubExplosions() { MatrixF trans = getTransform(); Explosion* pExplosion = new Explosion; - pExplosion->setDataBlock( mDataBlock->explosionList[i] ); + pExplosion->setSubstitutionData(ss_object, ss_index); + pExplosion->setDataBlock(mDataBlock->explosionList[i]->cloneAndPerformSubstitutions(ss_object, ss_index)); pExplosion->setTransform( trans ); pExplosion->setInitialState( trans.getPosition(), mInitialNormal, 1); if (!pExplosion->registerObject()) @@ -1266,12 +1388,18 @@ bool Explosion::explode() resetWorldBox(); } - if (mDataBlock->soundProfile) - SFX->playOnce( mDataBlock->soundProfile, &getTransform() ); + SFXProfile* sound_prof = dynamic_cast(mDataBlock->soundProfile); + if (sound_prof) + { + soundProfile_clone = sound_prof->cloneAndPerformSubstitutions(ss_object, ss_index); + SFX->playOnce( soundProfile_clone, &getTransform() ); + if (!soundProfile_clone->isTempClone()) + soundProfile_clone = 0; + } if (mDataBlock->particleEmitter) { mMainEmitter = new ParticleEmitter; - mMainEmitter->setDataBlock(mDataBlock->particleEmitter); + mMainEmitter->setDataBlock(mDataBlock->particleEmitter->cloneAndPerformSubstitutions(ss_object, ss_index)); mMainEmitter->registerObject(); mMainEmitter->emitParticles(getPosition(), mInitialNormal, mDataBlock->particleRadius, @@ -1283,7 +1411,7 @@ bool Explosion::explode() if( mDataBlock->emitterList[i] != NULL ) { ParticleEmitter * pEmitter = new ParticleEmitter; - pEmitter->setDataBlock( mDataBlock->emitterList[i] ); + pEmitter->setDataBlock(mDataBlock->emitterList[i]->cloneAndPerformSubstitutions(ss_object, ss_index)); if( !pEmitter->registerObject() ) { Con::warnf( ConsoleLogEntry::General, "Could not register emitter for particle of class: %s", mDataBlock->getName() ); diff --git a/Engine/source/T3D/fx/explosion.h b/Engine/source/T3D/fx/explosion.h index a030776fe..df4396a76 100644 --- a/Engine/source/T3D/fx/explosion.h +++ b/Engine/source/T3D/fx/explosion.h @@ -20,6 +20,11 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// +// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames +// Copyright (C) 2015 Faust Logic, Inc. +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// + #ifndef _EXPLOSION_H_ #define _EXPLOSION_H_ @@ -42,6 +47,7 @@ class TSThread; class SFXTrack; struct DebrisData; +class SFXProfile; //-------------------------------------------------------------------------- class ExplosionData : public GameBaseData { public: @@ -126,6 +132,11 @@ class ExplosionData : public GameBaseData { static void initPersistFields(); virtual void packData(BitStream* stream); virtual void unpackData(BitStream* stream); +public: + /*C*/ ExplosionData(const ExplosionData&, bool = false); + /*D*/ ~ExplosionData(); + ExplosionData* cloneAndPerformSubstitutions(const SimObject*, S32 index=0); + virtual bool allowSubstitutions() const { return true; } }; @@ -188,6 +199,12 @@ class Explosion : public GameBase, public ISceneLight DECLARE_CONOBJECT(Explosion); static void initPersistFields(); +private: + SimObject* ss_object; + S32 ss_index; + SFXProfile* soundProfile_clone; +public: + void setSubstitutionData(SimObject* obj, S32 idx=0) { ss_object = obj; ss_index = idx; } }; #endif // _H_EXPLOSION diff --git a/Engine/source/T3D/fx/particle.cpp b/Engine/source/T3D/fx/particle.cpp index cb307ccbb..f887a021e 100644 --- a/Engine/source/T3D/fx/particle.cpp +++ b/Engine/source/T3D/fx/particle.cpp @@ -19,6 +19,11 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. //----------------------------------------------------------------------------- + +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// +// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames +// Copyright (C) 2015 Faust Logic, Inc. +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// #include "particle.h" #include "console/consoleTypes.h" #include "console/typeValidators.h" @@ -653,3 +658,78 @@ DefineEngineMethod(ParticleData, reload, void, (),, char errorBuffer[256]; object->reload(errorBuffer); } +//#define TRACK_PARTICLE_DATA_CLONES + +#ifdef TRACK_PARTICLE_DATA_CLONES +static int particle_data_clones = 0; +#endif + +ParticleData::ParticleData(const ParticleData& other, bool temp_clone) : SimDataBlock(other, temp_clone) +{ +#ifdef TRACK_PARTICLE_DATA_CLONES + particle_data_clones++; + if (particle_data_clones == 1) + Con::errorf("ParticleData -- Clones are on the loose!"); +#endif + + dragCoefficient = other.dragCoefficient; + windCoefficient = other.windCoefficient; + gravityCoefficient = other.gravityCoefficient; + inheritedVelFactor = other.inheritedVelFactor; + constantAcceleration = other.constantAcceleration; + lifetimeMS = other.lifetimeMS; + lifetimeVarianceMS = other.lifetimeVarianceMS; + spinSpeed = other.spinSpeed; + spinRandomMin = other.spinRandomMin; + spinRandomMax = other.spinRandomMax; + useInvAlpha = other.useInvAlpha; + animateTexture = other.animateTexture; + numFrames = other.numFrames; // -- calc from other fields + framesPerSec = other.framesPerSec; + dMemcpy( colors, other.colors, sizeof( colors ) ); + dMemcpy( sizes, other.sizes, sizeof( sizes ) ); + dMemcpy( times, other.times, sizeof( times ) ); + animTexUVs = other.animTexUVs; // -- calc from other fields + dMemcpy( texCoords, other.texCoords, sizeof( texCoords ) ); + animTexTiling = other.animTexTiling; + animTexFramesString = other.animTexFramesString; + animTexFrames = other.animTexFrames; // -- parsed from animTexFramesString + textureName = other.textureName; + textureHandle = other.textureHandle; + spinBias = other.spinBias; + randomizeSpinDir = other.randomizeSpinDir; + textureExtName = other.textureExtName; + textureExtHandle = other.textureExtHandle; + constrain_pos = other.constrain_pos; + start_angle = other.start_angle; + angle_variance = other.angle_variance; + sizeBias = other.sizeBias; +} + +ParticleData::~ParticleData() +{ + if (animTexUVs) + { + delete [] animTexUVs; + } + + if (!isTempClone()) + return; + +#ifdef TRACK_PARTICLE_DATA_CLONES + if (particle_data_clones > 0) + { + particle_data_clones--; + if (particle_data_clones == 0) + Con::errorf("ParticleData -- Clones eliminated!"); + } + else + Con::errorf("ParticleData -- Too many clones deleted!"); +#endif +} + +void ParticleData::onPerformSubstitutions() +{ + char errorBuffer[256]; + reload(errorBuffer); +} diff --git a/Engine/source/T3D/fx/particle.h b/Engine/source/T3D/fx/particle.h index 36b8dd11a..17c173e67 100644 --- a/Engine/source/T3D/fx/particle.h +++ b/Engine/source/T3D/fx/particle.h @@ -102,6 +102,10 @@ class ParticleData : public SimDataBlock static void initPersistFields(); bool reload(char errorBuffer[256]); + public: + /*C*/ ParticleData(const ParticleData&, bool = false); + virtual void onPerformSubstitutions(); + virtual bool allowSubstitutions() const { return true; } public: bool loadParameters(); bool reload(String &errorStr); diff --git a/Engine/source/T3D/fx/particleEmitter.cpp b/Engine/source/T3D/fx/particleEmitter.cpp index 0f164f42b..d59bef4e3 100644 --- a/Engine/source/T3D/fx/particleEmitter.cpp +++ b/Engine/source/T3D/fx/particleEmitter.cpp @@ -712,6 +712,134 @@ void ParticleEmitterData::allocPrimBuffer( S32 overrideSize ) delete [] indices; } +//#define TRACK_PARTICLE_EMITTER_DATA_CLONES + +#ifdef TRACK_PARTICLE_EMITTER_DATA_CLONES +static int emitter_data_clones = 0; +#endif + +ParticleEmitterData::ParticleEmitterData(const ParticleEmitterData& other, bool temp_clone) : GameBaseData(other, temp_clone) +{ +#ifdef TRACK_PARTICLE_EMITTER_DATA_CLONES + emitter_data_clones++; + if (emitter_data_clones == 1) + Con::errorf("ParticleEmitterData -- Clones are on the loose!"); +#endif + + ejectionPeriodMS = other.ejectionPeriodMS; + periodVarianceMS = other.periodVarianceMS; + ejectionVelocity = other.ejectionVelocity; + velocityVariance = other.velocityVariance; + ejectionOffset = other.ejectionOffset; + ejectionOffsetVariance = other.ejectionOffsetVariance; + thetaMin = other.thetaMin; + thetaMax = other.thetaMax; + phiReferenceVel = other.phiReferenceVel; + phiVariance = other.phiVariance; + softnessDistance = other.softnessDistance; + ambientFactor = other.ambientFactor; + lifetimeMS = other.lifetimeMS; + lifetimeVarianceMS = other.lifetimeVarianceMS; + overrideAdvance = other.overrideAdvance; + orientParticles = other.orientParticles; + orientOnVelocity = other.orientOnVelocity; + useEmitterSizes = other.useEmitterSizes; + useEmitterColors = other.useEmitterColors; + alignParticles = other.alignParticles; + alignDirection = other.alignDirection; + particleString = other.particleString; + particleDataBlocks = other.particleDataBlocks; // -- derived from particleString + dataBlockIds = other.dataBlockIds; // -- derived from particleString + partListInitSize = other.partListInitSize; // -- approx calc from other fields + primBuff = other.primBuff; + blendStyle = other.blendStyle; + sortParticles = other.sortParticles; + reverseOrder = other.reverseOrder; + textureName = other.textureName; + textureHandle = other.textureHandle; // -- TextureHandle loads using textureName + highResOnly = other.highResOnly; + renderReflection = other.renderReflection; + fade_color = other.fade_color; + fade_size = other.fade_size; + fade_alpha = other.fade_alpha; + ejectionInvert = other.ejectionInvert; + parts_per_eject = other.parts_per_eject; // -- set to 1 (used by subclasses) + use_emitter_xfm = other.use_emitter_xfm; +#if defined(AFX_CAP_PARTICLE_POOLS) + pool_datablock = other.pool_datablock; + pool_index = other.pool_index; + pool_depth_fade = other.pool_depth_fade; + pool_radial_fade = other.pool_radial_fade; + do_pool_id_convert = other.do_pool_id_convert; // -- flags pool id conversion need +#endif +} + +ParticleEmitterData::~ParticleEmitterData() +{ + if (!isTempClone()) + return; + + for (S32 i = 0; i < particleDataBlocks.size(); i++) + { + if (particleDataBlocks[i] && particleDataBlocks[i]->isTempClone()) + { + delete particleDataBlocks[i]; + particleDataBlocks[i] = 0; + } + } + +#ifdef TRACK_PARTICLE_EMITTER_DATA_CLONES + if (emitter_data_clones > 0) + { + emitter_data_clones--; + if (emitter_data_clones == 0) + Con::errorf("ParticleEmitterData -- Clones eliminated!"); + } + else + Con::errorf("ParticleEmitterData -- Too many clones deleted!"); +#endif +} + +ParticleEmitterData* ParticleEmitterData::cloneAndPerformSubstitutions(const SimObject* owner, S32 index) +{ + if (!owner) + return this; + + bool clone_parts_db = false; + + // note -- this could be checked when the particle blocks are evaluated + for (S32 i = 0; i < this->particleDataBlocks.size(); i++) + { + if (this->particleDataBlocks[i] && (this->particleDataBlocks[i]->getSubstitutionCount() > 0)) + { + clone_parts_db = true; + break; + } + } + + ParticleEmitterData* sub_emitter_db = this; + + if (this->getSubstitutionCount() > 0 || clone_parts_db) + { + sub_emitter_db = new ParticleEmitterData(*this, true); + performSubstitutions(sub_emitter_db, owner, index); + + if (clone_parts_db) + { + for (S32 i = 0; i < sub_emitter_db->particleDataBlocks.size(); i++) + { + if (sub_emitter_db->particleDataBlocks[i] && (sub_emitter_db->particleDataBlocks[i]->getSubstitutionCount() > 0)) + { + ParticleData* orig_db = sub_emitter_db->particleDataBlocks[i]; + sub_emitter_db->particleDataBlocks[i] = new ParticleData(*orig_db, true); + orig_db->performSubstitutions(sub_emitter_db->particleDataBlocks[i], owner, index); + } + } + } + } + + return sub_emitter_db; +} //----------------------------------------------------------------------------- // ParticleEmitter @@ -743,6 +871,7 @@ ParticleEmitter::ParticleEmitter() // ParticleEmitter should be allocated on the client only. mNetFlags.set( IsGhost ); + mDataBlock = 0; } //----------------------------------------------------------------------------- @@ -754,6 +883,19 @@ ParticleEmitter::~ParticleEmitter() { delete [] part_store[i]; } + if (db_temp_clone && mDataBlock && mDataBlock->isTempClone()) + { + for (S32 i = 0; i < mDataBlock->particleDataBlocks.size(); i++) + { + if (mDataBlock->particleDataBlocks[i] && mDataBlock->particleDataBlocks[i]->isTempClone()) + { + delete mDataBlock->particleDataBlocks[i]; + mDataBlock->particleDataBlocks[i] = 0; + } + } + delete mDataBlock; + mDataBlock = 0; + } } //----------------------------------------------------------------------------- @@ -832,6 +974,11 @@ bool ParticleEmitter::onNewDataBlock( GameBaseData *dptr, bool reload ) part_list_head.next = NULL; n_parts = 0; } + if (mDataBlock->isTempClone()) + { + db_temp_clone = true; + return true; + } scriptOnNewDataBlock(); return true; diff --git a/Engine/source/T3D/fx/particleEmitter.h b/Engine/source/T3D/fx/particleEmitter.h index 122dbcb00..f4da1ed53 100644 --- a/Engine/source/T3D/fx/particleEmitter.h +++ b/Engine/source/T3D/fx/particleEmitter.h @@ -20,6 +20,10 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// +// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames +// Copyright (C) 2015 Faust Logic, Inc. +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// #ifndef _H_PARTICLE_EMITTER #define _H_PARTICLE_EMITTER @@ -113,6 +117,11 @@ class ParticleEmitterData : public GameBaseData bool glow; ///< Renders this emitter into the glow buffer. bool reload(); +public: + /*C*/ ParticleEmitterData(const ParticleEmitterData&, bool = false); + /*D*/ ~ParticleEmitterData(); + virtual ParticleEmitterData* cloneAndPerformSubstitutions(const SimObject*, S32 index=0); + virtual bool allowSubstitutions() const { return true; } }; //***************************************************************************** diff --git a/Engine/source/T3D/gameBase/gameBase.cpp b/Engine/source/T3D/gameBase/gameBase.cpp index 5c7e76695..903187ac3 100644 --- a/Engine/source/T3D/gameBase/gameBase.cpp +++ b/Engine/source/T3D/gameBase/gameBase.cpp @@ -20,6 +20,10 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// +// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames +// Copyright (C) 2015 Faust Logic, Inc. +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// #include "platform/platform.h" #include "T3D/gameBase/gameBase.h" #include "console/consoleTypes.h" @@ -122,6 +126,12 @@ GameBaseData::GameBaseData() category = ""; packed = false; } +GameBaseData::GameBaseData(const GameBaseData& other, bool temp_clone) : SimDataBlock(other, temp_clone) +{ + packed = other.packed; + category = other.category; + //mReloadSignal = other.mReloadSignal; // DO NOT copy the mReloadSignal member. +} void GameBaseData::inspectPostApply() { @@ -290,6 +300,9 @@ bool GameBase::onNewDataBlock( GameBaseData *dptr, bool reload ) if ( !mDataBlock ) return false; + // Don't set mask when new datablock is a temp-clone. + if (mDataBlock->isTempClone()) + return true; setMaskBits(DataBlockMask); return true; diff --git a/Engine/source/T3D/gameBase/gameBase.h b/Engine/source/T3D/gameBase/gameBase.h index 3623603fa..be9094e85 100644 --- a/Engine/source/T3D/gameBase/gameBase.h +++ b/Engine/source/T3D/gameBase/gameBase.h @@ -20,6 +20,10 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// +// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames +// Copyright (C) 2015 Faust Logic, Inc. +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// #ifndef _GAMEBASE_H_ #define _GAMEBASE_H_ @@ -113,6 +117,8 @@ public: DECLARE_CALLBACK( void, onMount, ( SceneObject* obj, SceneObject* mountObj, S32 node ) ); DECLARE_CALLBACK( void, onUnmount, ( SceneObject* obj, SceneObject* mountObj, S32 node ) ); /// @} +public: + GameBaseData(const GameBaseData&, bool = false); }; //---------------------------------------------------------------------------- diff --git a/Engine/source/T3D/projectile.cpp b/Engine/source/T3D/projectile.cpp index f5003c1e5..eba9cb9d2 100644 --- a/Engine/source/T3D/projectile.cpp +++ b/Engine/source/T3D/projectile.cpp @@ -194,6 +194,40 @@ ProjectileData::ProjectileData() lightDescId = 0; } +ProjectileData::ProjectileData(const ProjectileData& other, bool temp_clone) : GameBaseData(other, temp_clone) +{ + projectileShapeName = other.projectileShapeName; + faceViewer = other.faceViewer; // -- always set to false + scale = other.scale; + velInheritFactor = other.velInheritFactor; + muzzleVelocity = other.muzzleVelocity; + impactForce = other.impactForce; + isBallistic = other.isBallistic; + bounceElasticity = other.bounceElasticity; + bounceFriction = other.bounceFriction; + gravityMod = other.gravityMod; + lifetime = other.lifetime; + armingDelay = other.armingDelay; + fadeDelay = other.fadeDelay; + explosion = other.explosion; + explosionId = other.explosionId; // -- for pack/unpack of explosion ptr + waterExplosion = other.waterExplosion; + waterExplosionId = other.waterExplosionId; // -- for pack/unpack of waterExplosion ptr + splash = other.splash; + splashId = other.splashId; // -- for pack/unpack of splash ptr + decal = other.decal; + decalId = other.decalId; // -- for pack/unpack of decal ptr + sound = other.sound; + lightDesc = other.lightDesc; + lightDescId = other.lightDescId; // -- for pack/unpack of lightDesc ptr + projectileShape = other.projectileShape; // -- TSShape loads using projectileShapeName + activateSeq = other.activateSeq; // -- from projectileShape sequence "activate" + maintainSeq = other.maintainSeq; // -- from projectileShape sequence "maintain" + particleEmitter = other.particleEmitter; + particleEmitterId = other.particleEmitterId; // -- for pack/unpack of particleEmitter ptr + particleWaterEmitter = other.particleWaterEmitter; + particleWaterEmitterId = other.particleWaterEmitterId; // -- for pack/unpack of particleWaterEmitter ptr +} //-------------------------------------------------------------------------- void ProjectileData::initPersistFields() @@ -585,6 +619,8 @@ Projectile::Projectile() mLightState.clear(); mLightState.setLightInfo( mLight ); + + mDataBlock = 0; } Projectile::~Projectile() @@ -593,6 +629,11 @@ Projectile::~Projectile() delete mProjectileShape; mProjectileShape = NULL; + if (mDataBlock && mDataBlock->isTempClone()) + { + delete mDataBlock; + mDataBlock = 0; + } } //-------------------------------------------------------------------------- diff --git a/Engine/source/T3D/projectile.h b/Engine/source/T3D/projectile.h index 17c90cfbc..72f2eac4f 100644 --- a/Engine/source/T3D/projectile.h +++ b/Engine/source/T3D/projectile.h @@ -20,6 +20,10 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// +// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames +// Copyright (C) 2015 Faust Logic, Inc. +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// #ifndef _PROJECTILE_H_ #define _PROJECTILE_H_ @@ -144,6 +148,9 @@ public: DECLARE_CALLBACK( void, onExplode, ( Projectile* proj, Point3F pos, F32 fade ) ); DECLARE_CALLBACK( void, onCollision, ( Projectile* proj, SceneObject* col, F32 fade, Point3F pos, Point3F normal ) ); +public: + ProjectileData(const ProjectileData&, bool = false); + virtual bool allowSubstitutions() const { return true; } }; diff --git a/Engine/source/T3D/shapeBase.cpp b/Engine/source/T3D/shapeBase.cpp index 445ca4b90..0419682ae 100644 --- a/Engine/source/T3D/shapeBase.cpp +++ b/Engine/source/T3D/shapeBase.cpp @@ -200,6 +200,66 @@ ShapeBaseData::ShapeBaseData() dMemset( mountPointNode, -1, sizeof( S32 ) * SceneObject::NumMountPoints ); } +ShapeBaseData::ShapeBaseData(const ShapeBaseData& other, bool temp_clone) : GameBaseData(other, temp_clone) +{ + shadowEnable = other.shadowEnable; + shadowSize = other.shadowSize; + shadowMaxVisibleDistance = other.shadowMaxVisibleDistance; + shadowProjectionDistance = other.shadowProjectionDistance; + shadowSphereAdjust = other.shadowSphereAdjust; + shapeName = other.shapeName; + cloakTexName = other.cloakTexName; + cubeDescName = other.cubeDescName; + cubeDescId = other.cubeDescId; + reflectorDesc = other.reflectorDesc; + debris = other.debris; + debrisID = other.debrisID; // -- for pack/unpack of debris ptr + debrisShapeName = other.debrisShapeName; + debrisShape = other.debrisShape; // -- TSShape loaded using debrisShapeName + explosion = other.explosion; + explosionID = other.explosionID; // -- for pack/unpack of explosion ptr + underwaterExplosion = other.underwaterExplosion; + underwaterExplosionID = other.underwaterExplosionID; // -- for pack/unpack of underwaterExplosion ptr + mass = other.mass; + drag = other.drag; + density = other.density; + maxEnergy = other.maxEnergy; + maxDamage = other.maxDamage; + repairRate = other.repairRate; + disabledLevel = other.disabledLevel; + destroyedLevel = other.destroyedLevel; + cameraMaxDist = other.cameraMaxDist; + cameraMinDist = other.cameraMinDist; + cameraDefaultFov = other.cameraDefaultFov; + cameraMinFov = other.cameraMinFov; + cameraMaxFov = other.cameraMaxFov; + cameraCanBank = other.cameraCanBank; + mountedImagesBank = other.mountedImagesBank; + mShape = other.mShape; // -- TSShape loaded using shapeName + mCRC = other.mCRC; // -- from shape, used to verify client shape + computeCRC = other.computeCRC; + eyeNode = other.eyeNode; // -- from shape node "eye" + earNode = other.earNode; // -- from shape node "ear" + cameraNode = other.cameraNode; // -- from shape node "cam" + dMemcpy(mountPointNode, other.mountPointNode, sizeof(mountPointNode)); // -- from shape nodes "mount#" 0-31 + debrisDetail = other.debrisDetail; // -- from shape detail "Debris-17" + damageSequence = other.damageSequence; // -- from shape sequence "Damage" + hulkSequence = other.hulkSequence; // -- from shape sequence "Visibility" + observeThroughObject = other.observeThroughObject; + collisionDetails = other.collisionDetails; // -- calc from shape (this is a Vector copy) + collisionBounds = other.collisionBounds; // -- calc from shape (this is a Vector copy) + LOSDetails = other.LOSDetails; // -- calc from shape (this is a Vector copy) + firstPersonOnly = other.firstPersonOnly; + useEyePoint = other.useEyePoint; + isInvincible = other.isInvincible; + renderWhenDestroyed = other.renderWhenDestroyed; + inheritEnergyFromMount = other.inheritEnergyFromMount; + remap_txr_tags = other.remap_txr_tags; + remap_buffer = other.remap_buffer; + txr_tag_remappings = other.txr_tag_remappings; + silent_bbox_check = other.silent_bbox_check; +} + struct ShapeBaseDataProto { F32 mass; diff --git a/Engine/source/T3D/shapeBase.h b/Engine/source/T3D/shapeBase.h index 98a42f73b..213a808e4 100644 --- a/Engine/source/T3D/shapeBase.h +++ b/Engine/source/T3D/shapeBase.h @@ -20,6 +20,10 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// +// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames +// Copyright (C) 2015 Faust Logic, Inc. +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// #ifndef _SHAPEBASE_H_ #define _SHAPEBASE_H_ @@ -654,6 +658,8 @@ public: DECLARE_CALLBACK(void, onEndSequence, (ShapeBase* obj, S32 slot, const char* name)); DECLARE_CALLBACK( void, onForceUncloak, ( ShapeBase* obj, const char* reason ) ); /// @} +public: + ShapeBaseData(const ShapeBaseData&, bool = false); }; diff --git a/Engine/source/T3D/staticShape.cpp b/Engine/source/T3D/staticShape.cpp index 6548e2161..874e31059 100644 --- a/Engine/source/T3D/staticShape.cpp +++ b/Engine/source/T3D/staticShape.cpp @@ -20,6 +20,10 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// +// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames +// Copyright (C) 2015 Faust Logic, Inc. +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// #include "platform/platform.h" #include "core/dnet.h" #include "core/stream/bitStream.h" @@ -97,6 +101,14 @@ StaticShapeData::StaticShapeData() noIndividualDamage = false; } +StaticShapeData::StaticShapeData(const StaticShapeData& other, bool temp_clone) : ShapeBaseData(other, temp_clone) +{ + noIndividualDamage = other.noIndividualDamage; + dynamicTypeField = other.dynamicTypeField; + isShielded = other.isShielded; // -- uninitialized, unused + energyPerDamagePoint = other.energyPerDamagePoint; // -- uninitialized, unused +} + void StaticShapeData::initPersistFields() { addField("noIndividualDamage", TypeBool, Offset(noIndividualDamage, StaticShapeData), "Deprecated\n\n @internal"); diff --git a/Engine/source/T3D/staticShape.h b/Engine/source/T3D/staticShape.h index 737a2e335..292260c72 100644 --- a/Engine/source/T3D/staticShape.h +++ b/Engine/source/T3D/staticShape.h @@ -20,6 +20,11 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// +// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames +// Copyright (C) 2015 Faust Logic, Inc. +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// + #ifndef _STATICSHAPE_H_ #define _STATICSHAPE_H_ @@ -38,12 +43,16 @@ struct StaticShapeData: public ShapeBaseData { bool noIndividualDamage; S32 dynamicTypeField; bool isShielded; + F32 energyPerDamagePoint; // Re-added for AFX // DECLARE_CONOBJECT(StaticShapeData); static void initPersistFields(); virtual void packData(BitStream* stream); virtual void unpackData(BitStream* stream); +public: + StaticShapeData(const StaticShapeData&, bool = false); + virtual bool allowSubstitutions() const { return true; } }; diff --git a/Engine/source/console/simObject.cpp b/Engine/source/console/simObject.cpp index 22e496bbf..b1dbb8f13 100644 --- a/Engine/source/console/simObject.cpp +++ b/Engine/source/console/simObject.cpp @@ -92,12 +92,17 @@ SimObject::SimObject() mCopySource = NULL; mPersistentId = NULL; + is_temp_clone = false; } //----------------------------------------------------------------------------- SimObject::~SimObject() { + // if this is a temp-clone, we don't delete any members that were shallow-copied + // over from the source datablock. + if (is_temp_clone) + return; if( mFieldDictionary ) { delete mFieldDictionary; @@ -1327,6 +1332,43 @@ void SimObject::setDataFieldType(const char *typeName, StringTableEntry slotName } } +// This is the copy-constructor used to create temporary datablock clones. +// The argument is added to distinguish this copy-constructor +// from any general-purpose copy-constructor that might be needed in the +// future. should always be true when creating temporary +// datablock clones. +// +SimObject::SimObject(const SimObject& other, bool temp_clone) +{ + is_temp_clone = temp_clone; + + objectName = other.objectName; + mOriginalName = other.mOriginalName; + nextNameObject = other.nextNameObject; + nextManagerNameObject = other.nextManagerNameObject; + nextIdObject = other.nextIdObject; + mGroup = other.mGroup; + mFlags = other.mFlags; + mCopySource = other.mCopySource; + mFieldDictionary = other.mFieldDictionary; + //mIdString = other.mIdString; // special treatment (see below) + mFilename = other.mFilename; + mDeclarationLine = other.mDeclarationLine; + mNotifyList = other.mNotifyList; + mId = other.mId; + mInternalName = other.mInternalName; + mCanSaveFieldDictionary = other.mCanSaveFieldDictionary; + mPersistentId = other.mPersistentId; + mNameSpace = other.mNameSpace; + mClassName = other.mClassName; + mSuperClassName = other.mSuperClassName; + preventNameChanging = other.preventNameChanging; + + if (mId) + dSprintf( mIdString, sizeof( mIdString ), "%u", mId ); + else + mIdString[ 0 ] = '\0'; +} //----------------------------------------------------------------------------- void SimObject::dumpClassHierarchy() diff --git a/Engine/source/console/simObject.h b/Engine/source/console/simObject.h index 6cba1beff..0585eda45 100644 --- a/Engine/source/console/simObject.h +++ b/Engine/source/console/simObject.h @@ -20,6 +20,10 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// +// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames +// Copyright (C) 2015 Faust Logic, Inc. +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// #ifndef _SIMOBJECT_H_ #define _SIMOBJECT_H_ @@ -970,6 +974,12 @@ class SimObject: public ConsoleObject, public TamlCallbacks // EngineObject. virtual void destroySelf(); +protected: + bool is_temp_clone; +public: + /*C*/ SimObject(const SimObject&, bool = false); + bool isTempClone() const { return is_temp_clone; } + virtual bool allowSubstitutions() const { return false; } }; diff --git a/Engine/source/sfx/sfxDescription.cpp b/Engine/source/sfx/sfxDescription.cpp index 1b4e0dead..c3d9f54cf 100644 --- a/Engine/source/sfx/sfxDescription.cpp +++ b/Engine/source/sfx/sfxDescription.cpp @@ -20,6 +20,10 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// +// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames +// Copyright (C) 2015 Faust Logic, Inc. +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// #include "platform/platform.h" #include "sfx/sfxDescription.h" @@ -176,6 +180,37 @@ SFXDescription::SFXDescription( const SFXDescription& desc ) //----------------------------------------------------------------------------- +SFXDescription::SFXDescription(const SFXDescription& other, bool temp_clone) + : SimDataBlock(other, temp_clone), + mVolume( other.mVolume ), + mPitch( other.mPitch ), + mIsLooping( other.mIsLooping ), + mIsStreaming( other.mIsStreaming ), + mIs3D( other.mIs3D ), + mUseHardware( other.mUseHardware ), + mMinDistance( other.mMinDistance ), + mMaxDistance( other.mMaxDistance ), + mConeInsideAngle( other.mConeInsideAngle ), + mConeOutsideAngle( other.mConeOutsideAngle ), + mConeOutsideVolume( other.mConeOutsideVolume ), + mRolloffFactor( other.mRolloffFactor ), + mSourceGroup( other.mSourceGroup ), + mFadeInTime( other.mFadeInTime ), + mFadeOutTime( other.mFadeOutTime ), + mFadeInEase( other.mFadeInEase ), + mFadeOutEase( other.mFadeOutEase ), + mFadeLoops( other.mFadeLoops ), + mStreamPacketSize( other.mStreamPacketSize ), + mStreamReadAhead( other.mStreamReadAhead ), + mUseReverb( other.mUseReverb ), + mReverb( other.mReverb ), + mPriority( other.mPriority ), + mScatterDistance( other.mScatterDistance ) +{ + for( U32 i = 0; i < MaxNumParameters; ++ i ) + mParameters[ i ] = other.mParameters[ i ]; +} + void SFXDescription::initPersistFields() { addGroup( "Playback" ); diff --git a/Engine/source/sfx/sfxDescription.h b/Engine/source/sfx/sfxDescription.h index 8bac79467..003faee27 100644 --- a/Engine/source/sfx/sfxDescription.h +++ b/Engine/source/sfx/sfxDescription.h @@ -20,6 +20,10 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// +// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames +// Copyright (C) 2015 Faust Logic, Inc. +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// #ifndef _SFXDESCRIPTION_H_ #define _SFXDESCRIPTION_H_ @@ -192,6 +196,9 @@ class SFXDescription : public SimDataBlock /// Validates the description fixing any /// parameters that are out of range. void validate(); + public: + SFXDescription(const SFXDescription&, bool); + virtual bool allowSubstitutions() const { return true; } }; diff --git a/Engine/source/sfx/sfxProfile.cpp b/Engine/source/sfx/sfxProfile.cpp index 2fff6854d..ef5b9dd42 100644 --- a/Engine/source/sfx/sfxProfile.cpp +++ b/Engine/source/sfx/sfxProfile.cpp @@ -24,6 +24,7 @@ // Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames // Copyright (C) 2015 Faust Logic, Inc. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// + #include "platform/platform.h" #include "sfx/sfxProfile.h" @@ -96,9 +97,6 @@ SFXProfile::SFXProfile( SFXDescription* desc, const String& filename, bool prelo //----------------------------------------------------------------------------- -SFXProfile::~SFXProfile() -{ -} //----------------------------------------------------------------------------- @@ -380,3 +378,95 @@ DefineEngineMethod( SFXProfile, getSoundDuration, F32, (),, { return ( F32 ) object->getSoundDuration() * 0.001f; } + +// enable this to help verify that temp-clones of AudioProfile are being deleted +//#define TRACK_AUDIO_PROFILE_CLONES + +#ifdef TRACK_AUDIO_PROFILE_CLONES +static int audio_prof_clones = 0; +#endif + +SFXProfile::SFXProfile(const SFXProfile& other, bool temp_clone) : SFXTrack(other, temp_clone) +{ +#ifdef TRACK_AUDIO_PROFILE_CLONES + audio_prof_clones++; + if (audio_prof_clones == 1) + Con::errorf("SFXProfile -- Clones are on the loose!"); +#endif + mResource = other.mResource; + mFilename = other.mFilename; + mPreload = other.mPreload; + mBuffer = other.mBuffer; // -- AudioBuffer loaded using mFilename + mChangedSignal = other.mChangedSignal; +} + +SFXProfile::~SFXProfile() +{ + if (!isTempClone()) + return; + + // cleanup after a temp-clone + + if (mDescription && mDescription->isTempClone()) + { + delete mDescription; + mDescription = 0; + } + +#ifdef TRACK_AUDIO_PROFILE_CLONES + if (audio_prof_clones > 0) + { + audio_prof_clones--; + if (audio_prof_clones == 0) + Con::errorf("SFXProfile -- Clones eliminated!"); + } + else + Con::errorf("SFXProfile -- Too many clones deleted!"); +#endif +} + +// Clone and perform substitutions on the SFXProfile and on any SFXDescription +// it references. +SFXProfile* SFXProfile::cloneAndPerformSubstitutions(const SimObject* owner, S32 index) +{ + if (!owner) + return this; + + SFXProfile* sub_profile_db = this; + + // look for mDescriptionObject subs + SFXDescription* desc_db; + if (mDescription && mDescription->getSubstitutionCount() > 0) + { + SFXDescription* orig_db = mDescription; + desc_db = new SFXDescription(*orig_db, true); + orig_db->performSubstitutions(desc_db, owner, index); + } + else + desc_db = 0; + + if (this->getSubstitutionCount() > 0 || desc_db) + { + sub_profile_db = new SFXProfile(*this, true); + performSubstitutions(sub_profile_db, owner, index); + if (desc_db) + sub_profile_db->mDescription = desc_db; + } + + return sub_profile_db; +} + +void SFXProfile::onPerformSubstitutions() +{ + if ( SFX ) + { + // If preload is enabled we load the resource + // and device buffer now to avoid a delay on + // first playback. + if ( mPreload && !_preloadBuffer() ) + Con::errorf( "SFXProfile(%s)::onPerformSubstitutions: The preload failed!", getName() ); + + // We need to get device change notifications. + SFX->getEventSignal().notify( this, &SFXProfile::_onDeviceEvent ); + } +} diff --git a/Engine/source/sfx/sfxProfile.h b/Engine/source/sfx/sfxProfile.h index 70ac4f097..ab1a4b1f0 100644 --- a/Engine/source/sfx/sfxProfile.h +++ b/Engine/source/sfx/sfxProfile.h @@ -20,6 +20,11 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// +// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames +// Copyright (C) 2015 Faust Logic, Inc. +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// + #ifndef _SFXPROFILE_H_ #define _SFXPROFILE_H_ @@ -175,6 +180,11 @@ class SFXProfile : public SFXTrack /// ChangedSignal& getChangedSignal() { return mChangedSignal; } + public: + /*C*/ SFXProfile(const SFXProfile&, bool = false); + SFXProfile* cloneAndPerformSubstitutions(const SimObject*, S32 index=0); + virtual void onPerformSubstitutions(); + virtual bool allowSubstitutions() const { return true; } }; diff --git a/Engine/source/sfx/sfxTrack.cpp b/Engine/source/sfx/sfxTrack.cpp index dde11bb26..067a202ca 100644 --- a/Engine/source/sfx/sfxTrack.cpp +++ b/Engine/source/sfx/sfxTrack.cpp @@ -20,6 +20,10 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// +// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames +// Copyright (C) 2015 Faust Logic, Inc. +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// #include "sfx/sfxTrack.h" #include "sfx/sfxTypes.h" #include "sfx/sfxDescription.h" @@ -65,6 +69,11 @@ SFXTrack::SFXTrack( SFXDescription* description ) dMemset( mParameters, 0, sizeof( mParameters ) ); } +SFXTrack::SFXTrack(const SFXTrack& other, bool temp_clone) : SimDataBlock(other, temp_clone) +{ + mDescription = other.mDescription; + dMemcpy(mParameters, other.mParameters, sizeof(mParameters)); +} //----------------------------------------------------------------------------- void SFXTrack::initPersistFields() diff --git a/Engine/source/sfx/sfxTrack.h b/Engine/source/sfx/sfxTrack.h index 13221dbb8..e30acd007 100644 --- a/Engine/source/sfx/sfxTrack.h +++ b/Engine/source/sfx/sfxTrack.h @@ -20,6 +20,10 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// +// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames +// Copyright (C) 2015 Faust Logic, Inc. +//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// #ifndef _SFXTRACK_H_ #define _SFXTRACK_H_ @@ -92,6 +96,8 @@ class SFXTrack : public SimDataBlock DECLARE_CONOBJECT( SFXTrack ); DECLARE_CATEGORY( "SFX" ); DECLARE_DESCRIPTION( "Abstract base class for any kind of data that can be turned into SFXSources." ); + public: + /*C*/ SFXTrack(const SFXTrack&, bool = false); }; #endif // !_SFXTRACK_H_