ParticleAssetField.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  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. S32 ParticleAssetField::addDataKey( const F32 time, const F32 value )
  200. {
  201. // Check Max Time.
  202. if ( time > mMaxTime )
  203. {
  204. // Warn.
  205. Con::warnf("ParticleAssetField::addDataKey() - Time is out of bounds! (time:%f)", time );
  206. // Return Error.
  207. return -1;
  208. }
  209. // If data key exists already then set it and return the key index.
  210. U32 index = 0;
  211. for ( index = 0; index < getDataKeyCount(); index++ )
  212. {
  213. // Found Time?
  214. if ( mDataKeys[index].mTime == time )
  215. {
  216. // Yes, so set time.
  217. mDataKeys[index].mValue = value;
  218. // Return Index.
  219. return index;
  220. }
  221. // Past Time?
  222. else if ( mDataKeys[index].mTime > time )
  223. // Finish search.
  224. break;
  225. }
  226. // Insert Data-Key.
  227. mDataKeys.insert( index );
  228. // Set Data-Key.
  229. mDataKeys[index].mTime = time;
  230. mDataKeys[index].mValue = value;
  231. // Return Index.
  232. return index;
  233. }
  234. //-----------------------------------------------------------------------------
  235. bool ParticleAssetField::removeDataKey( const U32 index )
  236. {
  237. // Cannot Remove First Node!
  238. if ( index == 0 )
  239. {
  240. // Warn.
  241. Con::warnf("rParticleAssetField::emoveDataKey() - Cannot remove first Data-Key!");
  242. return false;
  243. }
  244. // Check Index.
  245. if ( index >= getDataKeyCount() )
  246. {
  247. // Warn.
  248. Con::warnf("rParticleAssetField::emoveDataKey() - Index out of range! (%d of %d)", index, getDataKeyCount()-1);
  249. return false;
  250. }
  251. // Remove Index.
  252. mDataKeys.erase(index);
  253. // Return Okay.
  254. return true;
  255. }
  256. //-----------------------------------------------------------------------------
  257. void ParticleAssetField::clearDataKeys( void )
  258. {
  259. // Reset Data Keys.
  260. resetDataKeys();
  261. }
  262. //-----------------------------------------------------------------------------
  263. bool ParticleAssetField::setDataKeyValue( const U32 index, const F32 value )
  264. {
  265. // Check Index.
  266. if ( index >= getDataKeyCount() )
  267. {
  268. // Warn.
  269. Con::warnf("ParticleAssetField::setDataKeyValue() - Index out of range! (%d of %d)", index, getDataKeyCount()-1);
  270. return false;
  271. }
  272. // Set Data Key Value.
  273. mDataKeys[index].mValue = value;
  274. // Return Okay.
  275. return true;
  276. }
  277. //-----------------------------------------------------------------------------
  278. F32 ParticleAssetField::getDataKeyValue( const U32 index ) const
  279. {
  280. // Check Index.
  281. if ( index >= getDataKeyCount() )
  282. {
  283. // Warn.
  284. Con::warnf("ParticleAssetField::getDataKeyValue() - Index out of range! (%d of %d)", index, getDataKeyCount()-1);
  285. return 0.0f;
  286. }
  287. // Return Data Key Value.
  288. return mDataKeys[index].mValue;
  289. }
  290. //-----------------------------------------------------------------------------
  291. F32 ParticleAssetField::getDataKeyTime( const U32 index ) const
  292. {
  293. // Check Index.
  294. if ( index >= getDataKeyCount() )
  295. {
  296. // Warn.
  297. Con::warnf("ParticleAssetField::getDataKeyTime() - Index out of range! (%d of %d)", index, getDataKeyCount()-1);
  298. return 0.0f;
  299. }
  300. // Return Data Key Time.
  301. return mDataKeys[index].mTime;
  302. }
  303. //-----------------------------------------------------------------------------
  304. const ParticleAssetField::DataKey& ParticleAssetField::getDataKey( const U32 index ) const
  305. {
  306. // Check Index.
  307. if ( index >= getDataKeyCount() )
  308. {
  309. // Warn.
  310. Con::warnf("ParticleAssetField::getDataKey() - Index out of range! (%d of %d)", index, getDataKeyCount()-1);
  311. return BadDataKey;
  312. }
  313. // Return Data-Key.
  314. return mDataKeys[index];
  315. }
  316. //-----------------------------------------------------------------------------
  317. F32 ParticleAssetField::getFieldValue( F32 time ) const
  318. {
  319. // Return First Entry if it's the only one or we're using zero time.
  320. if ( mIsZero(time) || getDataKeyCount() < 2)
  321. return mDataKeys[0].mValue * mValueScale;
  322. // Clamp Key-Time.
  323. time = getMin(getMax( 0.0f, time ), mMaxTime);
  324. // Repeat Time.
  325. time = mFmod( time * mRepeatTime, mMaxTime + FLT_EPSILON );
  326. // Fetch Max Key Index.
  327. const U32 maxKeyIndex = getDataKeyCount()-1;
  328. // Return Last Value if we're on/past the last time.
  329. if ( time >= mDataKeys[maxKeyIndex].mTime )
  330. return mDataKeys[maxKeyIndex].mValue * mValueScale;
  331. // Find Data-Key Indexes.
  332. U32 index1;
  333. U32 index2;
  334. for ( index1 = 0; index1 < getDataKeyCount(); index1++ )
  335. if ( mDataKeys[index1].mTime >= time )
  336. break;
  337. // If we're exactly on a Data-Key then return that key.
  338. if ( mIsEqual( mDataKeys[index1].mTime, time) )
  339. return mDataKeys[index1].mValue * mValueScale;
  340. // Set Adjacent Indexes.
  341. index2 = index1--;
  342. // Fetch Index Times.
  343. const F32 time1 = mDataKeys[index1].mTime;
  344. const F32 time2 = mDataKeys[index2].mTime;
  345. // Calculate Time Differential.
  346. const F32 dTime = (time-time1)/(time2-time1);
  347. // Return lerped Value.
  348. return ((mDataKeys[index1].mValue * (1.0f-dTime)) + (mDataKeys[index2].mValue * dTime)) * mValueScale;
  349. }
  350. //-----------------------------------------------------------------------------
  351. F32 ParticleAssetField::calculateFieldBV( const ParticleAssetField& base, const ParticleAssetField& variation, const F32 effectAge, const bool modulate, const F32 modulo )
  352. {
  353. // Fetch Graph Components.
  354. const F32 baseValue = base.getFieldValue( effectAge );
  355. const F32 varValue = variation.getFieldValue( effectAge ) * 0.5f;
  356. // Modulate?
  357. if ( modulate )
  358. // Return Modulo Calculation.
  359. return mFmod( baseValue + CoreMath::mGetRandomF(-varValue, varValue), modulo );
  360. else
  361. // Return Clamped Calculation.
  362. return mClampF( baseValue + CoreMath::mGetRandomF(-varValue, varValue), base.getMinValue(), base.getMaxValue() );
  363. }
  364. //-----------------------------------------------------------------------------
  365. F32 ParticleAssetField::calculateFieldBVE( const ParticleAssetField& base, const ParticleAssetField& variation, const ParticleAssetField& effect, const F32 effectAge, const bool modulate, const F32 modulo )
  366. {
  367. // Fetch Graph Components.
  368. const F32 baseValue = base.getFieldValue( effectAge );
  369. const F32 varValue = variation.getFieldValue( effectAge ) * 0.5f;
  370. const F32 effectValue = effect.getFieldValue( effectAge );
  371. // Modulate?
  372. if ( modulate )
  373. // Return Modulo Calculation.
  374. return mFmod( (baseValue + CoreMath::mGetRandomF(-varValue, varValue)) * effectValue, modulo );
  375. else
  376. // Return Clamped Calculation.
  377. return mClampF( (baseValue + CoreMath::mGetRandomF(-varValue, varValue)) * effectValue, base.getMinValue(), base.getMaxValue() );
  378. }
  379. //-----------------------------------------------------------------------------
  380. 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 )
  381. {
  382. // Fetch Graph Components.
  383. const F32 baseValue = base.getFieldValue( effectAge );
  384. const F32 varValue = variation.getFieldValue( effectAge ) * 0.5f;
  385. const F32 effectValue = effect.getFieldValue( effectAge );
  386. const F32 lifeValue = overlife.getFieldValue( particleAge );
  387. // Modulate?
  388. if ( modulate )
  389. // Return Modulo Calculation.
  390. return mFmod( (baseValue + CoreMath::mGetRandomF(-varValue, varValue)) * effectValue * lifeValue, modulo );
  391. else
  392. // Return Clamped Calculation.
  393. return mClampF( (baseValue + CoreMath::mGetRandomF(-varValue, varValue)) * effectValue * lifeValue, base.getMinValue(), base.getMaxValue() );
  394. }
  395. //------------------------------------------------------------------------------
  396. void ParticleAssetField::onTamlCustomWrite( TamlCustomNode* pCustomNode )
  397. {
  398. // Debug Profiling.
  399. PROFILE_SCOPE(ParticleAssetField_OnTamlCustomWrite);
  400. // Add a child (ignore it if there ends up being no children).
  401. TamlCustomNode* pAssetField = pCustomNode->addNode( getFieldName(), true );
  402. // Sanity!
  403. AssertFatal( pAssetField != NULL, "ParticleAssetField::onTamlCustomWrite() - Could not create field." );
  404. if ( mValueBoundsDirty && (mNotEqual( getMinValue(), 0.0f ) || mNotEqual( getMaxValue(), 0.0f )) )
  405. {
  406. pAssetField->addField( particleAssetFieldMinValueName, getMinValue() );
  407. pAssetField->addField( particleAssetFieldMaxValueName, getMaxValue() );
  408. }
  409. if ( mValueBoundsDirty && mNotEqual( getMaxTime(), 1.0f ) )
  410. pAssetField->addField( particleAssetFieldMaxTimeName, getMaxTime() );
  411. if ( mValueBoundsDirty && mNotEqual( getDefaultValue(), 1.0f ) )
  412. pAssetField->addField( particleAssetFieldDefaultValueName, getDefaultValue() );
  413. if ( mNotEqual( getValueScale(), 1.0f ) )
  414. pAssetField->addField( particleAssetFieldValueScaleName, getValueScale() );
  415. if ( mNotEqual( getRepeatTime(), 1.0f ) )
  416. pAssetField->addField( particleAssetFieldRepeatTimeName, getRepeatTime() );
  417. // Fetch key count.
  418. const U32 keyCount = getDataKeyCount();
  419. // Finish if no data keys.
  420. if ( keyCount == 0 )
  421. return;
  422. // Finish if there's only one key and it's the default one.
  423. if ( keyCount == 1 && mIsEqual(mDataKeys[0].mTime, 0.0f) && mIsEqual(mDataKeys[0].mValue, mDefaultValue) )
  424. return;
  425. // Iterate the keys.
  426. for( U32 index = 0; index < keyCount; ++index )
  427. {
  428. // Fetch the data key.
  429. const DataKey& dataKey = mDataKeys[index];
  430. // Add a key node.
  431. TamlCustomNode* pKeyNode = pAssetField->addNode( particleAssetFieldDataKeyName );
  432. // Add key fields.
  433. pKeyNode->addField( particleAssetFieldDataKeyTimeName, dataKey.mTime );
  434. pKeyNode->addField( particleAssetFieldDataKeyValueName, dataKey.mValue );
  435. }
  436. }
  437. //-----------------------------------------------------------------------------
  438. void ParticleAssetField::onTamlCustomRead( const TamlCustomNode* pCustomNode )
  439. {
  440. // Debug Profiling.
  441. PROFILE_SCOPE(ParticleAssetField_OnTamlCustomRead);
  442. // Fetch existing values.
  443. F32 repeatTime = getRepeatTime();
  444. F32 maxTime = getMaxTime();
  445. F32 minValue = getMinValue();
  446. F32 maxValue = getMaxValue();
  447. F32 defaultValue = getDefaultValue();
  448. F32 valueScale = getValueScale();
  449. // Set-up a temporary set of keys.
  450. Vector<DataKey> keys;
  451. // Clear the existing keys.
  452. mDataKeys.clear();
  453. // Fetch fields.
  454. const TamlCustomFieldVector& fields = pCustomNode->getFields();
  455. // Iterate fields.
  456. for ( TamlCustomFieldVector::const_iterator fieldItr = fields.begin(); fieldItr != fields.end(); ++fieldItr )
  457. {
  458. // Fetch field.
  459. TamlCustomField* pField = *fieldItr;
  460. // Fetch property field name.
  461. StringTableEntry fieldName = pField->getFieldName();
  462. if ( fieldName == particleAssetFieldRepeatTimeName )
  463. {
  464. pField->getFieldValue( repeatTime );
  465. }
  466. else if ( fieldName == particleAssetFieldMaxTimeName )
  467. {
  468. pField->getFieldValue( maxTime );
  469. mValueBoundsDirty = true;
  470. }
  471. else if ( fieldName == particleAssetFieldMinValueName )
  472. {
  473. pField->getFieldValue( minValue );
  474. mValueBoundsDirty = true;
  475. }
  476. else if ( fieldName == particleAssetFieldMaxValueName )
  477. {
  478. pField->getFieldValue( maxValue );
  479. mValueBoundsDirty = true;
  480. }
  481. else if ( fieldName == particleAssetFieldDefaultValueName )
  482. {
  483. pField->getFieldValue( defaultValue );
  484. mValueBoundsDirty = true;
  485. }
  486. else if ( fieldName == particleAssetFieldValueScaleName )
  487. {
  488. pField->getFieldValue( valueScale );
  489. }
  490. else if ( fieldName == particleAssetFieldDataKeysName )
  491. {
  492. const char* pDataKeys = pField->getFieldValue();
  493. const S32 elementCount = StringUnit::getUnitCount( pDataKeys, " ,\t" );
  494. // Are there a valid number of elements?
  495. if ( elementCount < 2 || (elementCount % 2 ) != 0 )
  496. {
  497. // No, so warn.
  498. Con::warnf( "ParticleAssetField::onTamlCustomRead() - An invalid set of data keys was found." );
  499. }
  500. else
  501. {
  502. // Iterate the elements.
  503. for( S32 elementIndex = 0; elementIndex <= (elementCount-2); elementIndex += 2 )
  504. {
  505. DataKey key;
  506. key.mTime = dAtof( StringUnit::getUnit( pDataKeys, elementIndex, " ,\t" ) );
  507. key.mValue = dAtof( StringUnit::getUnit( pDataKeys, elementIndex+1, " ,\t" ) );
  508. keys.push_back( key );
  509. }
  510. }
  511. }
  512. }
  513. // Fetch any children.
  514. const TamlCustomNodeVector& children = pCustomNode->getChildren();
  515. // Iterate node children.
  516. for( TamlCustomNodeVector::const_iterator childItr = children.begin(); childItr != children.end(); ++childItr )
  517. {
  518. // Fetch node.
  519. TamlCustomNode* pKeyNode = *childItr;
  520. // Ignore anything that isn't a key.
  521. if ( pKeyNode->getNodeName() != particleAssetFieldDataKeyName )
  522. continue;
  523. // Fetch the fields.
  524. const TamlCustomField* pTimeField = pKeyNode->findField( particleAssetFieldDataKeyTimeName );
  525. const TamlCustomField* pValueField = pKeyNode->findField( particleAssetFieldDataKeyValueName );
  526. // Did we find the fields?
  527. if ( pTimeField == NULL || pValueField == NULL )
  528. {
  529. // No, so warn.
  530. Con::warnf("ParticleAssetField::onTamlCustomRead() - Found a key but it did not have a time and value field." );
  531. continue;
  532. }
  533. // Read key.
  534. DataKey key;
  535. pTimeField->getFieldValue( key.mTime );
  536. pValueField->getFieldValue( key.mValue );
  537. keys.push_back( key );
  538. }
  539. // Set the value bounds.
  540. setValueBounds( maxTime, minValue, maxValue, defaultValue );
  541. // Set the value scale.
  542. setValueScale( valueScale );
  543. // Set the repeat time.
  544. setRepeatTime( repeatTime );
  545. // Set the data keys.
  546. mDataKeys = keys;
  547. }
  548. //-----------------------------------------------------------------------------
  549. void ParticleAssetField::WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
  550. {
  551. // Sanity!
  552. AssertFatal( pClassRep != NULL, "ParticleAssetField::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
  553. AssertFatal( pParentElement != NULL, "ParticleAssetField::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
  554. // Create Field element.
  555. TiXmlElement* pFieldElement = new TiXmlElement( "xs:element" );
  556. pFieldElement->SetAttribute( "name", getFieldName() );
  557. pFieldElement->SetAttribute( "minOccurs", 0 );
  558. pFieldElement->SetAttribute( "maxOccurs", 1 );
  559. pParentElement->LinkEndChild( pFieldElement );
  560. // Create complex type Element.
  561. TiXmlElement* pFieldComplexTypeElement = new TiXmlElement( "xs:complexType" );
  562. pFieldElement->LinkEndChild( pFieldComplexTypeElement );
  563. // Create choice element.
  564. TiXmlElement* pFieldChoiceElement = new TiXmlElement( "xs:choice" );
  565. pFieldChoiceElement->SetAttribute( "minOccurs", 0 );
  566. pFieldChoiceElement->SetAttribute( "maxOccurs", 1 );
  567. pFieldComplexTypeElement->LinkEndChild( pFieldChoiceElement );
  568. // Create key element.
  569. TiXmlElement* pKeyElement = new TiXmlElement( "xs:element" );
  570. pKeyElement->SetAttribute( "name", particleAssetFieldDataKeyName );
  571. pKeyElement->SetAttribute( "minOccurs", 0 );
  572. pKeyElement->SetAttribute( "maxOccurs", "unbounded" );
  573. pFieldChoiceElement->LinkEndChild( pKeyElement );
  574. // Create complex type Element.
  575. TiXmlElement* pKeyComplexTypeElement = new TiXmlElement( "xs:complexType" );
  576. pKeyElement->LinkEndChild( pKeyComplexTypeElement );
  577. // Create "Time" attribute.
  578. TiXmlElement* pKeyTimeAttribute = new TiXmlElement( "xs:attribute" );
  579. pKeyTimeAttribute->SetAttribute( "name", particleAssetFieldDataKeyTimeName );
  580. pKeyComplexTypeElement->LinkEndChild( pKeyTimeAttribute );
  581. TiXmlElement* pKeyTimeSimpleType = new TiXmlElement( "xs:simpleType" );
  582. pKeyTimeAttribute->LinkEndChild( pKeyTimeSimpleType );
  583. TiXmlElement* pKeyTimeRestriction = new TiXmlElement( "xs:restriction" );
  584. pKeyTimeRestriction->SetAttribute( "base", "xs:float" );
  585. pKeyTimeSimpleType->LinkEndChild( pKeyTimeRestriction );
  586. TiXmlElement* pKeyTimeMinRestriction = new TiXmlElement( "xs:minInclusive" );
  587. pKeyTimeMinRestriction->SetAttribute( "value", "0" );
  588. pKeyTimeRestriction->LinkEndChild( pKeyTimeMinRestriction );
  589. // Create "Value" attribute.
  590. TiXmlElement* pKeyValueAttribute = new TiXmlElement( "xs:attribute" );
  591. pKeyValueAttribute->SetAttribute( "name", particleAssetFieldDataKeyValueName );
  592. pKeyValueAttribute->SetAttribute( "type", "xs:float" );
  593. pKeyComplexTypeElement->LinkEndChild( pKeyValueAttribute );
  594. // Create "Min Value" attribute.
  595. TiXmlElement* pFieldMinValue = new TiXmlElement( "xs:attribute" );
  596. pFieldMinValue->SetAttribute( "name", particleAssetFieldMinValueName );
  597. pFieldMinValue->SetAttribute( "type", "xs:float" );
  598. pFieldComplexTypeElement->LinkEndChild( pFieldMinValue );
  599. // Create "Max Value" attribute.
  600. TiXmlElement* pFieldMaxValue = new TiXmlElement( "xs:attribute" );
  601. pFieldMaxValue->SetAttribute( "name", particleAssetFieldMaxValueName );
  602. pFieldMaxValue->SetAttribute( "type", "xs:float" );
  603. pFieldComplexTypeElement->LinkEndChild( pFieldMaxValue );
  604. // Create "Max Time" attribute.
  605. TiXmlElement* pFieldMaxTime = new TiXmlElement( "xs:attribute" );
  606. pFieldMaxTime->SetAttribute( "name", particleAssetFieldMaxTimeName );
  607. pFieldMaxTime->SetAttribute( "type", "xs:float" );
  608. pFieldComplexTypeElement->LinkEndChild( pFieldMaxTime );
  609. // Create "Default Value" attribute.
  610. TiXmlElement* pFieldDefaultValue = new TiXmlElement( "xs:attribute" );
  611. pFieldDefaultValue->SetAttribute( "name", particleAssetFieldDefaultValueName );
  612. pFieldDefaultValue->SetAttribute( "type", "xs:float" );
  613. pFieldComplexTypeElement->LinkEndChild( pFieldDefaultValue );
  614. // Create "Value Scale" attribute.
  615. TiXmlElement* pFieldValueScale = new TiXmlElement( "xs:attribute" );
  616. pFieldValueScale->SetAttribute( "name", particleAssetFieldValueScaleName );
  617. pFieldValueScale->SetAttribute( "type", "xs:float" );
  618. pFieldComplexTypeElement->LinkEndChild( pFieldValueScale );
  619. // Create "Repeat Time" attribute.
  620. TiXmlElement* pFieldRepeatTime = new TiXmlElement( "xs:attribute" );
  621. pFieldRepeatTime->SetAttribute( "name", particleAssetFieldRepeatTimeName );
  622. pFieldRepeatTime->SetAttribute( "type", "xs:float" );
  623. pFieldComplexTypeElement->LinkEndChild( pFieldRepeatTime );
  624. }