Torque3D/Engine/source/afx/ea/afxEA_ParticleEmitter.cpp
marauder2k7 2b295fb7f0 rest of virtuals removed
virtuals removed and replaced with override where necessary on the rest of the code base, clang-tidy to the rescue.
2024-03-18 18:40:22 +00:00

337 lines
11 KiB
C++

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
// Copyright (C) 2015 Faust Logic, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
#include <typeinfo>
#include "afx/arcaneFX.h"
#if defined(STOCK_TGE_PARTICLES)
#include "game/fx/particleEngine.h"
#else
#include "afx/ce/afxParticleEmitter.h"
#endif
#include "afx/afxEffectDefs.h"
#include "afx/afxEffectWrapper.h"
#include "afx/afxChoreographer.h"
#include "afx/ea/afxEA_ParticleEmitter.h"
#include "afx/util/afxParticlePool.h"
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// afxEA_ParticleEmitter
afxEA_ParticleEmitter::afxEA_ParticleEmitter()
{
emitter_data = 0;
emitter = 0;
do_bbox_update = false;
}
afxEA_ParticleEmitter::~afxEA_ParticleEmitter()
{
if (emitter)
{
clearNotify(emitter);
emitter->deleteWhenEmpty();
emitter = 0;
}
}
void afxEA_ParticleEmitter::ea_set_datablock(SimDataBlock* db)
{
emitter_data = dynamic_cast<ParticleEmitterData*>(db);
}
bool afxEA_ParticleEmitter::ea_start()
{
if (!emitter_data)
{
Con::errorf("afxEA_ParticleEmitter::ea_start() -- missing or incompatible datablock.");
return false;
}
do_runtime_substitutions();
#if defined(STOCK_TGE_PARTICLES)
emitter = new ParticleEmitter();
emitter->onNewDataBlock(emitter_data);
#else
afxParticleEmitterData* afx_emitter_db = dynamic_cast<afxParticleEmitterData*>(emitter_data);
if (afx_emitter_db)
{
if (dynamic_cast<afxParticleEmitterVectorData*>(emitter_data))
{
afxParticleEmitterVector* pe = new afxParticleEmitterVector();
pe->onNewDataBlock(afx_emitter_db, false);
pe->setAFXOwner(mChoreographer);
emitter = pe;
}
else if (dynamic_cast<afxParticleEmitterConeData*>(emitter_data))
{
afxParticleEmitterCone* pe = new afxParticleEmitterCone();
pe->onNewDataBlock(afx_emitter_db, false);
pe->setAFXOwner(mChoreographer);
emitter = pe;
}
else if (dynamic_cast<afxParticleEmitterPathData*>(emitter_data))
{
afxParticleEmitterPath* pe = new afxParticleEmitterPath();
pe->onNewDataBlock(afx_emitter_db, false);
pe->setAFXOwner(mChoreographer);
emitter = pe;
}
else if (dynamic_cast<afxParticleEmitterDiscData*>(emitter_data))
{
afxParticleEmitterDisc* pe = new afxParticleEmitterDisc();
pe->onNewDataBlock(afx_emitter_db, false);
pe->setAFXOwner(mChoreographer);
emitter = pe;
}
}
else
{
emitter = new ParticleEmitter();
emitter->onNewDataBlock(emitter_data, false);
}
#endif
#if defined(AFX_CAP_PARTICLE_POOLS)
// here we find or create any required particle-pools
if (emitter_data->pool_datablock)
{
afxParticlePool* pool = mChoreographer->findParticlePool(emitter_data->pool_datablock, emitter_data->pool_index);
if (!pool)
{
afxParticlePoolData* pool_data = emitter_data->pool_datablock;
if (pool_data->getSubstitutionCount() > 0)
{
// clone the datablock and perform substitutions
afxParticlePoolData* orig_db = pool_data;
pool_data = new afxParticlePoolData(*orig_db, true);
orig_db->performSubstitutions(pool_data, mChoreographer, mGroup_index);
}
pool = new afxParticlePool();
pool->onNewDataBlock(pool_data, false);
pool->setKeyBlock(emitter_data->pool_datablock, emitter_data->pool_index);
if (!pool->registerObject())
{
Con::errorf("afxEA_ParticleEmitter::ea_start() -- Failed to register Particle Pool.");
delete pool;
pool = 0;
}
if (pool)
{
pool->setChoreographer(mChoreographer);
mChoreographer->registerParticlePool(pool);
}
}
if (pool)
emitter->setPool(pool);
}
#endif
if (!emitter->registerObject())
{
delete emitter;
emitter = NULL;
Con::errorf("afxEA_ParticleEmitter::ea_start() -- effect failed to register.");
return false;
}
if (mDatablock->forced_bbox.isValidBox())
{
do_bbox_update = true;
}
emitter->setSortPriority(mDatablock->sort_priority);
deleteNotify(emitter);
return true;
}
bool afxEA_ParticleEmitter::ea_update(F32 dt)
{
if (emitter && mIn_scope)
{
if (do_bbox_update)
{
Box3F bbox = emitter->getObjBox();
bbox.minExtents = mUpdated_pos + mDatablock->forced_bbox.minExtents;
bbox.maxExtents = mUpdated_pos + mDatablock->forced_bbox.maxExtents;
emitter->setForcedObjBox(bbox);
emitter->setTransform(emitter->getTransform());
if (!mDatablock->update_forced_bbox)
do_bbox_update = false;
}
if (mDo_fades)
emitter->setFadeAmount(mFade_value);
emitter->emitParticlesExt(mUpdated_xfm, mUpdated_pos, Point3F(0.0,0.0,0.0), (U32)(dt*1000));
}
return true;
}
void afxEA_ParticleEmitter::ea_finish(bool was_stopped)
{
if (arcaneFX::isShutdown())
return;
if (emitter)
{
// make sure particles are fully faded.
// note - fully faded particles are not always
// invisible, so they are still kept alive and
// deleted via deleteWhenEmpty().
if (mEW_timing.fade_out_time > 0.0f)
emitter->setFadeAmount(0.0f);
if (dynamic_cast<afxParticleEmitter*>(emitter))
((afxParticleEmitter*)emitter)->setAFXOwner(0);
clearNotify(emitter);
emitter->deleteWhenEmpty();
emitter = 0;
}
}
void afxEA_ParticleEmitter::do_runtime_substitutions()
{
bool clone_particles = false;
for (S32 i = 0; i < emitter_data->particleDataBlocks.size(); i++)
{
if (emitter_data->particleDataBlocks[i] && (emitter_data->particleDataBlocks[i]->getSubstitutionCount() > 0))
{
clone_particles = true;
break;
}
}
if (clone_particles || (emitter_data->getSubstitutionCount() > 0))
{
afxParticleEmitterData* afx_emitter_db = dynamic_cast<afxParticleEmitterData*>(emitter_data);
if (afx_emitter_db)
{
if (dynamic_cast<afxParticleEmitterVectorData*>(emitter_data))
{
afxParticleEmitterVectorData* orig_db = (afxParticleEmitterVectorData*)emitter_data;
emitter_data = new afxParticleEmitterVectorData(*orig_db, true);
orig_db->performSubstitutions(emitter_data, mChoreographer, mGroup_index);
}
else if (dynamic_cast<afxParticleEmitterConeData*>(emitter_data))
{
afxParticleEmitterConeData* orig_db = (afxParticleEmitterConeData*)emitter_data;
emitter_data = new afxParticleEmitterConeData(*orig_db, true);
orig_db->performSubstitutions(emitter_data, mChoreographer, mGroup_index);
}
else if (dynamic_cast<afxParticleEmitterPathData*>(emitter_data))
{
afxParticleEmitterPathData* orig_db = (afxParticleEmitterPathData*)emitter_data;
emitter_data = new afxParticleEmitterPathData(*orig_db, true);
orig_db->performSubstitutions(emitter_data, mChoreographer, mGroup_index);
}
else if (dynamic_cast<afxParticleEmitterDiscData*>(emitter_data))
{
afxParticleEmitterDiscData* orig_db = (afxParticleEmitterDiscData*)emitter_data;
emitter_data = new afxParticleEmitterDiscData(*orig_db, true);
orig_db->performSubstitutions(emitter_data, mChoreographer, mGroup_index);
}
}
else
{
ParticleEmitterData* orig_db = emitter_data;
emitter_data = new ParticleEmitterData(*orig_db, true);
orig_db->performSubstitutions(emitter_data, mChoreographer, mGroup_index);
}
if (clone_particles)
{
for (S32 i = 0; i < emitter_data->particleDataBlocks.size(); i++)
{
if (emitter_data->particleDataBlocks[i] && (emitter_data->particleDataBlocks[i]->getSubstitutionCount() > 0))
{
// clone the datablock and perform substitutions
ParticleData* orig_db = emitter_data->particleDataBlocks[i];
emitter_data->particleDataBlocks[i] = new ParticleData(*orig_db, true);
orig_db->performSubstitutions(emitter_data->particleDataBlocks[i], mChoreographer, mGroup_index);
}
}
}
}
}
void afxEA_ParticleEmitter::onDeleteNotify(SimObject* obj)
{
if (emitter == dynamic_cast<ParticleEmitter*>(obj))
emitter = 0;
Parent::onDeleteNotify(obj);
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
class afxEA_ParticleEmitterDesc : public afxEffectAdapterDesc, public afxEffectDefs
{
static afxEA_ParticleEmitterDesc desc;
public:
bool testEffectType(const SimDataBlock*) const override;
bool requiresStop(const afxEffectWrapperData*, const afxEffectTimingData&) const override;
bool runsOnServer(const afxEffectWrapperData*) const override { return false; }
bool runsOnClient(const afxEffectWrapperData*) const override { return true; }
afxEffectWrapper* create() const override { return new afxEA_ParticleEmitter; }
};
afxEA_ParticleEmitterDesc afxEA_ParticleEmitterDesc::desc;
bool afxEA_ParticleEmitterDesc::testEffectType(const SimDataBlock* db) const
{
#if defined(STOCK_TGE_PARTICLES)
return (typeid(ParticleEmitterData) == typeid(*db));
#else
if (typeid(ParticleEmitterData) == typeid(*db))
return true;
if (typeid(afxParticleEmitterVectorData) == typeid(*db))
return true;
if (typeid(afxParticleEmitterConeData) == typeid(*db))
return true;
if (typeid(afxParticleEmitterPathData) == typeid(*db))
return true;
if (typeid(afxParticleEmitterDiscData) == typeid(*db))
return true;
return false;
#endif
}
bool afxEA_ParticleEmitterDesc::requiresStop(const afxEffectWrapperData* ew, const afxEffectTimingData& timing) const
{
return (timing.lifetime < 0);
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//