tamlCustom.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  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. #ifndef _TAML_CUSTOM_H_
  23. #define _TAML_CUSTOM_H_
  24. #ifndef _FACTORY_CACHE_H_
  25. #include "memory/factoryCache.h"
  26. #endif
  27. #ifndef _STRINGTABLE_H_
  28. #include "string/stringTable.h"
  29. #endif
  30. #ifndef _CONSOLE_H_
  31. #include "console/console.h"
  32. #endif
  33. #ifndef B2_MATH_H
  34. #include "Box2D/Common/b2Math.h"
  35. #endif
  36. #ifndef _COLOR_H_
  37. #include "graphics/gColor.h"
  38. #endif
  39. #ifndef _SIMBASE_H_
  40. #include "sim/simBase.h"
  41. #endif
  42. #include "memory/safeDelete.h"
  43. //-----------------------------------------------------------------------------
  44. #define MAX_TAML_NODE_FIELDVALUE_LENGTH 2048
  45. //-----------------------------------------------------------------------------
  46. class TamlWriteNode;
  47. class TamlCustomNode;
  48. class TamlCustomField;
  49. extern FactoryCache<TamlCustomNode> TamlCustomNodeFactory;
  50. extern FactoryCache<TamlCustomField> TamlCustomFieldFactory;
  51. typedef Vector<TamlCustomNode*> TamlCustomNodeVector;
  52. typedef Vector<TamlCustomField*> TamlCustomFieldVector;
  53. //-----------------------------------------------------------------------------
  54. /// @ingroup tamlGroup
  55. /// @see tamlGroup
  56. class TamlCustomField : public IFactoryObjectReset
  57. {
  58. public:
  59. TamlCustomField()
  60. {
  61. resetState();
  62. }
  63. virtual ~TamlCustomField()
  64. {
  65. // Everything should already be cleared in a state reset.
  66. // Touching any memory here is dangerous as this type is typically
  67. // held in a static factory cache until shutdown at which point
  68. // pretty much anything or everything could be invalid!
  69. }
  70. virtual void resetState( void )
  71. {
  72. mFieldName = StringTable->EmptyString;
  73. *mFieldValue = 0;
  74. }
  75. void set( const char* pFieldName, const char* pFieldValue );
  76. inline void setFieldValue( const char* pFieldName, const ColorI& fieldValue )
  77. {
  78. // Fetch the field value.
  79. const char* pFieldValue = Con::getData( TypeColorI, &const_cast<ColorI&>(fieldValue), 0 );
  80. // Did we get a field value?
  81. if ( pFieldValue == NULL )
  82. {
  83. // No, so warn.
  84. Con::warnf( "Taml: Failed to add node field name '%s' with ColorI value.", pFieldName );
  85. pFieldValue = StringTable->EmptyString;
  86. }
  87. set( pFieldName, pFieldValue );
  88. }
  89. inline void setFieldValue( const char* pFieldName, const ColorF& fieldValue )
  90. {
  91. // Fetch the field value.
  92. const char* pFieldValue = Con::getData( TypeColorF, &const_cast<ColorF&>(fieldValue), 0 );
  93. // Did we get a field value?
  94. if ( pFieldValue == NULL )
  95. {
  96. // No, so warn.
  97. Con::warnf( "Taml: Failed to add node field name '%s' with ColorF value.", pFieldName );
  98. pFieldValue = StringTable->EmptyString;
  99. }
  100. set( pFieldName, pFieldValue );
  101. }
  102. inline void setFieldValue( const char* pFieldName, const Point2I& fieldValue )
  103. {
  104. char fieldValueBuffer[32];
  105. dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%d %d", fieldValue.x, fieldValue.y );
  106. set( pFieldName, fieldValueBuffer );
  107. }
  108. inline void setFieldValue( const char* pFieldName, const Point2F& fieldValue )
  109. {
  110. char fieldValueBuffer[32];
  111. dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%.5g %0.5g", fieldValue.x, fieldValue.y );
  112. set( pFieldName, fieldValueBuffer );
  113. }
  114. inline void setFieldValue( const char* pFieldName, const b2Vec2& fieldValue )
  115. {
  116. char fieldValueBuffer[32];
  117. dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%.5g %.5g", fieldValue.x, fieldValue.y );
  118. set( pFieldName, fieldValueBuffer );
  119. }
  120. inline void setFieldValue( const char* pFieldName, const U32 fieldValue )
  121. {
  122. char fieldValueBuffer[16];
  123. dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%d", fieldValue );
  124. set( pFieldName, fieldValueBuffer );
  125. }
  126. inline void setFieldValue( const char* pFieldName, const bool fieldValue )
  127. {
  128. char fieldValueBuffer[16];
  129. dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%d", fieldValue );
  130. set( pFieldName, fieldValueBuffer );
  131. }
  132. inline void setFieldValue( const char* pFieldName, const S32 fieldValue )
  133. {
  134. char fieldValueBuffer[16];
  135. dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%d", fieldValue );
  136. set( pFieldName, fieldValueBuffer );
  137. }
  138. inline void setFieldValue( const char* pFieldName, const float fieldValue )
  139. {
  140. char fieldValueBuffer[16];
  141. dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%.5g", fieldValue );
  142. set( pFieldName, fieldValueBuffer );
  143. }
  144. inline void setFieldValue( const char* pFieldName, const char* fieldValue )
  145. {
  146. set( pFieldName, fieldValue );
  147. }
  148. inline void getFieldValue( ColorF& fieldValue ) const
  149. {
  150. fieldValue.set( 1.0f, 1.0f, 1.0f, 1.0f );
  151. // Set color.
  152. const char* argv = (char*)mFieldValue;
  153. Con::setData( TypeColorF, &fieldValue, 0, 1, &argv );
  154. }
  155. inline void getFieldValue( ColorI& fieldValue ) const
  156. {
  157. fieldValue.set( 255, 255, 255, 255 );
  158. // Set color.
  159. const char* argv = (char*)mFieldValue;
  160. Con::setData( TypeColorI, &fieldValue, 0, 1, &argv );
  161. }
  162. inline void getFieldValue( Point2I& fieldValue ) const
  163. {
  164. if ( dSscanf( mFieldValue, "%d %d", &fieldValue.x, &fieldValue.y ) != 2 )
  165. {
  166. // Warn.
  167. Con::warnf( "TamlCustomField - Reading point2I but it has an incorrect format: '%s'.", mFieldValue );
  168. }
  169. }
  170. inline void getFieldValue( Point2F& fieldValue ) const
  171. {
  172. if ( dSscanf( mFieldValue, "%g %g", &fieldValue.x, &fieldValue.y ) != 2 )
  173. {
  174. // Warn.
  175. Con::warnf( "TamlCustomField - Reading point2F but it has an incorrect format: '%s'.", mFieldValue );
  176. }
  177. }
  178. inline void getFieldValue( b2Vec2& fieldValue ) const
  179. {
  180. if ( dSscanf( mFieldValue, "%g %g", &fieldValue.x, &fieldValue.y ) != 2 )
  181. {
  182. // Warn.
  183. Con::warnf( "TamlCustomField - Reading vector but it has an incorrect format: '%s'.", mFieldValue );
  184. }
  185. }
  186. inline void getFieldValue( bool& fieldValue ) const
  187. {
  188. fieldValue = dAtob( mFieldValue );
  189. }
  190. inline void getFieldValue( S32& fieldValue ) const
  191. {
  192. fieldValue = dAtoi( mFieldValue );
  193. }
  194. inline void getFieldValue( U32& fieldValue ) const
  195. {
  196. fieldValue = (U32)dAtoi( mFieldValue );
  197. }
  198. inline void getFieldValue( F32& fieldValue ) const
  199. {
  200. fieldValue = dAtof( mFieldValue );
  201. }
  202. inline const char* getFieldValue( void ) const
  203. {
  204. return mFieldValue;
  205. }
  206. inline StringTableEntry getFieldName( void ) const { return mFieldName; }
  207. bool fieldNameBeginsWith( const char* pComparison ) const
  208. {
  209. const U32 comparisonLength = dStrlen( pComparison );
  210. const U32 fieldNameLength = dStrlen( mFieldName );
  211. if ( comparisonLength == 0 || fieldNameLength == 0 || comparisonLength > fieldNameLength )
  212. return false;
  213. StringTableEntry comparison = StringTable->insert( pComparison );
  214. char fieldNameBuffer[1024];
  215. // Sanity!
  216. AssertFatal( fieldNameLength < sizeof(fieldNameBuffer), "TamlCustomField: Field name is too long." );
  217. dStrcpy( fieldNameBuffer, mFieldName );
  218. fieldNameBuffer[fieldNameLength-1] = 0;
  219. StringTableEntry fieldName = StringTable->insert( fieldNameBuffer );
  220. return ( fieldName == comparison );
  221. }
  222. inline bool isValueEmpty( void ) const { return *mFieldValue == 0; }
  223. private:
  224. StringTableEntry mFieldName;
  225. char mFieldValue[MAX_TAML_NODE_FIELDVALUE_LENGTH];
  226. };
  227. //-----------------------------------------------------------------------------
  228. /// @ingroup tamlGroup
  229. /// @see tamlGroup
  230. class TamlCustomNode : public IFactoryObjectReset
  231. {
  232. public:
  233. TamlCustomNode()
  234. {
  235. // Reset proxy object.
  236. // NOTE: This MUST be done before the state is reset otherwise we'll be touching uninitialized stuff.
  237. mpProxyWriteNode = NULL;
  238. mpProxyObject = NULL;
  239. resetState();
  240. }
  241. virtual ~TamlCustomNode()
  242. {
  243. // Everything should already be cleared in a state reset.
  244. // Touching any memory here is dangerous as this type is typically
  245. // held in a static factory cache until shutdown at which point
  246. // pretty much anything or everything could be invalid!
  247. }
  248. virtual void resetState( void )
  249. {
  250. // We don't need to delete the write node as it'll get destroyed when the compilation is reset!
  251. mpProxyWriteNode = NULL;
  252. mpProxyObject = NULL;
  253. // Cache the children.
  254. while ( mChildren.size() > 0 )
  255. {
  256. TamlCustomNodeFactory.cacheObject( mChildren.back() );
  257. mChildren.pop_back();
  258. }
  259. // Cache the fields.
  260. while( mFields.size() > 0 )
  261. {
  262. TamlCustomFieldFactory.cacheObject( mFields.back() );
  263. mFields.pop_back();
  264. }
  265. // Reset the node name.
  266. mNodeName = StringTable->EmptyString;
  267. // Reset node text.
  268. mNodeText.resetState();
  269. // Reset the ignore empty flag.
  270. mIgnoreEmpty = false;
  271. }
  272. inline TamlCustomNode* addNode( SimObject* pProxyObject )
  273. {
  274. // Sanity!
  275. AssertFatal( pProxyObject != NULL, "Field object cannot be NULL." );
  276. AssertFatal( mpProxyWriteNode == NULL, "Field write node must be NULL." );
  277. AssertFatal( *mNodeText.getFieldValue() == 0, "Cannot add node that has node text." );
  278. // Create a custom node.
  279. TamlCustomNode* pCustomNode = TamlCustomNodeFactory.createObject();
  280. // Set node name.
  281. pCustomNode->setNodeName( pProxyObject->getClassName() );
  282. // Set proxy object.
  283. pCustomNode->mpProxyObject = pProxyObject;
  284. // Store node.
  285. mChildren.push_back( pCustomNode );
  286. return pCustomNode;
  287. }
  288. inline TamlCustomNode* addNode( const char* pNodeName, const bool ignoreEmpty = true )
  289. {
  290. // Sanity!
  291. AssertFatal( *mNodeText.getFieldValue() == 0, "Cannot add node that has node text." );
  292. // Create a custom node.
  293. TamlCustomNode* pCustomNode = TamlCustomNodeFactory.createObject();
  294. // Fetch node name.
  295. pCustomNode->setNodeName( pNodeName );
  296. // Set ignore-empty flag.
  297. pCustomNode->setIgnoreEmpty( ignoreEmpty );
  298. // Store node.
  299. mChildren.push_back( pCustomNode );
  300. return pCustomNode;
  301. }
  302. inline void removeNode( const U32 index )
  303. {
  304. // Sanity!
  305. AssertFatal( index < (U32)mChildren.size(), "tamlCustomNode::removeNode() - Index is out of bounds." );
  306. // Cache the custom node.
  307. TamlCustomNodeFactory.cacheObject( mChildren[index] );
  308. // Remove it.
  309. mChildren.erase( index );
  310. }
  311. inline const TamlCustomNode* findNode( const char* pNodeName ) const
  312. {
  313. // Sanity!
  314. AssertFatal( pNodeName != NULL, "Cannot find Taml node name that is NULL." );
  315. // Fetch node name.
  316. StringTableEntry nodeName = StringTable->insert( pNodeName );
  317. // Find node.
  318. for( Vector<TamlCustomNode*>::const_iterator nodeItr = mChildren.begin(); nodeItr != mChildren.end(); ++nodeItr )
  319. {
  320. if ( (*nodeItr)->getNodeName() == nodeName )
  321. return (*nodeItr);
  322. }
  323. return NULL;
  324. }
  325. inline TamlCustomField* addField( const char* pFieldName, const ColorI& fieldValue )
  326. {
  327. TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
  328. pNodeField->setFieldValue( pFieldName, fieldValue );
  329. return registerField( pNodeField );
  330. }
  331. inline TamlCustomField* addField( const char* pFieldName, const ColorF& fieldValue )
  332. {
  333. TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
  334. pNodeField->setFieldValue( pFieldName, fieldValue );
  335. return registerField( pNodeField );
  336. }
  337. inline TamlCustomField* addField( const char* pFieldName, const Point2I& fieldValue )
  338. {
  339. TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
  340. pNodeField->setFieldValue( pFieldName, fieldValue );
  341. return registerField( pNodeField );
  342. }
  343. inline TamlCustomField* addField( const char* pFieldName, const Point2F& fieldValue )
  344. {
  345. TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
  346. pNodeField->setFieldValue( pFieldName, fieldValue );
  347. return registerField( pNodeField );
  348. }
  349. inline TamlCustomField* addField( const char* pFieldName, const b2Vec2& fieldValue )
  350. {
  351. TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
  352. pNodeField->setFieldValue( pFieldName, fieldValue );
  353. return registerField( pNodeField );
  354. }
  355. inline TamlCustomField* addField( const char* pFieldName, const U32 fieldValue )
  356. {
  357. TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
  358. pNodeField->setFieldValue( pFieldName, fieldValue );
  359. return registerField( pNodeField );
  360. }
  361. inline TamlCustomField* addField( const char* pFieldName, const bool fieldValue )
  362. {
  363. TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
  364. pNodeField->setFieldValue( pFieldName, fieldValue );
  365. return registerField( pNodeField );
  366. }
  367. inline TamlCustomField* addField( const char* pFieldName, const S32 fieldValue )
  368. {
  369. TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
  370. pNodeField->setFieldValue( pFieldName, fieldValue );
  371. return registerField( pNodeField );
  372. }
  373. inline TamlCustomField* addField( const char* pFieldName, const float fieldValue )
  374. {
  375. TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
  376. pNodeField->setFieldValue( pFieldName, fieldValue );
  377. return registerField( pNodeField );
  378. }
  379. inline TamlCustomField* addField( const char* pFieldName, const char* fieldValue )
  380. {
  381. TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
  382. pNodeField->setFieldValue( pFieldName, fieldValue );
  383. return registerField( pNodeField );
  384. }
  385. inline const TamlCustomField* findField( const char* pFieldName ) const
  386. {
  387. // Sanity!
  388. AssertFatal( pFieldName != NULL, "Cannot find Taml field name that is NULL." );
  389. // Fetch field name.
  390. StringTableEntry fieldName = StringTable->insert( pFieldName );
  391. // Find node field.
  392. for( TamlCustomFieldVector::const_iterator fieldItr = mFields.begin(); fieldItr != mFields.end(); ++fieldItr )
  393. {
  394. if ( (*fieldItr)->getFieldName() == fieldName )
  395. return (*fieldItr);
  396. }
  397. return NULL;
  398. }
  399. inline void setNodeName( const char* pNodeName )
  400. {
  401. // Sanity!
  402. AssertFatal( pNodeName != NULL, "Cannot add a NULL node name." );
  403. mNodeName = StringTable->insert( pNodeName );
  404. }
  405. inline StringTableEntry getNodeName( void ) const { return mNodeName; }
  406. void setWriteNode( TamlWriteNode* pWriteNode );
  407. inline void setNodeText( const char* pNodeText )
  408. {
  409. AssertFatal( dStrlen( pNodeText ) < MAX_TAML_NODE_FIELDVALUE_LENGTH, "Custom node text is too long." );
  410. AssertFatal( mChildren.size() == 0, "Cannot have node text with children." );
  411. AssertFatal( mFields.size() == 0, "Cannot have node text with fields." );
  412. mNodeText.set( StringTable->EmptyString, pNodeText );
  413. }
  414. inline const TamlCustomField& getNodeTextField( void ) const { return mNodeText; }
  415. inline TamlCustomField& getNodeTextField( void ) { return mNodeText; }
  416. inline const Vector<TamlCustomNode*>& getChildren( void ) const { return mChildren; }
  417. inline const TamlCustomFieldVector& getFields( void ) const { return mFields; }
  418. inline bool isProxyObject( void ) const { return mpProxyObject != NULL; }
  419. template<typename T> T* getProxyObject( const bool deleteIfNotType ) const
  420. {
  421. // Return nothing if no proxy object.
  422. if ( mpProxyObject == NULL )
  423. return NULL;
  424. // Cast object to specified type.
  425. T* pTypeCast = dynamic_cast<T*>( mpProxyObject );
  426. // Destroy the object if not the specified type and requested to do so.
  427. if ( deleteIfNotType && pTypeCast == NULL )
  428. {
  429. mpProxyObject->deleteObject();
  430. return NULL;
  431. }
  432. return pTypeCast;
  433. }
  434. inline const TamlWriteNode* getProxyWriteNode( void ) const { return mpProxyWriteNode; }
  435. inline bool isEmpty( void ) const { return mNodeText.isValueEmpty() && mFields.size() == 0 && mChildren.size() == 0; }
  436. inline void setIgnoreEmpty( const bool ignoreEmpty ) { mIgnoreEmpty = ignoreEmpty; }
  437. inline bool getIgnoreEmpty( void ) const { return mIgnoreEmpty; }
  438. private:
  439. inline TamlCustomField* registerField( TamlCustomField* pCustomField )
  440. {
  441. // Sanity!
  442. AssertFatal( *mNodeText.getFieldValue() == 0, "Cannot add field to a node that has node text." );
  443. #if TORQUE_DEBUG
  444. // Ensure a field name conflict does not exist.
  445. for( Vector<TamlCustomField*>::iterator nodeFieldItr = mFields.begin(); nodeFieldItr != mFields.end(); ++nodeFieldItr )
  446. {
  447. // Skip if field name is not the same.
  448. if ( pCustomField->getFieldName() != (*nodeFieldItr)->getFieldName() )
  449. continue;
  450. // Warn!
  451. Con::warnf("Conflicting Taml node field name of '%s' in node '%s'.", pCustomField->getFieldName(), mNodeName );
  452. // Cache node field.
  453. TamlCustomFieldFactory.cacheObject( pCustomField );
  454. return NULL;
  455. }
  456. // Ensure the field value is not too long.
  457. if ( dStrlen( pCustomField->getFieldValue() ) >= MAX_TAML_NODE_FIELDVALUE_LENGTH )
  458. {
  459. // Warn.
  460. Con::warnf("Taml field name '%s' has a field value that is too long (Max:%d): '%s'.",
  461. pCustomField->getFieldName(),
  462. MAX_TAML_NODE_FIELDVALUE_LENGTH,
  463. pCustomField->getFieldValue() );
  464. // Cache node field.
  465. TamlCustomFieldFactory.cacheObject( pCustomField );
  466. return NULL;
  467. }
  468. #endif
  469. // Store node field.
  470. mFields.push_back( pCustomField );
  471. return pCustomField;
  472. }
  473. inline TamlCustomField* createField( void ) const { return TamlCustomFieldFactory.createObject(); }
  474. private:
  475. StringTableEntry mNodeName;
  476. TamlCustomField mNodeText;
  477. Vector<TamlCustomNode*> mChildren;
  478. TamlCustomFieldVector mFields;
  479. bool mIgnoreEmpty;
  480. SimObject* mpProxyObject;
  481. TamlWriteNode* mpProxyWriteNode;
  482. };
  483. //-----------------------------------------------------------------------------
  484. /// @ingroup tamlGroup
  485. /// @see tamlGroup
  486. class TamlCustomNodes : public IFactoryObjectReset
  487. {
  488. public:
  489. TamlCustomNodes()
  490. {
  491. }
  492. virtual ~TamlCustomNodes()
  493. {
  494. resetState();
  495. }
  496. virtual void resetState( void )
  497. {
  498. // Cache the nodes.
  499. while ( mNodes.size() > 0 )
  500. {
  501. TamlCustomNodeFactory.cacheObject( mNodes.back() );
  502. mNodes.pop_back();
  503. }
  504. }
  505. inline TamlCustomNode* addNode( const char* pNodeName, const bool ignoreEmpty = true )
  506. {
  507. // Create a custom node.
  508. TamlCustomNode* pCustomNode = TamlCustomNodeFactory.createObject();
  509. // Set node name.
  510. pCustomNode->setNodeName( pNodeName );
  511. // Set ignore-empty flag.
  512. pCustomNode->setIgnoreEmpty( ignoreEmpty );
  513. #if TORQUE_DEBUG
  514. // Ensure a node name conflict does not exist.
  515. for( TamlCustomNodeVector::iterator nodeItr = mNodes.begin(); nodeItr != mNodes.end(); ++nodeItr )
  516. {
  517. // Skip if node name is not the same.
  518. if ( pCustomNode->getNodeName() != (*nodeItr)->getNodeName() )
  519. continue;
  520. // Warn!
  521. Con::warnf("Conflicting Taml custom node name of '%s'.", pNodeName );
  522. // Cache node.
  523. TamlCustomNodeFactory.cacheObject( pCustomNode );
  524. return NULL;
  525. }
  526. #endif
  527. // Store node.
  528. mNodes.push_back( pCustomNode );
  529. return pCustomNode;
  530. }
  531. inline void removeNode( const U32 index )
  532. {
  533. // Sanity!
  534. AssertFatal( index < (U32)mNodes.size(), "tamlCustomNode::removeNode() - Index is out of bounds." );
  535. // Cache the custom node.
  536. TamlCustomNodeFactory.cacheObject( mNodes[index] );
  537. // Remove it.
  538. mNodes.erase( index );
  539. }
  540. inline const TamlCustomNode* findNode( const char* pNodeName ) const
  541. {
  542. // Sanity!
  543. AssertFatal( pNodeName != NULL, "Cannot find Taml node name that is NULL." );
  544. // Fetch node name.
  545. StringTableEntry nodeName = StringTable->insert( pNodeName );
  546. // Find node.
  547. for( Vector<TamlCustomNode*>::const_iterator nodeItr = mNodes.begin(); nodeItr != mNodes.end(); ++nodeItr )
  548. {
  549. if ( (*nodeItr)->getNodeName() == nodeName )
  550. return (*nodeItr);
  551. }
  552. return NULL;
  553. }
  554. inline const TamlCustomNodeVector& getNodes( void ) const { return mNodes; }
  555. private:
  556. TamlCustomNodeVector mNodes;
  557. };
  558. #endif // _TAML_CUSTOM_H_