SpriteBatch.cc 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415
  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 _SPRITE_BATCH_H_
  23. #include "SpriteBatch.h"
  24. #endif
  25. #ifndef _SPRITE_BATCH_QUERY_H_
  26. #include "2d/core/spriteBatchQuery.h"
  27. #endif
  28. #ifndef _SCENE_RENDER_OBJECT_H_
  29. #include "2d/scene/SceneRenderObject.h"
  30. #endif
  31. //------------------------------------------------------------------------------
  32. static StringTableEntry spritesNodeName = StringTable->insert( "Sprites" );
  33. //------------------------------------------------------------------------------
  34. SpriteBatch::SpriteBatch() :
  35. mMasterBatchId( 0 ),
  36. mSelectedSprite( NULL ),
  37. mBatchSortMode( SceneRenderQueue::RENDER_SORT_OFF ),
  38. mDefaultSpriteStride( 1.0f, 1.0f),
  39. mDefaultSpriteSize( 1.0f, 1.0f ),
  40. mDefaultSpriteAngle( 0.0f ),
  41. mpSpriteBatchQuery( NULL ),
  42. mBatchCulling( true )
  43. {
  44. // Reset batch transform.
  45. mBatchTransform.SetIdentity();
  46. mBatchTransformDirty = true;
  47. mBatchTransformId = 0;
  48. // Reset local extents.
  49. mLocalExtents.SetZero();
  50. mLocalExtentsDirty = true;
  51. }
  52. //------------------------------------------------------------------------------
  53. SpriteBatch::~SpriteBatch()
  54. {
  55. }
  56. //-----------------------------------------------------------------------------
  57. bool SpriteBatch::onAdd()
  58. {
  59. // Create the sprite batch query if required.
  60. if ( mBatchCulling )
  61. createSpriteBatchQuery();
  62. return true;
  63. }
  64. //-----------------------------------------------------------------------------
  65. void SpriteBatch::onRemove()
  66. {
  67. // Clear the sprites.
  68. clearSprites();
  69. // Delete the sprite batch query.
  70. destroySpriteBatchQuery();
  71. }
  72. //-----------------------------------------------------------------------------
  73. void SpriteBatch::prepareRender( SceneRenderObject* pSceneRenderObject, const SceneRenderState* pSceneRenderState, SceneRenderQueue* pSceneRenderQueue )
  74. {
  75. // Debug Profiling.
  76. PROFILE_SCOPE(SpriteBatch_PrepareRender);
  77. // Set the sort mode.
  78. pSceneRenderQueue->setSortMode( getBatchSortMode() );
  79. // Calculate local AABB.
  80. const b2AABB localAABB = calculateLocalAABB( pSceneRenderState->mRenderAABB );
  81. // Do we have a sprite batch query?
  82. if ( mpSpriteBatchQuery != NULL )
  83. {
  84. // Yes, so debug Profiling.
  85. PROFILE_START(SpriteBatch_PrepareRenderQuery);
  86. // Yes, so fetch sprite batch query and clear results.
  87. SpriteBatchQuery* pSpriteBatchQuery = getSpriteBatchQuery( true );
  88. // Perform query.
  89. pSpriteBatchQuery->queryArea( localAABB, false );
  90. // Debug Profiling.
  91. PROFILE_END(); // SpriteBatch_PrepareRenderQuery
  92. // Fetch result count.
  93. const U32 resultCount = pSpriteBatchQuery->getQueryResultsCount();
  94. // Finish if no results.
  95. if ( resultCount == 0 )
  96. return;
  97. // Fetch results.
  98. typeSpriteBatchQueryResultVector& queryResults = pSpriteBatchQuery->getQueryResults();
  99. // Add picked sprites.
  100. for ( U32 n = 0; n < resultCount; n++ )
  101. {
  102. // Fetch sprite batch Item.
  103. SpriteBatchItem* pSpriteBatchItem = queryResults[n].mpSpriteBatchItem;
  104. // Skip if not visible.
  105. if ( !pSpriteBatchItem->getVisible() )
  106. continue;
  107. // Create a render request.
  108. SceneRenderRequest* pSceneRenderRequest = pSceneRenderQueue->createRenderRequest();
  109. // Prepare batch item.
  110. pSpriteBatchItem->prepareRender( pSceneRenderRequest, mBatchTransformId );
  111. // Set identity.
  112. pSceneRenderRequest->mpSceneRenderObject = pSceneRenderObject;
  113. // Set custom data.
  114. pSceneRenderRequest->mpCustomData1 = pSpriteBatchItem;
  115. }
  116. // Clear sprite batch query.
  117. pSpriteBatchQuery->clearQuery();
  118. }
  119. else
  120. {
  121. // No, so perform a render request for all the sprites.
  122. for( typeSpriteBatchHash::iterator spriteItr = mSprites.begin(); spriteItr != mSprites.end(); ++spriteItr )
  123. {
  124. // Fetch sprite batch Item.
  125. SpriteBatchItem* pSpriteBatchItem = spriteItr->value;
  126. // Skip if not visible.
  127. if ( !pSpriteBatchItem->getVisible() )
  128. continue;
  129. // Create a render request.
  130. SceneRenderRequest* pSceneRenderRequest = pSceneRenderQueue->createRenderRequest();
  131. // Prepare batch item.
  132. pSpriteBatchItem->prepareRender( pSceneRenderRequest, mBatchTransformId );
  133. // Set identity.
  134. pSceneRenderRequest->mpSceneRenderObject = pSceneRenderObject;
  135. // Set custom data.
  136. pSceneRenderRequest->mpCustomData1 = pSpriteBatchItem;
  137. }
  138. }
  139. }
  140. //------------------------------------------------------------------------------
  141. void SpriteBatch::render( const SceneRenderState* pSceneRenderState, const SceneRenderRequest* pSceneRenderRequest, BatchRender* pBatchRenderer )
  142. {
  143. // Fetch sprite batch Item.
  144. SpriteBatchItem* pSpriteBatchItem = (SpriteBatchItem*)pSceneRenderRequest->mpCustomData1;
  145. // Batch render.
  146. pSpriteBatchItem->render( pBatchRenderer, pSceneRenderRequest, mBatchTransformId );
  147. }
  148. //------------------------------------------------------------------------------
  149. void SpriteBatch::createQueryProxy( SpriteBatchItem* pSpriteBatchItem )
  150. {
  151. // Sanity!
  152. AssertFatal( pSpriteBatchItem != NULL, "SpriteBatch:createQueryProxy() - Cannot create query proxy on NULL sprite batch item." );
  153. // Debug Profiling.
  154. PROFILE_SCOPE(SpriteBatch_CreateTreeProxy);
  155. // Finish if the batch query is not available.
  156. if ( mpSpriteBatchQuery == NULL )
  157. return;
  158. // Create proxy.
  159. pSpriteBatchItem->mProxyId = mpSpriteBatchQuery->add( pSpriteBatchItem );
  160. }
  161. //------------------------------------------------------------------------------
  162. void SpriteBatch::destroyQueryProxy( SpriteBatchItem* pSpriteBatchItem )
  163. {
  164. // Sanity!
  165. AssertFatal( pSpriteBatchItem != NULL, "SpriteBatch:destroyQueryProxy() - Cannot destroy query proxy on NULL sprite batch item." );
  166. // Debug Profiling.
  167. PROFILE_SCOPE(SpriteBatch_DestroyTreeProxy);
  168. // Finish if the batch query is not available.
  169. if ( mpSpriteBatchQuery == NULL )
  170. return;
  171. // Destroy proxy.
  172. mpSpriteBatchQuery->remove( pSpriteBatchItem );
  173. // Remove proxy reference.
  174. pSpriteBatchItem->mProxyId = INVALID_SPRITE_PROXY;
  175. }
  176. //------------------------------------------------------------------------------
  177. void SpriteBatch::moveQueryProxy( SpriteBatchItem* pSpriteBatchItem, const b2AABB& localAABB )
  178. {
  179. // Sanity!
  180. AssertFatal( pSpriteBatchItem != NULL, "SpriteBatch:moveQueryProxy() - Cannot move query proxy on NULL sprite batch item." );
  181. // Debug Profiling.
  182. PROFILE_SCOPE(SpriteBatch_MoveTreeProxy);
  183. // Finish if the batch query is not available.
  184. if ( mpSpriteBatchQuery == NULL || pSpriteBatchItem->getProxyId() == INVALID_SPRITE_PROXY )
  185. return;
  186. // Move proxy.
  187. mpSpriteBatchQuery->update( pSpriteBatchItem, localAABB, b2Vec2(0.0f, 0.0f) );
  188. }
  189. //------------------------------------------------------------------------------
  190. SpriteBatchQuery* SpriteBatch::getSpriteBatchQuery( const bool clearQuery )
  191. {
  192. if ( mpSpriteBatchQuery == NULL )
  193. return NULL;
  194. // Clear the query if specified.
  195. if ( clearQuery )
  196. mpSpriteBatchQuery->clearQuery();
  197. return mpSpriteBatchQuery;
  198. }
  199. //------------------------------------------------------------------------------
  200. void SpriteBatch::copyTo( SpriteBatch* pSpriteBatch ) const
  201. {
  202. // Clear any existing sprites.
  203. pSpriteBatch->clearSprites();
  204. // Set master sprite Id.
  205. pSpriteBatch->mMasterBatchId = mMasterBatchId;
  206. // Set batch sort mode.
  207. pSpriteBatch->setBatchSortMode( getBatchSortMode() );
  208. // Set batch culling.
  209. pSpriteBatch->setBatchCulling( getBatchCulling() );
  210. // Set sprite default size and angle.
  211. pSpriteBatch->setDefaultSpriteStride( getDefaultSpriteStride() );
  212. pSpriteBatch->setDefaultSpriteSize( getDefaultSpriteSize() );
  213. pSpriteBatch->setDefaultSpriteAngle( getDefaultSpriteAngle() );
  214. // Copy sprites.
  215. for( typeSpriteBatchHash::const_iterator spriteItr = mSprites.begin(); spriteItr != mSprites.end(); ++spriteItr )
  216. {
  217. // Fetch sprite.
  218. SpriteBatchItem* pSpriteBatchItem = spriteItr->value;
  219. // Add a sprite.
  220. const U32 spriteBatchId = pSpriteBatch->addSprite( pSpriteBatchItem->getLogicalPosition() );
  221. // Fetch new sprite.
  222. SpriteBatchItem* pNewSpriteBatchItem = pSpriteBatch->findSpriteId( spriteBatchId );
  223. // Push a copy to it.
  224. pSpriteBatchItem->copyTo( pNewSpriteBatchItem );
  225. }
  226. }
  227. //------------------------------------------------------------------------------
  228. U32 SpriteBatch::addSprite( const SpriteBatchItem::LogicalPosition& logicalPosition )
  229. {
  230. // Debug Profiling.
  231. PROFILE_SCOPE(SpriteBatch_AddSprite);
  232. // Create sprite layout.
  233. mSelectedSprite = createSprite( logicalPosition );
  234. // Finish if no sprite created.
  235. if ( mSelectedSprite == NULL )
  236. return 0;
  237. // Insert logical position into sprite positions if it's valid.
  238. if ( logicalPosition.isValid() )
  239. mSpritePositions.insert( logicalPosition, mSelectedSprite );
  240. // Flag local extents as dirty.
  241. setLocalExtentsDirty();
  242. return mSelectedSprite->getBatchId();
  243. }
  244. //------------------------------------------------------------------------------
  245. bool SpriteBatch::removeSprite( void )
  246. {
  247. // Debug Profiling.
  248. PROFILE_SCOPE(SpriteBatch_RemoveSprite);
  249. // Finish if a sprite is not selected.
  250. if ( !checkSpriteSelected() )
  251. return false;
  252. // Remove the sprite logical position if it's valid.
  253. const SpriteBatchItem::LogicalPosition& logicalPosition = mSelectedSprite->getLogicalPosition();
  254. if ( logicalPosition.isValid() )
  255. mSpritePositions.erase( mSelectedSprite->getLogicalPosition() );
  256. // Fetch and remove any sprite name.
  257. StringTableEntry spriteName = mSelectedSprite->getName();
  258. if ( spriteName != StringTable->EmptyString )
  259. mSpriteNames.erase( spriteName );
  260. // Destroy the sprite.
  261. destroySprite( mSelectedSprite->getBatchId() );
  262. // Reset the selected sprite.
  263. mSelectedSprite = NULL;
  264. // Flag local extents as dirty.
  265. setLocalExtentsDirty();
  266. return true;
  267. }
  268. //------------------------------------------------------------------------------
  269. void SpriteBatch::clearSprites( void )
  270. {
  271. // Debug Profiling.
  272. PROFILE_SCOPE(SpriteBatch_ClearSprites);
  273. // Deselect any sprite.
  274. deselectSprite();
  275. // Clear sprite positions.
  276. mSpritePositions.clear();
  277. // Clear sprite names.
  278. mSpriteNames.clear();
  279. // Cache all sprites.
  280. for( typeSpriteBatchHash::iterator spriteItr = mSprites.begin(); spriteItr != mSprites.end(); ++spriteItr )
  281. {
  282. SpriteBatchItemFactory.cacheObject( spriteItr->value );
  283. }
  284. mSprites.clear();
  285. mMasterBatchId = 0;
  286. // Flag local extents as dirty.
  287. setLocalExtentsDirty();
  288. }
  289. //------------------------------------------------------------------------------
  290. void SpriteBatch::setBatchCulling( const bool batchCulling )
  291. {
  292. // Finish if no change.
  293. if ( mBatchCulling == batchCulling )
  294. return;
  295. // Set batch culling.
  296. mBatchCulling = batchCulling;
  297. // Create/destroy sprite batch query appropriately.
  298. if ( mBatchCulling )
  299. createSpriteBatchQuery();
  300. else
  301. destroySpriteBatchQuery();
  302. }
  303. //------------------------------------------------------------------------------
  304. bool SpriteBatch::selectSprite( const SpriteBatchItem::LogicalPosition& logicalPosition )
  305. {
  306. // Select sprite.
  307. mSelectedSprite = findSpritePosition( logicalPosition );
  308. // Finish if we selected the sprite.
  309. if ( mSelectedSprite != NULL )
  310. return true;
  311. // Not selected so warn.
  312. Con::warnf( "Cannot select sprite at logical position '%s' as one does not exist.", logicalPosition.getString() );
  313. return false;
  314. }
  315. //------------------------------------------------------------------------------
  316. bool SpriteBatch::selectSpriteId( const U32 batchId )
  317. {
  318. // Select sprite.
  319. mSelectedSprite = findSpriteId( batchId );
  320. // Finish if we selected the sprite.
  321. if ( mSelectedSprite != NULL )
  322. return true;
  323. // Not selected so warn.
  324. Con::warnf( "Cannot select sprite Id '%d' as it does not exist.", batchId );
  325. return false;
  326. }
  327. //------------------------------------------------------------------------------
  328. bool SpriteBatch::selectSpriteName( const char* pName )
  329. {
  330. // Fail if no name specified.
  331. if ( pName == NULL || pName == StringTable->EmptyString )
  332. return false;
  333. // Select sprite.
  334. mSelectedSprite = findSpriteName( pName );
  335. // Finish if we selected the sprite.
  336. if ( mSelectedSprite != NULL )
  337. return true;
  338. // Not selected so warn.
  339. Con::warnf( "Cannot select sprite name '%s' as it does not exist.", pName );
  340. return false;
  341. }
  342. //------------------------------------------------------------------------------
  343. void SpriteBatch::setSpriteImage( const char* pAssetId, const U32 imageFrame )
  344. {
  345. // Debug Profiling.
  346. PROFILE_SCOPE(SpriteBatch_SetSpriteImage);
  347. // Sanity!
  348. AssertFatal( pAssetId, "Cannot set sprite image using a NULL asset Id." );
  349. // Finish if a sprite is not selected.
  350. if ( !checkSpriteSelected() )
  351. return;
  352. // Set image and frame.
  353. mSelectedSprite->setImage( pAssetId, imageFrame );
  354. }
  355. //------------------------------------------------------------------------------
  356. StringTableEntry SpriteBatch::getSpriteImage( void ) const
  357. {
  358. // Finish if a sprite is not selected.
  359. if ( !checkSpriteSelected() )
  360. return StringTable->EmptyString;
  361. // Get sprite image.
  362. return mSelectedSprite->getImage();
  363. }
  364. //------------------------------------------------------------------------------
  365. void SpriteBatch::setSpriteImageFrame( const U32 imageFrame )
  366. {
  367. // Finish if a sprite is not selected.
  368. if ( !checkSpriteSelected() )
  369. return;
  370. // Set image frame.
  371. mSelectedSprite->setImageFrame( imageFrame );
  372. }
  373. //------------------------------------------------------------------------------
  374. U32 SpriteBatch::getSpriteImageFrame( void ) const
  375. {
  376. // Finish if a sprite is not selected.
  377. if ( !checkSpriteSelected() )
  378. return 0;
  379. // Get image frame.
  380. return mSelectedSprite->getImageFrame();
  381. }
  382. //------------------------------------------------------------------------------
  383. void SpriteBatch::setSpriteAnimation( const char* pAssetId )
  384. {
  385. // Debug Profiling.
  386. PROFILE_SCOPE(SpriteBatch_SetSpriteAnimation);
  387. // Sanity!
  388. AssertFatal( pAssetId, "Cannot set sprite animation using a NULL asset Id." );
  389. // Finish if a sprite is not selected.
  390. if ( !checkSpriteSelected() )
  391. return;
  392. // Set animation.
  393. mSelectedSprite->setAnimation( pAssetId );
  394. }
  395. //------------------------------------------------------------------------------
  396. StringTableEntry SpriteBatch::getSpriteAnimation( void ) const
  397. {
  398. // Finish if a sprite is not selected.
  399. if ( !checkSpriteSelected() )
  400. return StringTable->EmptyString;
  401. // Get animation.
  402. return mSelectedSprite->getAnimation();
  403. }
  404. //------------------------------------------------------------------------------
  405. void SpriteBatch::clearSpriteAsset( void )
  406. {
  407. // Finish if a sprite is not selected.
  408. if ( !checkSpriteSelected() )
  409. return;
  410. // Clear the asset.
  411. mSelectedSprite->clearAssets();
  412. }
  413. //------------------------------------------------------------------------------
  414. void SpriteBatch::setSpriteVisible( const bool visible )
  415. {
  416. // Finish if a sprite is not selected.
  417. if ( !checkSpriteSelected() )
  418. return;
  419. // Set visibility.
  420. mSelectedSprite->setVisible( visible );
  421. }
  422. //------------------------------------------------------------------------------
  423. bool SpriteBatch::getSpriteVisible( void ) const
  424. {
  425. // Finish if a sprite is not selected.
  426. if ( !checkSpriteSelected() )
  427. return false;
  428. // Get visibility.
  429. return mSelectedSprite->getVisible();
  430. }
  431. //------------------------------------------------------------------------------
  432. void SpriteBatch::setSpriteLocalPosition( const Vector2& localPosition )
  433. {
  434. // Finish if a sprite is not selected.
  435. if ( !checkSpriteSelected() )
  436. return;
  437. // Set local position.
  438. mSelectedSprite->setLocalPosition( localPosition );
  439. // Flag local extents as dirty.
  440. setLocalExtentsDirty();
  441. }
  442. //------------------------------------------------------------------------------
  443. Vector2 SpriteBatch::getSpriteLocalPosition( void )
  444. {
  445. // Finish if a sprite is not selected.
  446. if ( !checkSpriteSelected() )
  447. return Vector2::getZero();
  448. // Get local position.
  449. return mSelectedSprite->getLocalPosition();
  450. }
  451. //------------------------------------------------------------------------------
  452. void SpriteBatch::setSpriteAngle( const F32 localAngle )
  453. {
  454. // Finish if a sprite is not selected.
  455. if ( !checkSpriteSelected() )
  456. return;
  457. // Set local angle.
  458. mSelectedSprite->setLocalAngle( localAngle );
  459. // Flag local extents as dirty.
  460. setLocalExtentsDirty();
  461. }
  462. //------------------------------------------------------------------------------
  463. F32 SpriteBatch::getSpriteAngle( void ) const
  464. {
  465. // Finish if a sprite is not selected.
  466. if ( !checkSpriteSelected() )
  467. return 0.0f;
  468. // Get local angle.
  469. return mSelectedSprite->getLocalAngle();
  470. }
  471. //------------------------------------------------------------------------------
  472. void SpriteBatch::setSpriteDepth( const F32 depth )
  473. {
  474. // Finish if a sprite is not selected.
  475. if ( !checkSpriteSelected() )
  476. return;
  477. // Set depth.
  478. mSelectedSprite->setDepth( depth );
  479. }
  480. //------------------------------------------------------------------------------
  481. F32 SpriteBatch::getSpriteDepth( void ) const
  482. {
  483. // Finish if a sprite is not selected.
  484. if ( !checkSpriteSelected() )
  485. return 0.0f;
  486. // Get depth.
  487. return mSelectedSprite->getDepth();
  488. }
  489. //------------------------------------------------------------------------------
  490. void SpriteBatch::setSpriteSize( const Vector2& size )
  491. {
  492. // Finish if a sprite is not selected.
  493. if ( !checkSpriteSelected() )
  494. return;
  495. // Set size.
  496. mSelectedSprite->setSize( size );
  497. // Flag local extents as dirty.
  498. setLocalExtentsDirty();
  499. }
  500. //------------------------------------------------------------------------------
  501. Vector2 SpriteBatch::getSpriteSize( void ) const
  502. {
  503. // Finish if a sprite is not selected.
  504. if ( !checkSpriteSelected() )
  505. return Vector2::getZero();
  506. // Get size.
  507. return mSelectedSprite->getSize();
  508. }
  509. //------------------------------------------------------------------------------
  510. void SpriteBatch::setSpriteFlipX( const bool flipX )
  511. {
  512. // Finish if a sprite is not selected.
  513. if ( !checkSpriteSelected() )
  514. return;
  515. // Set flip X.
  516. mSelectedSprite->setFlipX( flipX );
  517. }
  518. //------------------------------------------------------------------------------
  519. bool SpriteBatch::getSpriteFlipX( void ) const
  520. {
  521. // Finish if a sprite is not selected.
  522. if ( !checkSpriteSelected() )
  523. return false;
  524. // Get flip X.
  525. return mSelectedSprite->getFlipX();
  526. }
  527. //------------------------------------------------------------------------------
  528. void SpriteBatch::setSpriteFlipY( const bool flipY )
  529. {
  530. // Finish if a sprite is not selected.
  531. if ( !checkSpriteSelected() )
  532. return;
  533. // Set flip Y.
  534. mSelectedSprite->setFlipY( flipY );
  535. }
  536. //------------------------------------------------------------------------------
  537. bool SpriteBatch::getSpriteFlipY( void ) const
  538. {
  539. // Finish if a sprite is not selected.
  540. if ( !checkSpriteSelected() )
  541. return false;
  542. // Get flip Y.
  543. return mSelectedSprite->getFlipY();
  544. }
  545. //------------------------------------------------------------------------------
  546. void SpriteBatch::setSpriteSortPoint( const Vector2& sortPoint )
  547. {
  548. // Finish if a sprite is not selected.
  549. if ( !checkSpriteSelected() )
  550. return;
  551. // Set sort point.
  552. mSelectedSprite->setSortPoint( sortPoint );
  553. }
  554. //------------------------------------------------------------------------------
  555. Vector2 SpriteBatch::getSpriteSortPoint( void ) const
  556. {
  557. // Finish if a sprite is not selected.
  558. if ( !checkSpriteSelected() )
  559. return Vector2::getZero();
  560. // Get sort point.
  561. return mSelectedSprite->getSortPoint();
  562. }
  563. //------------------------------------------------------------------------------
  564. void SpriteBatch::setSpriteRenderGroup( const char* pRenderGroup )
  565. {
  566. // Finish if a sprite is not selected.
  567. if ( !checkSpriteSelected() )
  568. return;
  569. // Set render group.
  570. mSelectedSprite->setRenderGroup( pRenderGroup );
  571. }
  572. //------------------------------------------------------------------------------
  573. StringTableEntry SpriteBatch::getSpriteRenderGroup( void ) const
  574. {
  575. // Finish if a sprite is not selected.
  576. if ( !checkSpriteSelected() )
  577. return NULL;
  578. // Get render group.
  579. return mSelectedSprite->getRenderGroup();
  580. }
  581. //------------------------------------------------------------------------------
  582. void SpriteBatch::setSpriteBlendMode( const bool blendMode )
  583. {
  584. // Finish if a sprite is not selected.
  585. if ( !checkSpriteSelected() )
  586. return;
  587. // Set blend mode.
  588. mSelectedSprite->setBlendMode( blendMode );
  589. }
  590. //------------------------------------------------------------------------------
  591. bool SpriteBatch::getSpriteBlendMode( void ) const
  592. {
  593. // Finish if a sprite is not selected.
  594. if ( !checkSpriteSelected() )
  595. return true;
  596. // Get blend mode.
  597. return mSelectedSprite->getBlendMode();
  598. }
  599. //------------------------------------------------------------------------------
  600. void SpriteBatch::setSpriteSrcBlendFactor( GLenum srcBlendFactor )
  601. {
  602. // Finish if a sprite is not selected.
  603. if ( !checkSpriteSelected() )
  604. return;
  605. // Set source blend factor.
  606. mSelectedSprite->setSrcBlendFactor( srcBlendFactor );
  607. }
  608. //------------------------------------------------------------------------------
  609. GLenum SpriteBatch::getSpriteSrcBlendFactor( void ) const
  610. {
  611. // Finish if a sprite is not selected.
  612. if ( !checkSpriteSelected() )
  613. return GL_SRC_ALPHA;
  614. // Get source blend factor.
  615. return mSelectedSprite->getSrcBlendFactor();
  616. }
  617. //------------------------------------------------------------------------------
  618. void SpriteBatch::setSpriteDstBlendFactor( GLenum dstBlendFactor )
  619. {
  620. // Finish if a sprite is not selected.
  621. if ( !checkSpriteSelected() )
  622. return ;
  623. // Set destination blend factor.
  624. mSelectedSprite->setDstBlendFactor( dstBlendFactor );
  625. }
  626. //------------------------------------------------------------------------------
  627. GLenum SpriteBatch::getSpriteDstBlendFactor( void ) const
  628. {
  629. // Finish if a sprite is not selected.
  630. if ( !checkSpriteSelected() )
  631. return GL_ONE_MINUS_SRC_ALPHA;
  632. // Get destination blend factor.
  633. return mSelectedSprite->getDstBlendFactor();
  634. }
  635. //------------------------------------------------------------------------------
  636. void SpriteBatch::setSpriteBlendColor( const ColorF& blendColor )
  637. {
  638. // Finish if a sprite is not selected.
  639. if ( !checkSpriteSelected() )
  640. return;
  641. // Set blend color.
  642. mSelectedSprite->setBlendColor( blendColor );
  643. }
  644. //------------------------------------------------------------------------------
  645. const ColorF& SpriteBatch::getSpriteBlendColor( void ) const
  646. {
  647. // Finish if a sprite is not selected.
  648. if ( !checkSpriteSelected() )
  649. return ColorF::StockColor("White");
  650. // Get blend color.
  651. return mSelectedSprite->getBlendColor();
  652. }
  653. //------------------------------------------------------------------------------
  654. void SpriteBatch::setSpriteBlendAlpha( const F32 alpha )
  655. {
  656. // Finish if a sprite is not selected.
  657. if ( !checkSpriteSelected() )
  658. return;
  659. // Set blend alpha.
  660. mSelectedSprite->setBlendAlpha( alpha );
  661. }
  662. //------------------------------------------------------------------------------
  663. F32 SpriteBatch::getSpriteBlendAlpha( void ) const
  664. {
  665. // Finish if a sprite is not selected.
  666. if ( !checkSpriteSelected() )
  667. return 0.0f;
  668. // Get blend alpha.
  669. return mSelectedSprite->getBlendAlpha();
  670. }
  671. //------------------------------------------------------------------------------
  672. void SpriteBatch::setSpriteAlphaTest( const F32 alphaTestMode )
  673. {
  674. // Finish if a sprite is not selected.
  675. if ( !checkSpriteSelected() )
  676. return;
  677. // Set alpha-test mode.
  678. mSelectedSprite->setAlphaTest( alphaTestMode );
  679. }
  680. //------------------------------------------------------------------------------
  681. F32 SpriteBatch::getSpriteAlphaTest( void ) const
  682. {
  683. // Finish if a sprite is not selected.
  684. if ( !checkSpriteSelected() )
  685. return -1.0f;
  686. // Get alpha-test mode.
  687. return mSelectedSprite->getAlphaTest();
  688. }
  689. //------------------------------------------------------------------------------
  690. void SpriteBatch::setSpriteDataObject( SimObject* pDataObject )
  691. {
  692. // Finish if a sprite is not selected.
  693. if ( !checkSpriteSelected() )
  694. return;
  695. // Set data object.
  696. mSelectedSprite->setDataObject( pDataObject );
  697. }
  698. //------------------------------------------------------------------------------
  699. SimObject* SpriteBatch::getSpriteDataObject( void ) const
  700. {
  701. // Finish if a sprite is not selected.
  702. if ( !checkSpriteSelected() )
  703. return NULL;
  704. // Get data object.
  705. return mSelectedSprite->getDataObject();
  706. }
  707. //------------------------------------------------------------------------------
  708. void SpriteBatch::setUserData( void* pUserData )
  709. {
  710. // Finish if a sprite is not selected.
  711. if ( !checkSpriteSelected() )
  712. return;
  713. // Set user data.
  714. mSelectedSprite->setUserData( pUserData );
  715. }
  716. //------------------------------------------------------------------------------
  717. void* SpriteBatch::getUserData( void ) const
  718. {
  719. // Finish if a sprite is not selected.
  720. if ( !checkSpriteSelected() )
  721. return NULL;
  722. // Get user data.
  723. return mSelectedSprite->getUserData();
  724. }
  725. //------------------------------------------------------------------------------
  726. void SpriteBatch::setSpriteName( const char* pName )
  727. {
  728. // Finish if a sprite is not selected.
  729. if ( !checkSpriteSelected() )
  730. return;
  731. // Finish if the sprite name already exists.
  732. if ( findSpriteName( pName ) )
  733. return;
  734. // Insert sprite name.
  735. mSpriteNames.insert( StringTable->insert( pName ), mSelectedSprite );
  736. // Set name.
  737. mSelectedSprite->setName( pName );
  738. }
  739. //------------------------------------------------------------------------------
  740. StringTableEntry SpriteBatch::getSpriteName( void ) const
  741. {
  742. // Finish if a sprite is not selected.
  743. if ( !checkSpriteSelected() )
  744. return StringTable->EmptyString;
  745. // Get name.
  746. return mSelectedSprite->getName();
  747. }
  748. //------------------------------------------------------------------------------
  749. SpriteBatchItem* SpriteBatch::createSprite( void )
  750. {
  751. // Debug Profiling.
  752. PROFILE_SCOPE(SpriteBatch_CreateSprite);
  753. // Allocate batch Id.
  754. const U32 batchId = ++mMasterBatchId;
  755. // Create sprite batch item,
  756. SpriteBatchItem* pSpriteBatchItem = SpriteBatchItemFactory.createObject();
  757. // Set batch parent.
  758. pSpriteBatchItem->setBatchParent( this, batchId );
  759. // Create sprite batch item,
  760. mSprites.insert( batchId, pSpriteBatchItem );
  761. return pSpriteBatchItem;
  762. }
  763. //------------------------------------------------------------------------------
  764. SpriteBatchItem* SpriteBatch::findSpritePosition( const SpriteBatchItem::LogicalPosition& logicalPosition )
  765. {
  766. // Debug Profiling.
  767. PROFILE_SCOPE(SpriteBatch_FindSpritePosition);
  768. // Invalid logical positions are not stored.
  769. if ( !logicalPosition.isValid() )
  770. return NULL;
  771. // Find sprite.
  772. typeSpritePositionHash::iterator spriteItr = mSpritePositions.find( logicalPosition );
  773. return spriteItr == mSpritePositions.end() ? NULL : spriteItr->value;
  774. }
  775. //------------------------------------------------------------------------------
  776. SpriteBatchItem* SpriteBatch::findSpriteId( const U32 batchId )
  777. {
  778. // Debug Profiling.
  779. PROFILE_SCOPE(SpriteBatch_FindSpriteId);
  780. // Find sprite.
  781. typeSpriteBatchHash::iterator spriteItr = mSprites.find( batchId );
  782. return spriteItr != mSprites.end() ? spriteItr->value : NULL;
  783. }
  784. //------------------------------------------------------------------------------
  785. SpriteBatchItem* SpriteBatch::findSpriteName( const char* pName )
  786. {
  787. // Debug Profiling.
  788. PROFILE_SCOPE(SpriteBatch_FindSpriteName);
  789. // Finish if no name specified.
  790. if ( pName == NULL || pName == StringTable->EmptyString )
  791. return NULL;
  792. // Find sprite.
  793. typeSpriteNameHash::iterator spriteItr = mSpriteNames.find( StringTable->insert(pName) );
  794. return spriteItr != mSpriteNames.end() ? spriteItr->value : NULL;
  795. }
  796. //------------------------------------------------------------------------------
  797. SpriteBatchItem* SpriteBatch::createSprite( const SpriteBatchItem::LogicalPosition& logicalPosition )
  798. {
  799. // Debug Profiling.
  800. PROFILE_SCOPE(SpriteBatch_CreateSpriteAtLogicalPosition);
  801. // Reset sprite batch item.
  802. SpriteBatchItem* pSpriteBatchItem = NULL;
  803. // Do we have a valid logical position?
  804. if ( logicalPosition.isValid() )
  805. {
  806. // Does it have the correct argument count?
  807. if ( logicalPosition.getArgCount() != 2 )
  808. {
  809. // No, so warn.
  810. Con::warnf( "Invalid logical position specified for composite sprite." );
  811. return NULL;
  812. }
  813. // Does the sprite already exist?
  814. if ( findSpritePosition( logicalPosition ) != NULL )
  815. {
  816. // Yes, so warn.
  817. Con::warnf( "Cannot add sprite at logical position '%s' as one already exists.", logicalPosition.getString() );
  818. return NULL;
  819. }
  820. // Create the sprite.
  821. pSpriteBatchItem = createSprite();
  822. // Set the logical position.
  823. pSpriteBatchItem->setLogicalPosition( logicalPosition );
  824. // Set the sprite default local position.
  825. pSpriteBatchItem->setLocalPosition( logicalPosition.getAsVector2() );
  826. }
  827. else
  828. {
  829. // Create the sprite.
  830. pSpriteBatchItem = createSprite();
  831. }
  832. // Set the sprite default size and angle.
  833. pSpriteBatchItem->setSize( getDefaultSpriteSize() );
  834. pSpriteBatchItem->setLocalAngle( getDefaultSpriteAngle() );
  835. return pSpriteBatchItem;
  836. }
  837. //------------------------------------------------------------------------------
  838. void SpriteBatch::setBatchTransform( const b2Transform& batchTransform )
  839. {
  840. // Update world transform.
  841. mBatchTransform = batchTransform;
  842. // Flag the batch transform as dirty.
  843. setBatchTransformDirty();
  844. }
  845. //------------------------------------------------------------------------------
  846. void SpriteBatch::updateLocalExtents( void )
  847. {
  848. // Debug Profiling.
  849. PROFILE_SCOPE(SpriteBatch_UpdateLocalExtents);
  850. // Finish if the local extents are not dirty.
  851. if ( !mLocalExtentsDirty )
  852. return;
  853. // Flag as NOT dirty.
  854. mLocalExtentsDirty = false;
  855. // Do we have any sprites?
  856. if ( mSprites.size() == 0 )
  857. {
  858. // No, so reset local extents.
  859. mLocalExtents.setOne();
  860. return;
  861. }
  862. // Fetch first sprite.
  863. typeSpriteBatchHash::iterator spriteItr = mSprites.begin();
  864. // Set render AABB to this sprite.
  865. b2AABB localAABB = spriteItr->value->getLocalAABB();
  866. // Combine with the rest of the sprites.
  867. for( ; spriteItr != mSprites.end(); ++spriteItr )
  868. {
  869. localAABB.Combine( spriteItr->value->getLocalAABB() );
  870. }
  871. // Fetch local render extents.
  872. const b2Vec2& localLowerExtent = localAABB.lowerBound;
  873. const b2Vec2& localUpperExtent = localAABB.upperBound;
  874. // Calculate maximum extents.
  875. const F32 lowerExtentX = mFabs(localLowerExtent.x);
  876. const F32 lowerExtentY = mFabs(localLowerExtent.y);
  877. const F32 upperExtentX = mFabs(localUpperExtent.x);
  878. const F32 upperExtentY = mFabs(localUpperExtent.y);
  879. // Calculate local extents.
  880. mLocalExtents.Set( mFabs(lowerExtentX > upperExtentX ? lowerExtentX : upperExtentX) * 2.0f, mFabs(lowerExtentY > upperExtentY ? lowerExtentY : upperExtentY) * 2.0f );
  881. }
  882. //------------------------------------------------------------------------------
  883. void SpriteBatch::createSpriteBatchQuery( void )
  884. {
  885. // Debug Profiling.
  886. PROFILE_SCOPE(SpriteBatch_CreateSpriteBatchQuery);
  887. // Finish if batch culling is off or there is already a sprite batch query.
  888. if ( !mBatchCulling || mpSpriteBatchQuery != NULL )
  889. return;
  890. // Set the sprite batch query appropriately.
  891. mpSpriteBatchQuery = new SpriteBatchQuery( this );
  892. // Finish if there are no sprites.
  893. if ( mSprites.size() == 0 )
  894. return;
  895. // Add proxies for all the sprites.
  896. for( typeSpriteBatchHash::iterator spriteItr = mSprites.begin(); spriteItr != mSprites.end(); ++spriteItr )
  897. {
  898. // Fetch sprite batch item.
  899. SpriteBatchItem* pSpriteBatchItem = spriteItr->value;
  900. // Create query proxy for sprite.
  901. createQueryProxy( pSpriteBatchItem );
  902. }
  903. }
  904. //------------------------------------------------------------------------------
  905. void SpriteBatch::destroySpriteBatchQuery( void )
  906. {
  907. // Debug Profiling.
  908. PROFILE_SCOPE(SpriteBatch_DestroySpriteBatchQuery);
  909. // Finish if there is no sprite batch query.
  910. if ( mpSpriteBatchQuery == NULL )
  911. return;
  912. // Are there any sprites?
  913. if ( mSprites.size() > 0 )
  914. {
  915. // Yes, so destroy proxies of all the sprites.
  916. for( typeSpriteBatchHash::iterator spriteItr = mSprites.begin(); spriteItr != mSprites.end(); ++spriteItr )
  917. {
  918. // Destroy query proxy for sprite.
  919. destroyQueryProxy( spriteItr->value );
  920. }
  921. }
  922. // Finish if sprite clipping
  923. delete mpSpriteBatchQuery;
  924. mpSpriteBatchQuery = NULL;
  925. }
  926. //------------------------------------------------------------------------------
  927. bool SpriteBatch::destroySprite( const U32 batchId )
  928. {
  929. // Debug Profiling.
  930. PROFILE_SCOPE(SpriteBatch_DestroySprite);
  931. // Find sprite.
  932. typeSpriteBatchHash::iterator spriteItr = mSprites.find( batchId );
  933. // Finish if sprite not found.
  934. if ( spriteItr == mSprites.end() )
  935. return false;
  936. // Find sprite.
  937. SpriteBatchItem* pSpriteBatchItem = spriteItr->value;
  938. // Sanity!
  939. AssertFatal( pSpriteBatchItem != NULL, "SpriteBatch::destroySprite() - Found sprite but it was NULL." );
  940. // Cache sprite.
  941. SpriteBatchItemFactory.cacheObject( pSpriteBatchItem );
  942. // Remove from sprites.
  943. mSprites.erase( batchId );
  944. return true;
  945. }
  946. //------------------------------------------------------------------------------
  947. bool SpriteBatch::checkSpriteSelected( void ) const
  948. {
  949. // Finish if a sprite is selected.
  950. if ( mSelectedSprite != NULL )
  951. return true;
  952. // No, so warn,
  953. Con::warnf( "Cannot perform sprite operation no sprite is selected." );
  954. return false;
  955. }
  956. //------------------------------------------------------------------------------
  957. b2AABB SpriteBatch::calculateLocalAABB( const b2AABB& renderAABB )
  958. {
  959. // Debug Profiling.
  960. PROFILE_SCOPE(SpriteBatch_CalculateLocalAABB);
  961. // Calculate local OOBB.
  962. b2Vec2 localOOBB[4];
  963. CoreMath::mAABBtoOOBB( renderAABB, localOOBB );
  964. CoreMath::mCalculateInverseOOBB( localOOBB, mBatchTransform, localOOBB );
  965. // Calculate local AABB.
  966. b2AABB localAABB;
  967. CoreMath::mOOBBtoAABB( localOOBB, localAABB );
  968. return localAABB;
  969. }
  970. //------------------------------------------------------------------------------
  971. void SpriteBatch::onTamlCustomWrite( TamlCustomNodes& customNodes )
  972. {
  973. // Debug Profiling.
  974. PROFILE_SCOPE(SpriteBatch_TamlCustomWrite);
  975. // Finish if no sprites.
  976. if ( getSpriteCount() == 0 )
  977. return;
  978. // Add sprites node.
  979. TamlCustomNode* pSpritesNode = customNodes.addNode( spritesNodeName );
  980. // Write all sprites.
  981. for( typeSpriteBatchHash::iterator spriteItr = mSprites.begin(); spriteItr != mSprites.end(); ++spriteItr )
  982. {
  983. // Write type with sprite item.
  984. spriteItr->value->onTamlCustomWrite( pSpritesNode );
  985. }
  986. }
  987. //------------------------------------------------------------------------------
  988. void SpriteBatch::onTamlCustomRead( const TamlCustomNodes& customNodes )
  989. {
  990. // Debug Profiling.
  991. PROFILE_SCOPE(SpriteBatch_TamlCustomRead);
  992. // Find sprites custom node.
  993. const TamlCustomNode* pSpritesNode = customNodes.findNode( spritesNodeName );
  994. // Finish if we don't have the node.
  995. if ( pSpritesNode == NULL )
  996. return;
  997. // Fetch children nodes.
  998. const TamlCustomNodeVector& spriteNodes = pSpritesNode->getChildren();
  999. // Iterate sprite item types.
  1000. for( TamlCustomNodeVector::const_iterator spriteItr = spriteNodes.begin(); spriteItr != spriteNodes.end(); ++spriteItr )
  1001. {
  1002. // Fetch sprite node.
  1003. TamlCustomNode* pNode = *spriteItr;
  1004. // Fetch alias name.
  1005. StringTableEntry nodeName = pNode->getNodeName();
  1006. // Is this a known node name?
  1007. if ( nodeName != spritesItemTypeName )
  1008. {
  1009. // No, so warn.
  1010. Con::warnf( "SpriteBatch - Unknown custom type '%s'.", nodeName );
  1011. continue;
  1012. }
  1013. // Create sprite.
  1014. SpriteBatchItem* pSpriteBatchItem = createSprite();
  1015. // Read type with sprite item.
  1016. pSpriteBatchItem->onTamlCustomRead( pNode );
  1017. // Fetch logical position.
  1018. const SpriteBatchItem::LogicalPosition& logicalPosition = pSpriteBatchItem->getLogicalPosition();
  1019. // Did we get a logical position?
  1020. if ( logicalPosition.isValid() )
  1021. {
  1022. // Yes, so insert into sprite positions.
  1023. mSpritePositions.insert( logicalPosition, pSpriteBatchItem );
  1024. }
  1025. // Fetch sprite name.
  1026. StringTableEntry spriteName = pSpriteBatchItem->getName();
  1027. // Did we get a sprite name?
  1028. if ( spriteName != StringTable->EmptyString )
  1029. {
  1030. // Yes, so insert into sprite names if it doesn't already exist.
  1031. if ( mSpriteNames.find( spriteName ) != mSpriteNames.end() )
  1032. mSpriteNames.insert( spriteName, mSelectedSprite );
  1033. }
  1034. }
  1035. }
  1036. //------------------------------------------------------------------------------
  1037. void SpriteBatch::WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
  1038. {
  1039. // Sanity!
  1040. AssertFatal( pClassRep != NULL, "SpriteBatch::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
  1041. AssertFatal( pParentElement != NULL, "SpriteBatch::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
  1042. char buffer[1024];
  1043. // Create sprite batch node element.
  1044. TiXmlElement* pBatchNodeElement = new TiXmlElement( "xs:element" );
  1045. dSprintf( buffer, sizeof(buffer), "%s.%s", pClassRep->getClassName(), spritesNodeName );
  1046. pBatchNodeElement->SetAttribute( "name", buffer );
  1047. pBatchNodeElement->SetAttribute( "minOccurs", 0 );
  1048. pBatchNodeElement->SetAttribute( "maxOccurs", 1 );
  1049. pParentElement->LinkEndChild( pBatchNodeElement );
  1050. // Create complex type.
  1051. TiXmlElement* pBatchNodeComplexTypeElement = new TiXmlElement( "xs:complexType" );
  1052. pBatchNodeElement->LinkEndChild( pBatchNodeComplexTypeElement );
  1053. // Create choice element.
  1054. TiXmlElement* pBatchNodeChoiceElement = new TiXmlElement( "xs:choice" );
  1055. pBatchNodeChoiceElement->SetAttribute( "minOccurs", 0 );
  1056. pBatchNodeChoiceElement->SetAttribute( "maxOccurs", "unbounded" );
  1057. pBatchNodeComplexTypeElement->LinkEndChild( pBatchNodeChoiceElement );
  1058. // Write sprite batch item.
  1059. SpriteBatchItem::WriteCustomTamlSchema( pClassRep, pBatchNodeChoiceElement );
  1060. }