afxEA_ParticleEmitter.cpp
Engine/source/afx/ea/afxEA_ParticleEmitter.cpp
Classes:
Detailed Description
1 2 3//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 4// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames 5// Copyright (C) 2015 Faust Logic, Inc. 6// 7// Permission is hereby granted, free of charge, to any person obtaining a copy 8// of this software and associated documentation files (the "Software"), to 9// deal in the Software without restriction, including without limitation the 10// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11// sell copies of the Software, and to permit persons to whom the Software is 12// furnished to do so, subject to the following conditions: 13// 14// The above copyright notice and this permission notice shall be included in 15// all copies or substantial portions of the Software. 16// 17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23// IN THE SOFTWARE. 24// 25//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 26 27#include <typeinfo> 28#include "afx/arcaneFX.h" 29 30#if defined(STOCK_TGE_PARTICLES) 31#include "game/fx/particleEngine.h" 32#else 33#include "afx/ce/afxParticleEmitter.h" 34#endif 35 36#include "afx/afxEffectDefs.h" 37#include "afx/afxEffectWrapper.h" 38#include "afx/afxChoreographer.h" 39#include "afx/ea/afxEA_ParticleEmitter.h" 40#include "afx/util/afxParticlePool.h" 41 42//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 43// afxEA_ParticleEmitter 44 45afxEA_ParticleEmitter::afxEA_ParticleEmitter() 46{ 47 emitter_data = 0; 48 emitter = 0; 49 do_bbox_update = false; 50} 51 52afxEA_ParticleEmitter::~afxEA_ParticleEmitter() 53{ 54 if (emitter) 55 { 56 clearNotify(emitter); 57 emitter->deleteWhenEmpty(); 58 emitter = 0; 59 } 60} 61 62void afxEA_ParticleEmitter::ea_set_datablock(SimDataBlock* db) 63{ 64 emitter_data = dynamic_cast<ParticleEmitterData*>(db); 65} 66 67bool afxEA_ParticleEmitter::ea_start() 68{ 69 if (!emitter_data) 70 { 71 Con::errorf("afxEA_ParticleEmitter::ea_start() -- missing or incompatible datablock."); 72 return false; 73 } 74 75 do_runtime_substitutions(); 76 77#if defined(STOCK_TGE_PARTICLES) 78 emitter = new ParticleEmitter(); 79 emitter->onNewDataBlock(emitter_data); 80#else 81 afxParticleEmitterData* afx_emitter_db = dynamic_cast<afxParticleEmitterData*>(emitter_data); 82 if (afx_emitter_db) 83 { 84 if (dynamic_cast<afxParticleEmitterVectorData*>(emitter_data)) 85 { 86 afxParticleEmitterVector* pe = new afxParticleEmitterVector(); 87 pe->onNewDataBlock(afx_emitter_db, false); 88 pe->setAFXOwner(mChoreographer); 89 emitter = pe; 90 } 91 else if (dynamic_cast<afxParticleEmitterConeData*>(emitter_data)) 92 { 93 afxParticleEmitterCone* pe = new afxParticleEmitterCone(); 94 pe->onNewDataBlock(afx_emitter_db, false); 95 pe->setAFXOwner(mChoreographer); 96 emitter = pe; 97 } 98 else if (dynamic_cast<afxParticleEmitterPathData*>(emitter_data)) 99 { 100 afxParticleEmitterPath* pe = new afxParticleEmitterPath(); 101 pe->onNewDataBlock(afx_emitter_db, false); 102 pe->setAFXOwner(mChoreographer); 103 emitter = pe; 104 } 105 else if (dynamic_cast<afxParticleEmitterDiscData*>(emitter_data)) 106 { 107 afxParticleEmitterDisc* pe = new afxParticleEmitterDisc(); 108 pe->onNewDataBlock(afx_emitter_db, false); 109 pe->setAFXOwner(mChoreographer); 110 emitter = pe; 111 } 112 } 113 else 114 { 115 emitter = new ParticleEmitter(); 116 emitter->onNewDataBlock(emitter_data, false); 117 } 118#endif 119 120#if defined(AFX_CAP_PARTICLE_POOLS) 121 // here we find or create any required particle-pools 122 if (emitter_data->pool_datablock) 123 { 124 afxParticlePool* pool = mChoreographer->findParticlePool(emitter_data->pool_datablock, emitter_data->pool_index); 125 if (!pool) 126 { 127 afxParticlePoolData* pool_data = emitter_data->pool_datablock; 128 if (pool_data->getSubstitutionCount() > 0) 129 { 130 // clone the datablock and perform substitutions 131 afxParticlePoolData* orig_db = pool_data; 132 pool_data = new afxParticlePoolData(*orig_db, true); 133 orig_db->performSubstitutions(pool_data, mChoreographer, mGroup_index); 134 } 135 136 pool = new afxParticlePool(); 137 pool->onNewDataBlock(pool_data, false); 138 pool->setKeyBlock(emitter_data->pool_datablock, emitter_data->pool_index); 139 if (!pool->registerObject()) 140 { 141 Con::errorf("afxEA_ParticleEmitter::ea_start() -- Failed to register Particle Pool."); 142 delete pool; 143 pool = 0; 144 } 145 if (pool) 146 { 147 pool->setChoreographer(mChoreographer); 148 mChoreographer->registerParticlePool(pool); 149 } 150 } 151 if (pool) 152 emitter->setPool(pool); 153 } 154#endif 155 156 if (!emitter->registerObject()) 157 { 158 delete emitter; 159 emitter = NULL; 160 Con::errorf("afxEA_ParticleEmitter::ea_start() -- effect failed to register."); 161 return false; 162 } 163 164 if (mDatablock->forced_bbox.isValidBox()) 165 { 166 do_bbox_update = true; 167 } 168 169 emitter->setSortPriority(mDatablock->sort_priority); 170 deleteNotify(emitter); 171 172 return true; 173} 174 175bool afxEA_ParticleEmitter::ea_update(F32 dt) 176{ 177 if (emitter && mIn_scope) 178 { 179 if (do_bbox_update) 180 { 181 Box3F bbox = emitter->getObjBox(); 182 183 bbox.minExtents = mUpdated_pos + mDatablock->forced_bbox.minExtents; 184 bbox.maxExtents = mUpdated_pos + mDatablock->forced_bbox.maxExtents; 185 186 emitter->setForcedObjBox(bbox); 187 emitter->setTransform(emitter->getTransform()); 188 189 if (!mDatablock->update_forced_bbox) 190 do_bbox_update = false; 191 } 192 193 if (mDo_fades) 194 emitter->setFadeAmount(mFade_value); 195 196 emitter->emitParticlesExt(mUpdated_xfm, mUpdated_pos, Point3F(0.0,0.0,0.0), (U32)(dt*1000)); 197 } 198 199 return true; 200} 201 202void afxEA_ParticleEmitter::ea_finish(bool was_stopped) 203{ 204 if (arcaneFX::isShutdown()) 205 return; 206 207 if (emitter) 208 { 209 // make sure particles are fully faded. 210 // note - fully faded particles are not always 211 // invisible, so they are still kept alive and 212 // deleted via deleteWhenEmpty(). 213 if (mEW_timing.fade_out_time > 0.0f) 214 emitter->setFadeAmount(0.0f); 215 if (dynamic_cast<afxParticleEmitter*>(emitter)) 216 ((afxParticleEmitter*)emitter)->setAFXOwner(0); 217 clearNotify(emitter); 218 emitter->deleteWhenEmpty(); 219 emitter = 0; 220 } 221} 222 223void afxEA_ParticleEmitter::do_runtime_substitutions() 224{ 225 bool clone_particles = false; 226 for (S32 i = 0; i < emitter_data->particleDataBlocks.size(); i++) 227 { 228 if (emitter_data->particleDataBlocks[i] && (emitter_data->particleDataBlocks[i]->getSubstitutionCount() > 0)) 229 { 230 clone_particles = true; 231 break; 232 } 233 } 234 235 if (clone_particles || (emitter_data->getSubstitutionCount() > 0)) 236 { 237 afxParticleEmitterData* afx_emitter_db = dynamic_cast<afxParticleEmitterData*>(emitter_data); 238 if (afx_emitter_db) 239 { 240 if (dynamic_cast<afxParticleEmitterVectorData*>(emitter_data)) 241 { 242 afxParticleEmitterVectorData* orig_db = (afxParticleEmitterVectorData*)emitter_data; 243 emitter_data = new afxParticleEmitterVectorData(*orig_db, true); 244 orig_db->performSubstitutions(emitter_data, mChoreographer, mGroup_index); 245 } 246 else if (dynamic_cast<afxParticleEmitterConeData*>(emitter_data)) 247 { 248 afxParticleEmitterConeData* orig_db = (afxParticleEmitterConeData*)emitter_data; 249 emitter_data = new afxParticleEmitterConeData(*orig_db, true); 250 orig_db->performSubstitutions(emitter_data, mChoreographer, mGroup_index); 251 } 252 else if (dynamic_cast<afxParticleEmitterPathData*>(emitter_data)) 253 { 254 afxParticleEmitterPathData* orig_db = (afxParticleEmitterPathData*)emitter_data; 255 emitter_data = new afxParticleEmitterPathData(*orig_db, true); 256 orig_db->performSubstitutions(emitter_data, mChoreographer, mGroup_index); 257 } 258 else if (dynamic_cast<afxParticleEmitterDiscData*>(emitter_data)) 259 { 260 afxParticleEmitterDiscData* orig_db = (afxParticleEmitterDiscData*)emitter_data; 261 emitter_data = new afxParticleEmitterDiscData(*orig_db, true); 262 orig_db->performSubstitutions(emitter_data, mChoreographer, mGroup_index); 263 } 264 } 265 else 266 { 267 ParticleEmitterData* orig_db = emitter_data; 268 emitter_data = new ParticleEmitterData(*orig_db, true); 269 orig_db->performSubstitutions(emitter_data, mChoreographer, mGroup_index); 270 } 271 272 if (clone_particles) 273 { 274 for (S32 i = 0; i < emitter_data->particleDataBlocks.size(); i++) 275 { 276 if (emitter_data->particleDataBlocks[i] && (emitter_data->particleDataBlocks[i]->getSubstitutionCount() > 0)) 277 { 278 // clone the datablock and perform substitutions 279 ParticleData* orig_db = emitter_data->particleDataBlocks[i]; 280 emitter_data->particleDataBlocks[i] = new ParticleData(*orig_db, true); 281 orig_db->performSubstitutions(emitter_data->particleDataBlocks[i], mChoreographer, mGroup_index); 282 } 283 } 284 } 285 } 286} 287 288void afxEA_ParticleEmitter::onDeleteNotify(SimObject* obj) 289{ 290 if (emitter == dynamic_cast<ParticleEmitter*>(obj)) 291 emitter = 0; 292 293 Parent::onDeleteNotify(obj); 294} 295 296//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 297 298class afxEA_ParticleEmitterDesc : public afxEffectAdapterDesc, public afxEffectDefs 299{ 300 static afxEA_ParticleEmitterDesc desc; 301 302public: 303 virtual bool testEffectType(const SimDataBlock*) const; 304 virtual bool requiresStop(const afxEffectWrapperData*, const afxEffectTimingData&) const; 305 virtual bool runsOnServer(const afxEffectWrapperData*) const { return false; } 306 virtual bool runsOnClient(const afxEffectWrapperData*) const { return true; } 307 308 virtual afxEffectWrapper* create() const { return new afxEA_ParticleEmitter; } 309}; 310 311afxEA_ParticleEmitterDesc afxEA_ParticleEmitterDesc::desc; 312 313bool afxEA_ParticleEmitterDesc::testEffectType(const SimDataBlock* db) const 314{ 315#if defined(STOCK_TGE_PARTICLES) 316 return (typeid(ParticleEmitterData) == typeid(*db)); 317#else 318 if (typeid(ParticleEmitterData) == typeid(*db)) 319 return true; 320 if (typeid(afxParticleEmitterVectorData) == typeid(*db)) 321 return true; 322 if (typeid(afxParticleEmitterConeData) == typeid(*db)) 323 return true; 324 if (typeid(afxParticleEmitterPathData) == typeid(*db)) 325 return true; 326 if (typeid(afxParticleEmitterDiscData) == typeid(*db)) 327 return true; 328 329 return false; 330#endif 331} 332 333bool afxEA_ParticleEmitterDesc::requiresStop(const afxEffectWrapperData* ew, const afxEffectTimingData& timing) const 334{ 335 return (timing.lifetime < 0); 336} 337 338//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 339