ParticleAssetField.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  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 "2d/assets/ParticleAssetField.h"
  23. #ifndef _CORE_MATH_H_
  24. #include "2d/core/CoreMath.h"
  25. #endif
  26. #ifndef _MMATH_H_
  27. #include "math/mMath.h"
  28. #endif
  29. #ifndef _SIMBASE_H_
  30. #include "sim/simBase.h"
  31. #endif
  32. #ifndef _STRINGUNIT_H_
  33. #include "string/stringUnit.h"
  34. #endif
  35. //-----------------------------------------------------------------------------
  36. static StringTableEntry particleAssetFieldRepeatTimeName = StringTable->insert( "RepeatTime" );
  37. static StringTableEntry particleAssetFieldMaxTimeName = StringTable->insert( "MaxTime" );
  38. static StringTableEntry particleAssetFieldMinValueName = StringTable->insert( "MinValue" );
  39. static StringTableEntry particleAssetFieldMaxValueName = StringTable->insert( "MaxValue" );
  40. static StringTableEntry particleAssetFieldDefaultValueName = StringTable->insert( "DefaultValue" );
  41. static StringTableEntry particleAssetFieldValueScaleName = StringTable->insert( "ValueScale" );
  42. static StringTableEntry particleAssetFieldDataKeysName = StringTable->insert( "Keys" );
  43. static StringTableEntry particleAssetFieldDataKeyName = StringTable->insert( "Key" );
  44. static StringTableEntry particleAssetFieldDataKeyTimeName = StringTable->insert( "Time" );
  45. static StringTableEntry particleAssetFieldDataKeyValueName = StringTable->insert( "Value" );
  46. ParticleAssetField::DataKey ParticleAssetField::BadDataKey( -1.0f, 0.0f );
  47. //-----------------------------------------------------------------------------
  48. ParticleAssetField::ParticleAssetField() :
  49. mFieldName( StringTable->EmptyString ),
  50. mRepeatTime( 1.0f ),
  51. mMaxTime( 1.0f ),
  52. mMinValue( 0.0f ),
  53. mMaxValue( 0.0f ),
  54. mDefaultValue( 1.0f ),
  55. mValueScale( 1.0f ),
  56. mValueBoundsDirty( true )
  57. {
  58. // Set Vector Associations.
  59. VECTOR_SET_ASSOCIATION( mDataKeys );
  60. }
  61. //-----------------------------------------------------------------------------
  62. ParticleAssetField::~ParticleAssetField()
  63. {
  64. }
  65. //-----------------------------------------------------------------------------
  66. void ParticleAssetField::copyTo( ParticleAssetField& field )
  67. {
  68. field.mFieldName = mFieldName;
  69. field.mRepeatTime = mRepeatTime;
  70. field.mMaxTime = mMaxTime;
  71. field.mMinValue = mMinValue;
  72. field.mMaxValue = mMaxValue;
  73. field.mDefaultValue = mDefaultValue;
  74. field.mValueScale = mValueScale;
  75. // Copy data keys.
  76. field.clearDataKeys();
  77. for ( S32 i = 0; i < mDataKeys.size(); i++ )
  78. {
  79. DataKey key = mDataKeys[i];
  80. field.addDataKey(key.mTime, key.mValue);
  81. }
  82. }
  83. //-----------------------------------------------------------------------------
  84. void ParticleAssetField::initialize( const F32 maxTime, const F32 minValue, const F32 maxValue, const F32 defaultValue )
  85. {
  86. // Set the value bounds.
  87. setValueBounds( maxTime, minValue, maxValue, defaultValue );
  88. // Reset the value bounds dirty flag.
  89. mValueBoundsDirty = false;
  90. }
  91. //-----------------------------------------------------------------------------
  92. void ParticleAssetField::setValueBounds( F32 maxTime, F32 minValue, F32 maxValue, F32 defaultValue )
  93. {
  94. // Check Max Time.
  95. if ( maxTime <= 0.0f )
  96. {
  97. // Warn.
  98. Con::warnf("ParticleAssetField::setValueBounds() - Max-time '%f' is invalid", maxTime );
  99. // Set Default Max Time.
  100. maxTime = 1.0f;
  101. }
  102. // Set Max Time.
  103. mMaxTime = maxTime;
  104. // Check Value Range Normalisation.
  105. if ( minValue > maxValue )
  106. {
  107. // Warn.
  108. Con::warnf("ParticleAssetField::setValueBounds() - Value Range is not normalised! (minValue:%f / maxValue:%f)", minValue, maxValue );
  109. // Normalise Y-Axis.
  110. F32 temp = minValue;
  111. minValue = maxValue;
  112. maxValue = temp;
  113. }
  114. // Check Value Range Scale.
  115. else if ( minValue == maxValue )
  116. {
  117. // Warn.
  118. Con::warnf("ParticleAssetField::setValueBounds() - Value Range has no scale! (minValue:%f / maxValue:%f)", minValue, maxValue );
  119. // Insert some Y-Axis Scale.
  120. maxValue = minValue + 0.001f;
  121. }
  122. // Set Bounds.
  123. mMinValue = minValue;
  124. mMaxValue = maxValue;
  125. // Check Default Value.
  126. if ( defaultValue < minValue || defaultValue > maxValue )
  127. {
  128. // Warn.
  129. Con::warnf("ParticleAssetField::setValueBounds() - Default Value is out of range! (minValue:%f / maxValue:%f / defaultValue:%f)", minValue, maxValue, defaultValue );
  130. // Clamp at lower value.
  131. defaultValue = minValue;
  132. }
  133. // Set Default Value.
  134. mDefaultValue = defaultValue;
  135. // Reset the data keys if none are present.
  136. if ( mDataKeys.size() == 0 )
  137. resetDataKeys();
  138. // Flag the value bounds as dirty.
  139. mValueBoundsDirty = true;
  140. }
  141. //-----------------------------------------------------------------------------
  142. void ParticleAssetField::setFieldName( const char* pFieldName )
  143. {
  144. // Sanity!
  145. AssertFatal( mFieldName == StringTable->EmptyString, "ParticleAssetField::setFieldName() - Cannot set particle asset field name once it has been set." );
  146. mFieldName = StringTable->insert( pFieldName );
  147. // Sanity!
  148. AssertFatal( mFieldName != StringTable->EmptyString, "ParticleAssetField::setFieldName() - Field name cannot be empty." );
  149. }
  150. //-----------------------------------------------------------------------------
  151. bool ParticleAssetField::setRepeatTime( const F32 repeatTime )
  152. {
  153. // Check repeat time.
  154. if ( repeatTime < 0.0f )
  155. {
  156. // Warn.
  157. Con::warnf("ParticleAssetField::setRepeatTime() - Repeat time''%f'' is invalid.", repeatTime );
  158. // Return Error.
  159. return false;
  160. }
  161. // Set repeat time.
  162. mRepeatTime = repeatTime;
  163. // Return Okay.
  164. return true;
  165. }
  166. //-----------------------------------------------------------------------------
  167. bool ParticleAssetField::setValueScale( const F32 valueScale )
  168. {
  169. // Check Value Scale.
  170. if ( valueScale < 0.0f )
  171. {
  172. // Warn.
  173. Con::warnf("ParticleAssetField::setValueScale() - Invalid Value Scale! (%f)", valueScale );
  174. // Return Error.
  175. return false;
  176. }
  177. // Set Value Scale/
  178. mValueScale = valueScale;
  179. // Return Okay.
  180. return true;
  181. }
  182. //-----------------------------------------------------------------------------
  183. void ParticleAssetField::resetDataKeys(void)
  184. {
  185. // Clear Data Keys.
  186. mDataKeys.clear();
  187. // Add default value Data-Key.
  188. addDataKey( 0.0f, mDefaultValue );
  189. }
  190. //-----------------------------------------------------------------------------
  191. S32 ParticleAssetField::setSingleDataKey( const F32 value )
  192. {
  193. // Clear Data Keys.
  194. mDataKeys.clear();
  195. // Add a single key with the specified value.
  196. return addDataKey( 0.0f, value );
  197. }
  198. //-----------------------------------------------------------------------------
  199. bool ParticleAssetField::doesKeyExist(const F32 time)
  200. {
  201. U32 index = 0;
  202. for (index = 0; index < getDataKeyCount(); index++)
  203. {
  204. // Found Time?
  205. if (mDataKeys[index].mTime == time)
  206. {
  207. return true;
  208. }
  209. // Past Time?
  210. else if (mDataKeys[index].mTime > time)
  211. // Finish search.
  212. break;
  213. }
  214. return false;
  215. }
  216. //-----------------------------------------------------------------------------
  217. S32 ParticleAssetField::addDataKey( const F32 time, const F32 value )
  218. {
  219. // Check Max Time.
  220. if ( time > mMaxTime )
  221. {
  222. // Warn.
  223. Con::warnf("ParticleAssetField::addDataKey() - Time is out of bounds! (time:%f)", time );
  224. // Return Error.
  225. return -1;
  226. }
  227. // If data key exists already then set it and return the key index.
  228. U32 index = 0;
  229. for ( index = 0; index < getDataKeyCount(); index++ )
  230. {
  231. // Found Time?
  232. if ( mDataKeys[index].mTime == time )
  233. {
  234. // Yes, so set time.
  235. mDataKeys[index].mValue = value;
  236. // Return Index.
  237. return index;
  238. }
  239. // Past Time?
  240. else if ( mDataKeys[index].mTime > time )
  241. // Finish search.
  242. break;
  243. }
  244. // Insert Data-Key.
  245. mDataKeys.insert( index );
  246. // Set Data-Key.
  247. mDataKeys[index].mTime = time;
  248. mDataKeys[index].mValue = value;
  249. // Return Index.
  250. return index;
  251. }
  252. //-----------------------------------------------------------------------------
  253. bool ParticleAssetField::removeDataKey( const U32 index )
  254. {
  255. // Cannot Remove First Node!
  256. if ( index == 0 )
  257. {
  258. // Warn.
  259. Con::warnf("rParticleAssetField::emoveDataKey() - Cannot remove first Data-Key!");
  260. return false;
  261. }
  262. // Check Index.
  263. if ( index >= getDataKeyCount() )
  264. {
  265. // Warn.
  266. Con::warnf("rParticleAssetField::emoveDataKey() - Index out of range! (%d of %d)", index, getDataKeyCount()-1);
  267. return false;
  268. }
  269. // Remove Index.
  270. mDataKeys.erase(index);
  271. // Return Okay.
  272. return true;
  273. }
  274. //-----------------------------------------------------------------------------
  275. void ParticleAssetField::clearDataKeys( void )
  276. {
  277. // Reset Data Keys.
  278. resetDataKeys();
  279. }
  280. //-----------------------------------------------------------------------------
  281. bool ParticleAssetField::setDataKeyValue( const U32 index, const F32 value )
  282. {
  283. // Check Index.
  284. if ( index >= getDataKeyCount() )
  285. {
  286. // Warn.
  287. Con::warnf("ParticleAssetField::setDataKeyValue() - Index out of range! (%d of %d)", index, getDataKeyCount()-1);
  288. return false;
  289. }
  290. // Set Data Key Value.
  291. mDataKeys[index].mValue = value;
  292. // Return Okay.
  293. return true;
  294. }
  295. //-----------------------------------------------------------------------------
  296. F32 ParticleAssetField::getDataKeyValue( const U32 index ) const
  297. {
  298. // Check Index.
  299. if ( index >= getDataKeyCount() )
  300. {
  301. // Warn.
  302. Con::warnf("ParticleAssetField::getDataKeyValue() - Index out of range! (%d of %d)", index, getDataKeyCount()-1);
  303. return 0.0f;
  304. }
  305. // Return Data Key Value.
  306. return mDataKeys[index].mValue;
  307. }
  308. //-----------------------------------------------------------------------------
  309. F32 ParticleAssetField::getDataKeyTime( const U32 index ) const
  310. {
  311. // Check Index.
  312. if ( index >= getDataKeyCount() )
  313. {
  314. // Warn.
  315. Con::warnf("ParticleAssetField::getDataKeyTime() - Index out of range! (%d of %d)", index, getDataKeyCount()-1);
  316. return 0.0f;
  317. }
  318. // Return Data Key Time.
  319. return mDataKeys[index].mTime;
  320. }
  321. //-----------------------------------------------------------------------------
  322. const ParticleAssetField::DataKey& ParticleAssetField::getDataKey( const U32 index ) const
  323. {
  324. // Check Index.
  325. if ( index >= getDataKeyCount() )
  326. {
  327. // Warn.
  328. Con::warnf("ParticleAssetField::getDataKey() - Index out of range! (%d of %d)", index, getDataKeyCount()-1);
  329. return BadDataKey;
  330. }
  331. // Return Data-Key.
  332. return mDataKeys[index];
  333. }
  334. //-----------------------------------------------------------------------------
  335. F32 ParticleAssetField::getFieldValue( F32 time ) const
  336. {
  337. // Return First Entry if it's the only one or we're using zero time.
  338. if ( mIsZero(time) || getDataKeyCount() < 2)
  339. return mDataKeys[0].mValue * mValueScale;
  340. // Clamp Key-Time.
  341. time = getMin(getMax( 0.0f, time ), mMaxTime);
  342. // Repeat Time.
  343. time = mFmod( time * mRepeatTime, mMaxTime + FLT_EPSILON );
  344. // Fetch Max Key Index.
  345. const U32 maxKeyIndex = getDataKeyCount()-1;
  346. // Return Last Value if we're on/past the last time.
  347. if ( time >= mDataKeys[maxKeyIndex].mTime )
  348. return mDataKeys[maxKeyIndex].mValue * mValueScale;
  349. // Find Data-Key Indexes.
  350. U32 index1;
  351. U32 index2;
  352. for ( index1 = 0; index1 < getDataKeyCount(); index1++ )
  353. if ( mDataKeys[index1].mTime >= time )
  354. break;
  355. // If we're exactly on a Data-Key then return that key.
  356. if ( mIsEqual( mDataKeys[index1].mTime, time) )
  357. return mDataKeys[index1].mValue * mValueScale;
  358. // Set Adjacent Indexes.
  359. index2 = index1--;
  360. // Fetch Index Times.
  361. const F32 time1 = mDataKeys[index1].mTime;
  362. const F32 time2 = mDataKeys[index2].mTime;
  363. // Calculate Time Differential.
  364. const F32 dTime = (time-time1)/(time2-time1);
  365. // Return lerped Value.
  366. return ((mDataKeys[index1].mValue * (1.0f-dTime)) + (mDataKeys[index2].mValue * dTime)) * mValueScale;
  367. }
  368. //-----------------------------------------------------------------------------
  369. F32 ParticleAssetField::calculateFieldBV( const ParticleAssetField& base, const ParticleAssetField& variation, const F32 effectAge, const bool modulate, const F32 modulo )
  370. {
  371. // Fetch Graph Components.
  372. const F32 baseValue = base.getFieldValue( effectAge );
  373. const F32 varValue = variation.getFieldValue( effectAge ) * 0.5f;
  374. // Modulate?
  375. if ( modulate )
  376. // Return Modulo Calculation.
  377. return mFmod( baseValue + CoreMath::mGetRandomF(-varValue, varValue), modulo );
  378. else
  379. // Return Clamped Calculation.
  380. return mClampF( baseValue + CoreMath::mGetRandomF(-varValue, varValue), base.getMinValue(), base.getMaxValue() );
  381. }
  382. //-----------------------------------------------------------------------------
  383. F32 ParticleAssetField::calculateFieldBVE( const ParticleAssetField& base, const ParticleAssetField& variation, const ParticleAssetField& effect, const F32 effectAge, const bool modulate, const F32 modulo )
  384. {
  385. // Fetch Graph Components.
  386. const F32 baseValue = base.getFieldValue( effectAge );
  387. const F32 varValue = variation.getFieldValue( effectAge ) * 0.5f;
  388. const F32 effectValue = effect.getFieldValue( effectAge );
  389. // Modulate?
  390. if ( modulate )
  391. // Return Modulo Calculation.
  392. return mFmod( (baseValue + CoreMath::mGetRandomF(-varValue, varValue)) * effectValue, modulo );
  393. else
  394. // Return Clamped Calculation.
  395. return mClampF( (baseValue + CoreMath::mGetRandomF(-varValue, varValue)) * effectValue, base.getMinValue(), base.getMaxValue() );
  396. }
  397. //-----------------------------------------------------------------------------
  398. F32 ParticleAssetField::calculateFieldBVLE( const ParticleAssetField& base, const ParticleAssetField& variation, const ParticleAssetField& overlife, const ParticleAssetField& effect, const F32 effectAge, const F32 particleAge, const bool modulate, const F32 modulo )
  399. {
  400. // Fetch Graph Components.
  401. const F32 baseValue = base.getFieldValue( effectAge );
  402. const F32 varValue = variation.getFieldValue( effectAge ) * 0.5f;
  403. const F32 effectValue = effect.getFieldValue( effectAge );
  404. const F32 lifeValue = overlife.getFieldValue( particleAge );
  405. // Modulate?
  406. if ( modulate )
  407. // Return Modulo Calculation.
  408. return mFmod( (baseValue + CoreMath::mGetRandomF(-varValue, varValue)) * effectValue * lifeValue, modulo );
  409. else
  410. // Return Clamped Calculation.
  411. return mClampF( (baseValue + CoreMath::mGetRandomF(-varValue, varValue)) * effectValue * lifeValue, base.getMinValue(), base.getMaxValue() );
  412. }
  413. //------------------------------------------------------------------------------
  414. void ParticleAssetField::onTamlCustomWrite( TamlCustomNode* pCustomNode )
  415. {
  416. // Debug Profiling.
  417. PROFILE_SCOPE(ParticleAssetField_OnTamlCustomWrite);
  418. // Add a child (ignore it if there ends up being no children).
  419. TamlCustomNode* pAssetField = pCustomNode->addNode( getFieldName(), true );
  420. // Sanity!
  421. AssertFatal( pAssetField != NULL, "ParticleAssetField::onTamlCustomWrite() - Could not create field." );
  422. if ( mValueBoundsDirty && (mNotEqual( getMinValue(), 0.0f ) || mNotEqual( getMaxValue(), 0.0f )) )
  423. {
  424. pAssetField->addField( particleAssetFieldMinValueName, getMinValue() );
  425. pAssetField->addField( particleAssetFieldMaxValueName, getMaxValue() );
  426. }
  427. if ( mValueBoundsDirty && mNotEqual( getMaxTime(), 1.0f ) )
  428. pAssetField->addField( particleAssetFieldMaxTimeName, getMaxTime() );
  429. if ( mValueBoundsDirty && mNotEqual( getDefaultValue(), 1.0f ) )
  430. pAssetField->addField( particleAssetFieldDefaultValueName, getDefaultValue() );
  431. if ( mNotEqual( getValueScale(), 1.0f ) )
  432. pAssetField->addField( particleAssetFieldValueScaleName, getValueScale() );
  433. if ( mNotEqual( getRepeatTime(), 1.0f ) )
  434. pAssetField->addField( particleAssetFieldRepeatTimeName, getRepeatTime() );
  435. // Fetch key count.
  436. const U32 keyCount = getDataKeyCount();
  437. // Finish if no data keys.
  438. if ( keyCount == 0 )
  439. return;
  440. // Finish if there's only one key and it's the default one.
  441. if ( keyCount == 1 && mIsEqual(mDataKeys[0].mTime, 0.0f) && mIsEqual(mDataKeys[0].mValue, mDefaultValue) )
  442. return;
  443. // Iterate the keys.
  444. for( U32 index = 0; index < keyCount; ++index )
  445. {
  446. // Fetch the data key.
  447. const DataKey& dataKey = mDataKeys[index];
  448. // Add a key node.
  449. TamlCustomNode* pKeyNode = pAssetField->addNode( particleAssetFieldDataKeyName );
  450. // Add key fields.
  451. pKeyNode->addField( particleAssetFieldDataKeyTimeName, dataKey.mTime );
  452. pKeyNode->addField( particleAssetFieldDataKeyValueName, dataKey.mValue );
  453. }
  454. }
  455. //-----------------------------------------------------------------------------
  456. void ParticleAssetField::onTamlCustomRead( const TamlCustomNode* pCustomNode )
  457. {
  458. // Debug Profiling.
  459. PROFILE_SCOPE(ParticleAssetField_OnTamlCustomRead);
  460. // Fetch existing values.
  461. F32 repeatTime = getRepeatTime();
  462. F32 maxTime = getMaxTime();
  463. F32 minValue = getMinValue();
  464. F32 maxValue = getMaxValue();
  465. F32 defaultValue = getDefaultValue();
  466. F32 valueScale = getValueScale();
  467. // Set-up a temporary set of keys.
  468. Vector<DataKey> keys;
  469. // Clear the existing keys.
  470. mDataKeys.clear();
  471. // Fetch fields.
  472. const TamlCustomFieldVector& fields = pCustomNode->getFields();
  473. // Iterate fields.
  474. for ( TamlCustomFieldVector::const_iterator fieldItr = fields.begin(); fieldItr != fields.end(); ++fieldItr )
  475. {
  476. // Fetch field.
  477. TamlCustomField* pField = *fieldItr;
  478. // Fetch property field name.
  479. StringTableEntry fieldName = pField->getFieldName();
  480. if ( fieldName == particleAssetFieldRepeatTimeName )
  481. {
  482. pField->getFieldValue( repeatTime );
  483. }
  484. else if ( fieldName == particleAssetFieldMaxTimeName )
  485. {
  486. pField->getFieldValue( maxTime );
  487. mValueBoundsDirty = true;
  488. }
  489. else if ( fieldName == particleAssetFieldMinValueName )
  490. {
  491. pField->getFieldValue( minValue );
  492. mValueBoundsDirty = true;
  493. }
  494. else if ( fieldName == particleAssetFieldMaxValueName )
  495. {
  496. pField->getFieldValue( maxValue );
  497. mValueBoundsDirty = true;
  498. }
  499. else if ( fieldName == particleAssetFieldDefaultValueName )
  500. {
  501. pField->getFieldValue( defaultValue );
  502. mValueBoundsDirty = true;
  503. }
  504. else if ( fieldName == particleAssetFieldValueScaleName )
  505. {
  506. pField->getFieldValue( valueScale );
  507. }
  508. else if ( fieldName == particleAssetFieldDataKeysName )
  509. {
  510. const char* pDataKeys = pField->getFieldValue();
  511. const S32 elementCount = StringUnit::getUnitCount( pDataKeys, " ,\t" );
  512. // Are there a valid number of elements?
  513. if ( elementCount < 2 || (elementCount % 2 ) != 0 )
  514. {
  515. // No, so warn.
  516. Con::warnf( "ParticleAssetField::onTamlCustomRead() - An invalid set of data keys was found." );
  517. }
  518. else
  519. {
  520. // Iterate the elements.
  521. for( S32 elementIndex = 0; elementIndex <= (elementCount-2); elementIndex += 2 )
  522. {
  523. DataKey key;
  524. key.mTime = dAtof( StringUnit::getUnit( pDataKeys, elementIndex, " ,\t" ) );
  525. key.mValue = dAtof( StringUnit::getUnit( pDataKeys, elementIndex+1, " ,\t" ) );
  526. keys.push_back( key );
  527. }
  528. }
  529. }
  530. }
  531. // Fetch any children.
  532. const TamlCustomNodeVector& children = pCustomNode->getChildren();
  533. // Iterate node children.
  534. for( TamlCustomNodeVector::const_iterator childItr = children.begin(); childItr != children.end(); ++childItr )
  535. {
  536. // Fetch node.
  537. TamlCustomNode* pKeyNode = *childItr;
  538. // Ignore anything that isn't a key.
  539. if ( pKeyNode->getNodeName() != particleAssetFieldDataKeyName )
  540. continue;
  541. // Fetch the fields.
  542. const TamlCustomField* pTimeField = pKeyNode->findField( particleAssetFieldDataKeyTimeName );
  543. const TamlCustomField* pValueField = pKeyNode->findField( particleAssetFieldDataKeyValueName );
  544. // Did we find the fields?
  545. if ( pTimeField == NULL || pValueField == NULL )
  546. {
  547. // No, so warn.
  548. Con::warnf("ParticleAssetField::onTamlCustomRead() - Found a key but it did not have a time and value field." );
  549. continue;
  550. }
  551. // Read key.
  552. DataKey key;
  553. pTimeField->getFieldValue( key.mTime );
  554. pValueField->getFieldValue( key.mValue );
  555. keys.push_back( key );
  556. }
  557. // If value bounds are present but no keys, assign the field its default values.
  558. if ( !keys.size() )
  559. {
  560. DataKey key;
  561. key.mTime = getMinTime();
  562. key.mValue = getDefaultValue();
  563. keys.push_back( key );
  564. }
  565. // Did we read in any value bounds?
  566. if ( mValueBoundsDirty )
  567. {
  568. // Set the value bounds.
  569. setValueBounds( maxTime, minValue, maxValue, defaultValue );
  570. }
  571. // Set the value scale.
  572. setValueScale( valueScale );
  573. // Set the repeat time.
  574. setRepeatTime( repeatTime );
  575. // Set the data keys.
  576. mDataKeys = keys;
  577. }
  578. //-----------------------------------------------------------------------------
  579. void ParticleAssetField::WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
  580. {
  581. // Sanity!
  582. AssertFatal( pClassRep != NULL, "ParticleAssetField::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
  583. AssertFatal( pParentElement != NULL, "ParticleAssetField::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
  584. // Create Field element.
  585. TiXmlElement* pFieldElement = new TiXmlElement( "xs:element" );
  586. pFieldElement->SetAttribute( "name", getFieldName() );
  587. pFieldElement->SetAttribute( "minOccurs", 0 );
  588. pFieldElement->SetAttribute( "maxOccurs", 1 );
  589. pParentElement->LinkEndChild( pFieldElement );
  590. // Create complex type Element.
  591. TiXmlElement* pFieldComplexTypeElement = new TiXmlElement( "xs:complexType" );
  592. pFieldElement->LinkEndChild( pFieldComplexTypeElement );
  593. // Create choice element.
  594. TiXmlElement* pFieldChoiceElement = new TiXmlElement( "xs:choice" );
  595. pFieldChoiceElement->SetAttribute( "minOccurs", 0 );
  596. pFieldChoiceElement->SetAttribute( "maxOccurs", 1 );
  597. pFieldComplexTypeElement->LinkEndChild( pFieldChoiceElement );
  598. // Create key element.
  599. TiXmlElement* pKeyElement = new TiXmlElement( "xs:element" );
  600. pKeyElement->SetAttribute( "name", particleAssetFieldDataKeyName );
  601. pKeyElement->SetAttribute( "minOccurs", 0 );
  602. pKeyElement->SetAttribute( "maxOccurs", "unbounded" );
  603. pFieldChoiceElement->LinkEndChild( pKeyElement );
  604. // Create complex type Element.
  605. TiXmlElement* pKeyComplexTypeElement = new TiXmlElement( "xs:complexType" );
  606. pKeyElement->LinkEndChild( pKeyComplexTypeElement );
  607. // Create "Time" attribute.
  608. TiXmlElement* pKeyTimeAttribute = new TiXmlElement( "xs:attribute" );
  609. pKeyTimeAttribute->SetAttribute( "name", particleAssetFieldDataKeyTimeName );
  610. pKeyComplexTypeElement->LinkEndChild( pKeyTimeAttribute );
  611. TiXmlElement* pKeyTimeSimpleType = new TiXmlElement( "xs:simpleType" );
  612. pKeyTimeAttribute->LinkEndChild( pKeyTimeSimpleType );
  613. TiXmlElement* pKeyTimeRestriction = new TiXmlElement( "xs:restriction" );
  614. pKeyTimeRestriction->SetAttribute( "base", "xs:float" );
  615. pKeyTimeSimpleType->LinkEndChild( pKeyTimeRestriction );
  616. TiXmlElement* pKeyTimeMinRestriction = new TiXmlElement( "xs:minInclusive" );
  617. pKeyTimeMinRestriction->SetAttribute( "value", "0" );
  618. pKeyTimeRestriction->LinkEndChild( pKeyTimeMinRestriction );
  619. // Create "Value" attribute.
  620. TiXmlElement* pKeyValueAttribute = new TiXmlElement( "xs:attribute" );
  621. pKeyValueAttribute->SetAttribute( "name", particleAssetFieldDataKeyValueName );
  622. pKeyValueAttribute->SetAttribute( "type", "xs:float" );
  623. pKeyComplexTypeElement->LinkEndChild( pKeyValueAttribute );
  624. // Create "Min Value" attribute.
  625. TiXmlElement* pFieldMinValue = new TiXmlElement( "xs:attribute" );
  626. pFieldMinValue->SetAttribute( "name", particleAssetFieldMinValueName );
  627. pFieldMinValue->SetAttribute( "type", "xs:float" );
  628. pFieldComplexTypeElement->LinkEndChild( pFieldMinValue );
  629. // Create "Max Value" attribute.
  630. TiXmlElement* pFieldMaxValue = new TiXmlElement( "xs:attribute" );
  631. pFieldMaxValue->SetAttribute( "name", particleAssetFieldMaxValueName );
  632. pFieldMaxValue->SetAttribute( "type", "xs:float" );
  633. pFieldComplexTypeElement->LinkEndChild( pFieldMaxValue );
  634. // Create "Max Time" attribute.
  635. TiXmlElement* pFieldMaxTime = new TiXmlElement( "xs:attribute" );
  636. pFieldMaxTime->SetAttribute( "name", particleAssetFieldMaxTimeName );
  637. pFieldMaxTime->SetAttribute( "type", "xs:float" );
  638. pFieldComplexTypeElement->LinkEndChild( pFieldMaxTime );
  639. // Create "Default Value" attribute.
  640. TiXmlElement* pFieldDefaultValue = new TiXmlElement( "xs:attribute" );
  641. pFieldDefaultValue->SetAttribute( "name", particleAssetFieldDefaultValueName );
  642. pFieldDefaultValue->SetAttribute( "type", "xs:float" );
  643. pFieldComplexTypeElement->LinkEndChild( pFieldDefaultValue );
  644. // Create "Value Scale" attribute.
  645. TiXmlElement* pFieldValueScale = new TiXmlElement( "xs:attribute" );
  646. pFieldValueScale->SetAttribute( "name", particleAssetFieldValueScaleName );
  647. pFieldValueScale->SetAttribute( "type", "xs:float" );
  648. pFieldComplexTypeElement->LinkEndChild( pFieldValueScale );
  649. // Create "Repeat Time" attribute.
  650. TiXmlElement* pFieldRepeatTime = new TiXmlElement( "xs:attribute" );
  651. pFieldRepeatTime->SetAttribute( "name", particleAssetFieldRepeatTimeName );
  652. pFieldRepeatTime->SetAttribute( "type", "xs:float" );
  653. pFieldComplexTypeElement->LinkEndChild( pFieldRepeatTime );
  654. }