datablock-temp-clone -- Implements creation of temporary datablock clones to allow late substitution of datablock fields.

This commit is contained in:
Marc Chapman 2017-07-26 21:10:43 +01:00
parent 83c533249f
commit 43815793d1
24 changed files with 865 additions and 11 deletions

View file

@ -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<SFXProfile*>(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() );

View file

@ -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

View file

@ -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);
}

View file

@ -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);

View file

@ -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;

View file

@ -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; }
};
//*****************************************************************************