ParticleAsset.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "console/consoleTypes.h"
  23. #include "2d/assets/ParticleAsset.h"
  24. // Script bindings.
  25. #include "ParticleAsset_ScriptBinding.h"
  26. // Debug Profiling.
  27. #include "debug/profiler.h"
  28. //------------------------------------------------------------------------------
  29. static EnumTable::Enums particleAssetLifeModeLookup[] =
  30. {
  31. { ParticleAsset::INFINITE, "INFINITE" },
  32. { ParticleAsset::CYCLE, "CYCLE" },
  33. { ParticleAsset::STOP, "STOP" },
  34. { ParticleAsset::KILL, "KILL" },
  35. };
  36. //-----------------------------------------------------------------------------
  37. static EnumTable LifeModeTable(sizeof(particleAssetLifeModeLookup) / sizeof(EnumTable::Enums), &particleAssetLifeModeLookup[0]);
  38. //-----------------------------------------------------------------------------
  39. ParticleAsset::LifeMode ParticleAsset::getParticleAssetLifeModeEnum( const char* label )
  40. {
  41. // Search for Mnemonic.
  42. for(U32 i = 0; i < (sizeof(particleAssetLifeModeLookup) / sizeof(EnumTable::Enums)); i++)
  43. if( dStricmp(particleAssetLifeModeLookup[i].label, label) == 0)
  44. return((ParticleAsset::LifeMode)particleAssetLifeModeLookup[i].index);
  45. // Warn.
  46. Con::warnf( "ParticleAsset::getParticleAssetLifeModeEnum() - Invalid life mode '%s'.", label );
  47. return ParticleAsset::INVALID_LIFEMODE;
  48. }
  49. //-----------------------------------------------------------------------------
  50. const char* ParticleAsset::getParticleAssetLifeModeDescription( const ParticleAsset::LifeMode lifeMode )
  51. {
  52. // Search for Mnemonic.
  53. for (U32 i = 0; i < (sizeof(particleAssetLifeModeLookup) / sizeof(EnumTable::Enums)); i++)
  54. {
  55. if( particleAssetLifeModeLookup[i].index == (S32)lifeMode )
  56. return particleAssetLifeModeLookup[i].label;
  57. }
  58. // Warn.
  59. Con::warnf( "ParticleAsset::getParticleAssetLifeModeDescription() - Invalid life-mode." );
  60. return StringTable->EmptyString;
  61. }
  62. //-----------------------------------------------------------------------------
  63. ConsoleType( particleAssetPtr, TypeParticleAssetPtr, sizeof(AssetPtr<ParticleAsset>), ASSET_ID_FIELD_PREFIX )
  64. //-----------------------------------------------------------------------------
  65. ConsoleGetType( TypeParticleAssetPtr )
  66. {
  67. // Fetch asset Id.
  68. return (*((AssetPtr<ParticleAsset>*)dptr)).getAssetId();
  69. }
  70. //-----------------------------------------------------------------------------
  71. ConsoleSetType( TypeParticleAssetPtr )
  72. {
  73. // Was a single argument specified?
  74. if( argc == 1 )
  75. {
  76. // Yes, so fetch field value.
  77. const char* pFieldValue = argv[0];
  78. // Fetch asset pointer.
  79. AssetPtr<ParticleAsset>* pAssetPtr = dynamic_cast<AssetPtr<ParticleAsset>*>((AssetPtrBase*)(dptr));
  80. // Is the asset pointer the correct type?
  81. if ( pAssetPtr == NULL )
  82. {
  83. // No, so fail.
  84. Con::warnf( "(TypeParticleAssetPtr) - Failed to set asset Id '%d'.", pFieldValue );
  85. return;
  86. }
  87. // Set asset.
  88. pAssetPtr->setAssetId( pFieldValue );
  89. return;
  90. }
  91. // Warn.
  92. Con::warnf( "(TypeParticleAssetPtr) - Cannot set multiple args to a single asset." );
  93. }
  94. //------------------------------------------------------------------------------
  95. ParticleAsset::ParticleAsset() :
  96. mLifetime( 0.0f ),
  97. mLifeMode( INFINITE )
  98. {
  99. // Set Vector Associations.
  100. VECTOR_SET_ASSOCIATION( mEmitters );
  101. // Initialize particle fields.
  102. mParticleFields.addField( mParticleLifeScale.getBase(), "LifetimeScale", 1000.0f, 0.0f, 100.0f, 1.0f );
  103. mParticleFields.addField( mQuantityScale.getBase(), "QuantityScale", 1000.0f, 0.0f, 100.0f, 1.0f );
  104. mParticleFields.addField( mSizeXScale.getBase(), "SizeXScale", 1000.0f, 0.0f, 100.0f, 1.0f );
  105. mParticleFields.addField( mSizeYScale.getBase(), "SizeYScale", 1000.0f, 0.0f, 100.0f, 1.0f );
  106. mParticleFields.addField( mSpeedScale.getBase(), "SpeedScale", 1000.0f, 0.0f, 100.0f, 1.0f );
  107. mParticleFields.addField( mSpinScale.getBase(), "SpinScale", 1000.0f, -100.0f, 100.0f, 1.0f );
  108. mParticleFields.addField( mFixedForceScale.getBase(), "FixedForceScale", 1000.0f, -100.0f, 100.0f, 1.0f );
  109. mParticleFields.addField( mRandomMotionScale.getBase(), "RandomMotionScale", 1000.0f, 0.0f, 100.0f, 1.0f );
  110. mParticleFields.addField( mAlphaChannelScale.getBase(), "AlphaChannelScale", 1000.0f, 0.0f, 100.0f, 1.0f );
  111. }
  112. //------------------------------------------------------------------------------
  113. ParticleAsset::~ParticleAsset()
  114. {
  115. // Clear the emitters.
  116. clearEmitters();
  117. }
  118. //------------------------------------------------------------------------------
  119. void ParticleAsset::initPersistFields()
  120. {
  121. // Call parent.
  122. Parent::initPersistFields();
  123. addProtectedField("Lifetime", TypeF32, Offset(mLifetime, ParticleAsset), &setLifetime, &defaultProtectedGetFn, &writeLifetime, "");
  124. addProtectedField("LifeMode", TypeEnum, Offset(mLifeMode, ParticleAsset), &setLifeMode, &defaultProtectedGetFn, &writeLifeMode, 1, &LifeModeTable);
  125. }
  126. //------------------------------------------------------------------------------
  127. void ParticleAsset::copyTo(SimObject* object)
  128. {
  129. // Fetch particle asset object.
  130. ParticleAsset* pParticleAsset = static_cast<ParticleAsset*>( object );
  131. // Sanity!
  132. AssertFatal( pParticleAsset != NULL, "ParticleAsset::copyTo() - Object is not the correct type.");
  133. // Copy parent.
  134. Parent::copyTo( object );
  135. // Copy fields.
  136. pParticleAsset->setLifetime( getLifetime() );
  137. pParticleAsset->setLifeMode( getLifeMode() );
  138. // Copy particle fields.
  139. mParticleFields.copyTo( pParticleAsset->mParticleFields );
  140. // Copy the emitters.
  141. pParticleAsset->clearEmitters();
  142. const U32 emitterCount = getEmitterCount();
  143. for ( U32 index = 0; index < emitterCount; ++index )
  144. {
  145. // Fetch emitter.
  146. ParticleAssetEmitter* pParticleAssetEmitter = getEmitter( index );
  147. // Create a new emitter.
  148. ParticleAssetEmitter* pNewEmitter = new ParticleAssetEmitter();
  149. pParticleAsset->addEmitter( pNewEmitter );
  150. // Copy emitter.
  151. pParticleAssetEmitter->copyTo( pNewEmitter );
  152. }
  153. }
  154. //------------------------------------------------------------------------------
  155. void ParticleAsset::onDeleteNotify( SimObject* object )
  156. {
  157. // Fetch emitter.
  158. ParticleAssetEmitter* pParticleAssetEmitter = dynamic_cast<ParticleAssetEmitter*>( object );
  159. // Ignore if not an emitter.
  160. if ( pParticleAssetEmitter == NULL )
  161. return;
  162. // Iterate emitters.
  163. for ( typeEmitterVector::iterator emitterItr = mEmitters.begin(); emitterItr != mEmitters.end(); ++emitterItr )
  164. {
  165. // Is this the emitter being deleted?
  166. if ( *emitterItr == object )
  167. {
  168. // Yes, so remove it.
  169. mEmitters.erase( emitterItr );
  170. return;
  171. }
  172. }
  173. }
  174. //------------------------------------------------------------------------------
  175. bool ParticleAsset::isAssetValid( void ) const
  176. {
  177. return mEmitters.size() > 0;
  178. }
  179. //------------------------------------------------------------------------------
  180. void ParticleAsset::setLifetime( const F32 lifetime )
  181. {
  182. // Ignore no change.
  183. if ( mIsEqual( lifetime, mLifetime ) )
  184. return;
  185. // Is lifetime valid?
  186. if ( lifetime < 0.0f )
  187. {
  188. // No, so warn.
  189. Con::warnf( "ParticleAsset::setLifetime() - Lifetime cannot be negative." );
  190. return;
  191. }
  192. mLifetime = lifetime;
  193. // Refresh the asset.
  194. refreshAsset();
  195. }
  196. //------------------------------------------------------------------------------
  197. void ParticleAsset::setLifeMode( const LifeMode lifemode )
  198. {
  199. // Ignore no change.
  200. if ( lifemode == mLifeMode )
  201. return;
  202. // Is life mode valid?
  203. if ( lifemode == INVALID_LIFEMODE )
  204. {
  205. // No, so warn.
  206. Con::warnf( "ParticleAsset::setLifeMode() - Life mode is invalid." );
  207. return;
  208. }
  209. mLifeMode = lifemode;
  210. // Refresh the asset.
  211. refreshAsset();
  212. }
  213. //------------------------------------------------------------------------------
  214. void ParticleAsset::initializeAsset( void )
  215. {
  216. // Call parent.
  217. Parent::initializeAsset();
  218. // Currently there is no specific initialization required.
  219. }
  220. //-----------------------------------------------------------------------------
  221. ParticleAssetEmitter* ParticleAsset::createEmitter( void )
  222. {
  223. // Create an emitter.
  224. ParticleAssetEmitter* pParticleAssetEmitter = new ParticleAssetEmitter();
  225. // Add the emitter.
  226. if ( addEmitter( pParticleAssetEmitter ) )
  227. return pParticleAssetEmitter;
  228. // Error.
  229. delete pParticleAssetEmitter;
  230. return NULL;
  231. }
  232. //-----------------------------------------------------------------------------
  233. bool ParticleAsset::addEmitter( ParticleAssetEmitter* pParticleAssetEmitter )
  234. {
  235. // Sanity!
  236. AssertFatal( pParticleAssetEmitter != NULL, "Cannot add a NULL particle asset emitter." );
  237. // Does the particle already have an owner?
  238. if ( pParticleAssetEmitter->getOwner() != NULL )
  239. {
  240. Con::warnf( "ParticleAsset::addEmitter() - Cannot add a particle asset emitter that already has an owner." );
  241. return false;
  242. }
  243. // Is the emitter registered?
  244. if ( !pParticleAssetEmitter->isProperlyAdded() )
  245. {
  246. // No, so register it.
  247. if ( !pParticleAssetEmitter->registerObject() )
  248. {
  249. // Failed so warn.
  250. Con::warnf( "ParticleAsset::addEmitter() - Failed to register emitter." );
  251. return false;
  252. }
  253. }
  254. // Set the owner.
  255. pParticleAssetEmitter->setOwner( this );
  256. // Add the emitter.
  257. mEmitters.push_back( pParticleAssetEmitter );
  258. // Start delete notify.
  259. deleteNotify( pParticleAssetEmitter );
  260. return true;
  261. }
  262. //------------------------------------------------------------------------------
  263. void ParticleAsset::removeEmitter( ParticleAssetEmitter* pParticleAssetEmitter, const bool deleteEmitter )
  264. {
  265. // Sanity!
  266. AssertFatal( pParticleAssetEmitter != NULL, "Cannot remove a NULL particle asset emitter." );
  267. // Is this emitter owned by this asset?
  268. if ( pParticleAssetEmitter->getOwner() != this )
  269. {
  270. // No, so warn.
  271. Con::warnf( "ParticleAsset::removeEmitter() - Cannot remove the particle emitter as it is not owned by this particle asset." );
  272. return;
  273. }
  274. // Iterate emitters.
  275. for ( typeEmitterVector::iterator emitterItr = mEmitters.begin(); emitterItr != mEmitters.end(); ++emitterItr )
  276. {
  277. if ( *emitterItr == pParticleAssetEmitter )
  278. {
  279. // Remove emitter.
  280. mEmitters.erase( emitterItr );
  281. // Remove owner.
  282. pParticleAssetEmitter->setOwner( NULL );
  283. // Stop delete notify.
  284. clearNotify( pParticleAssetEmitter );
  285. // If requested, delete the emitter.
  286. if ( deleteEmitter )
  287. pParticleAssetEmitter->deleteObject();
  288. return;
  289. }
  290. }
  291. // Warn.
  292. Con::warnf( "ParticleAsset::removeEmitter() - Cannot remove the particle emitter as it is not part of this particle asset." );
  293. }
  294. //------------------------------------------------------------------------------
  295. void ParticleAsset::clearEmitters( void )
  296. {
  297. // Remove all emitters.
  298. while( mEmitters.size() > 0 )
  299. {
  300. mEmitters.last()->deleteObject();
  301. mEmitters.pop_back();
  302. }
  303. }
  304. //------------------------------------------------------------------------------
  305. ParticleAssetEmitter* ParticleAsset::getEmitter( const U32 emitterIndex ) const
  306. {
  307. // Is emitter index valid?
  308. if ( emitterIndex >= (U32)mEmitters.size() )
  309. {
  310. // No, so warn.
  311. Con::warnf( "ParticleAsset::getEmitter() - Invalid emitter index." );
  312. return NULL;
  313. }
  314. return mEmitters[emitterIndex];
  315. }
  316. //------------------------------------------------------------------------------
  317. ParticleAssetEmitter* ParticleAsset::findEmitter( const char* pEmitterName ) const
  318. {
  319. // Sanity!
  320. AssertFatal( pEmitterName != NULL, "ParticleAsset::findEmitter() - Cannot find a NULL emitter name." );
  321. // Finish if there are no emitters.
  322. if ( getEmitterCount() == 0 )
  323. return NULL;
  324. // Fetch emitter name.
  325. StringTableEntry emitterName = StringTable->insert( pEmitterName );
  326. // Search for emitter..
  327. for( typeEmitterVector::const_iterator emitterItr = mEmitters.begin(); emitterItr != mEmitters.end(); ++emitterItr )
  328. {
  329. if ( (*emitterItr)->getEmitterName() == emitterName )
  330. return *emitterItr;
  331. }
  332. // Not found.
  333. return NULL;
  334. }
  335. //-----------------------------------------------------------------------------
  336. void ParticleAsset::moveEmitter( S32 fromIndex, S32 toIndex )
  337. {
  338. // Check From Emitter Index.
  339. if ( fromIndex < 0 || fromIndex >= (S32)getEmitterCount() )
  340. {
  341. // Warn.
  342. Con::warnf("ParticleAsset::moveEmitter() - Invalid From-Emitter-Index (%d)", fromIndex);
  343. return;
  344. }
  345. // Check To Emitter Index.
  346. if ( toIndex < 0 || toIndex >= (S32)getEmitterCount() )
  347. {
  348. // Warn.
  349. Con::warnf("ParticleAsset::moveEmitter() - Invalid To-Emitter-Index (%d)", toIndex);
  350. return;
  351. }
  352. // We need to skip an object if we're inserting above the object.
  353. if ( toIndex > fromIndex )
  354. toIndex++;
  355. else
  356. fromIndex++;
  357. // Fetch Emitter to be moved.
  358. typeEmitterVector::iterator fromItr = (mEmitters.address()+fromIndex);
  359. // Fetch Emitter to be inserted at.
  360. typeEmitterVector::iterator toItr = (mEmitters.address()+toIndex);
  361. // Insert Object at new Position.
  362. mEmitters.insert( toItr, (*fromItr) );
  363. // Remove Original Reference.
  364. mEmitters.erase( fromItr );
  365. }
  366. //------------------------------------------------------------------------------
  367. void ParticleAsset::onTamlCustomWrite( TamlCustomNodes& customNodes )
  368. {
  369. // Debug Profiling.
  370. PROFILE_SCOPE(ParticleAsset_OnTamlCustomWrite);
  371. // Write the fields.
  372. mParticleFields.onTamlCustomWrite( customNodes );
  373. }
  374. //-----------------------------------------------------------------------------
  375. void ParticleAsset::onTamlCustomRead( const TamlCustomNodes& customNodes )
  376. {
  377. // Debug Profiling.
  378. PROFILE_SCOPE(ParticleAsset_OnTamlCustomRead);
  379. // Read the fields.
  380. mParticleFields.onTamlCustomRead( customNodes );
  381. }
  382. //-----------------------------------------------------------------------------
  383. static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
  384. {
  385. // Sanity!
  386. AssertFatal( pClassRep != NULL, "ParticleAsset::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
  387. AssertFatal( pParentElement != NULL, "ParticleAsset::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
  388. // Write the particle asset fields.
  389. ParticleAsset particleAsset;
  390. particleAsset.getParticleFields().WriteCustomTamlSchema( pClassRep, pParentElement );
  391. }
  392. //-----------------------------------------------------------------------------
  393. IMPLEMENT_CONOBJECT_CHILDREN_SCHEMA(ParticleAsset, WriteCustomTamlSchema);