2
0

CompositeSprite.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  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 _COMPOSITE_SPRITE_H_
  23. #include "2d/sceneobject/CompositeSprite.h"
  24. #endif
  25. #ifndef _SPRITE_BATCH_QUERY_H_
  26. #include "2d/core/SpriteBatchQuery.h"
  27. #endif
  28. #ifndef _RENDER_PROXY_H_
  29. #include "2d/core/RenderProxy.h"
  30. #endif
  31. // Script bindings.
  32. #include "2d/sceneobject/CompositeSprite_ScriptBinding.h"
  33. //------------------------------------------------------------------------------
  34. static EnumTable::Enums batchLayoutTypeLookup[] =
  35. {
  36. { CompositeSprite::NO_LAYOUT, "off" },
  37. { CompositeSprite::RECTILINEAR_LAYOUT, "rect" },
  38. { CompositeSprite::ISOMETRIC_LAYOUT, "iso" },
  39. { CompositeSprite::CUSTOM_LAYOUT, "custom" },
  40. };
  41. EnumTable batchLayoutTypeTable(sizeof(batchLayoutTypeLookup) / sizeof(EnumTable::Enums), &batchLayoutTypeLookup[0]);
  42. //-----------------------------------------------------------------------------
  43. CompositeSprite::BatchLayoutType CompositeSprite::getBatchLayoutTypeEnum(const char* label)
  44. {
  45. // Search for Mnemonic.
  46. for (U32 i = 0; i < (sizeof(batchLayoutTypeLookup) / sizeof(EnumTable::Enums)); i++)
  47. {
  48. if( dStricmp(batchLayoutTypeLookup[i].label, label) == 0)
  49. return (BatchLayoutType)batchLayoutTypeLookup[i].index;
  50. }
  51. // Warn.
  52. Con::warnf("CompositeSprite::getBatchLayoutTypeEnum() - Invalid batch layout type of '%s'", label );
  53. return CompositeSprite::INVALID_LAYOUT;
  54. }
  55. //-----------------------------------------------------------------------------
  56. const char* CompositeSprite::getBatchLayoutTypeDescription(const CompositeSprite::BatchLayoutType batchLayoutType )
  57. {
  58. // Search for Mnemonic.
  59. for (U32 i = 0; i < (sizeof(batchLayoutTypeLookup) / sizeof(EnumTable::Enums)); i++)
  60. {
  61. if( batchLayoutTypeLookup[i].index == batchLayoutType )
  62. return batchLayoutTypeLookup[i].label;
  63. }
  64. // Warn.
  65. Con::warnf( "CompositeSprite::getBatchLayoutTypeDescription() - Invalid batch layout type.");
  66. return StringTable->EmptyString;
  67. }
  68. //------------------------------------------------------------------------------
  69. CompositeSprite::CompositeSprite() :
  70. mBatchLayoutType( NO_LAYOUT )
  71. {
  72. // Set as auto-sizing.
  73. mAutoSizing = true;
  74. }
  75. //------------------------------------------------------------------------------
  76. CompositeSprite::~CompositeSprite()
  77. {
  78. }
  79. //------------------------------------------------------------------------------
  80. void CompositeSprite::initPersistFields()
  81. {
  82. // Call parent.
  83. Parent::initPersistFields();
  84. /// Defaults.
  85. addProtectedField( "DefaultSpriteStride", TypeVector2, Offset(mDefaultSpriteStride, CompositeSprite), &defaultProtectedSetFn, &defaultProtectedGetFn, &writeDefaultSpriteStride, "");
  86. addProtectedField( "DefaultSpriteSize", TypeVector2, Offset(mDefaultSpriteSize, CompositeSprite), &defaultProtectedSetFn, &defaultProtectedGetFn, &writeDefaultSpriteSize, "");
  87. addProtectedField( "DefaultSpriteAngle", TypeF32, Offset(mDefaultSpriteSize, CompositeSprite), &setDefaultSpriteAngle, &getDefaultSpriteAngle, &writeDefaultSpriteAngle, "");
  88. addProtectedField( "BatchLayout", TypeEnum, Offset(mBatchLayoutType, CompositeSprite), &setBatchLayout, &defaultProtectedGetFn, &writeBatchLayout, 1, &batchLayoutTypeTable, "");
  89. addProtectedField( "BatchCulling", TypeBool, Offset(mBatchCulling, CompositeSprite), &setBatchCulling, &defaultProtectedGetFn, &writeBatchCulling, "");
  90. addField( "BatchIsolated", TypeBool, Offset(mBatchIsolated, CompositeSprite), &writeBatchIsolated, "");
  91. addField( "BatchSortMode", TypeEnum, Offset(mBatchSortMode, CompositeSprite), &writeBatchSortMode, 1, &SceneRenderQueue::renderSortTable, "");
  92. }
  93. //-----------------------------------------------------------------------------
  94. bool CompositeSprite::onAdd()
  95. {
  96. // Call parent.
  97. if ( !Parent::onAdd() )
  98. return false;
  99. // Call sprite batch.
  100. return SpriteBatch::onAdd();
  101. }
  102. //-----------------------------------------------------------------------------
  103. void CompositeSprite::onRemove()
  104. {
  105. // Call sprite batch.
  106. SpriteBatch::onRemove();
  107. // Call parent.
  108. Parent::onRemove();
  109. }
  110. //-----------------------------------------------------------------------------
  111. void CompositeSprite::preIntegrate( const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats )
  112. {
  113. // Are the spatials dirty?
  114. if ( getSpatialDirty() )
  115. {
  116. // Yes, so update the world transform.
  117. setBatchTransform( getRenderTransform() );
  118. }
  119. // Are the render extents dirty?
  120. if ( getLocalExtentsDirty() )
  121. {
  122. // Yes, so set size as local extents.
  123. setSize( getLocalExtents() );
  124. }
  125. // Call parent.
  126. Parent::preIntegrate( totalTime, elapsedTime, pDebugStats );
  127. }
  128. //-----------------------------------------------------------------------------
  129. void CompositeSprite::integrateObject( const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats )
  130. {
  131. // Call Parent.
  132. Parent::integrateObject( totalTime, elapsedTime, pDebugStats );
  133. integrateSprites(totalTime, elapsedTime, pDebugStats);
  134. // Finish if the spatials are NOT dirty.
  135. if ( !getSpatialDirty() )
  136. return;
  137. // Update the batch world transform.
  138. setBatchTransform( getRenderTransform() );
  139. }
  140. //-----------------------------------------------------------------------------
  141. void CompositeSprite::interpolateObject( const F32 timeDelta )
  142. {
  143. // Call parent.
  144. Parent::interpolateObject( timeDelta );
  145. // Finish if the spatials are NOT dirty.
  146. if ( !getSpatialDirty() )
  147. return;
  148. // Update the batch world transform.
  149. setBatchTransform( getRenderTransform() );
  150. }
  151. //-----------------------------------------------------------------------------
  152. void CompositeSprite::scenePrepareRender( const SceneRenderState* pSceneRenderState, SceneRenderQueue* pSceneRenderQueue )
  153. {
  154. // Prepare render.
  155. SpriteBatch::prepareRender( this, pSceneRenderState, pSceneRenderQueue );
  156. }
  157. //-----------------------------------------------------------------------------
  158. void CompositeSprite::sceneRender( const SceneRenderState* pSceneRenderState, const SceneRenderRequest* pSceneRenderRequest, BatchRender* pBatchRenderer )
  159. {
  160. // Render.
  161. SpriteBatch::render( pSceneRenderState, pSceneRenderRequest, pBatchRenderer );
  162. }
  163. //------------------------------------------------------------------------------
  164. void CompositeSprite::copyTo(SimObject* object)
  165. {
  166. // Call to parent.
  167. Parent::copyTo(object);
  168. // Fetch object.
  169. CompositeSprite* pCompositeSprite = dynamic_cast<CompositeSprite*>(object);
  170. // Sanity!
  171. AssertFatal(pCompositeSprite != NULL, "CompositeSprite::copyTo() - Object is not the correct type.");
  172. // Copy batch layout.
  173. pCompositeSprite->setBatchLayout( getBatchLayout() );
  174. // Call sprite batch.
  175. SpriteBatch::copyTo( dynamic_cast<SpriteBatch*>(object) );
  176. }
  177. //------------------------------------------------------------------------------
  178. void CompositeSprite::setBatchLayout( const BatchLayoutType& batchLayoutType )
  179. {
  180. // Finish if no change.
  181. if ( mBatchLayoutType == batchLayoutType )
  182. return;
  183. // Do we already have some sprites?
  184. if ( getSpriteCount() > 0 )
  185. {
  186. // Yes, so warn.
  187. Con::warnf( "CompositeSprite::setBatchLayout() - Changing the batch layout with existing sprites is not allowed. Clear the sprites first." );
  188. return;
  189. }
  190. // Set layout type.
  191. mBatchLayoutType = batchLayoutType;
  192. }
  193. //------------------------------------------------------------------------------
  194. SpriteBatchItem* CompositeSprite::createSprite( const SpriteBatchItem::LogicalPosition& logicalPosition )
  195. {
  196. // Handle layout type appropriately.
  197. switch( mBatchLayoutType )
  198. {
  199. // No layout.
  200. case NO_LAYOUT:
  201. return SpriteBatch::createSprite( logicalPosition );
  202. // Rectilinear layout.
  203. case RECTILINEAR_LAYOUT:
  204. return createSpriteRectilinearLayout( logicalPosition );
  205. // Isometric layout.
  206. case ISOMETRIC_LAYOUT:
  207. return createSpriteIsometricLayout( logicalPosition );
  208. case CUSTOM_LAYOUT:
  209. return createCustomLayout( logicalPosition );
  210. default:
  211. // Warn.
  212. Con::warnf( "CompositeSprite::createSprite() - Unknown layout type encountered." );
  213. return SpriteBatch::createSprite( logicalPosition );
  214. }
  215. }
  216. //-----------------------------------------------------------------------------
  217. SpriteBatchItem* CompositeSprite::createSpriteRectilinearLayout( const SpriteBatchItem::LogicalPosition& logicalPosition )
  218. {
  219. // Do we have a valid logical position?
  220. if ( logicalPosition.getArgCount() != 2 )
  221. {
  222. // No, so warn.
  223. Con::warnf( "Invalid logical position specified for composite sprite." );
  224. return NULL;
  225. }
  226. // Does the sprite position already exist?
  227. if ( findSpritePosition( logicalPosition ) != NULL )
  228. {
  229. // Yes, so warn.
  230. Con::warnf( "Cannot add sprite at logical position '%s' as one already exists.", logicalPosition.getString() );
  231. return NULL;
  232. }
  233. // Create the sprite.
  234. SpriteBatchItem* pSpriteBatchItem = SpriteBatch::createSprite();
  235. // Set sprite logical position.
  236. pSpriteBatchItem->setLogicalPosition( logicalPosition );
  237. // Set the sprite default position.
  238. pSpriteBatchItem->setLocalPosition( logicalPosition.getAsVector2().mult( getDefaultSpriteStride() ) );
  239. // Set the sprite default size and angle.
  240. pSpriteBatchItem->setSize( SpriteBatch::getDefaultSpriteSize() );
  241. pSpriteBatchItem->setLocalAngle( SpriteBatch::getDefaultSpriteAngle() );
  242. return pSpriteBatchItem;
  243. }
  244. //-----------------------------------------------------------------------------
  245. SpriteBatchItem* CompositeSprite::createSpriteIsometricLayout( const SpriteBatchItem::LogicalPosition& logicalPosition )
  246. {
  247. // Do we have a valid logical position?
  248. if ( logicalPosition.getArgCount() != 2 )
  249. {
  250. // No, so warn.
  251. Con::warnf( "Invalid logical position specified for composite rectilinear sprite." );
  252. return NULL;
  253. }
  254. // Does the sprite position already exist?
  255. if ( findSpritePosition( logicalPosition ) != NULL )
  256. {
  257. // Yes, so warn.
  258. Con::warnf( "Cannot add sprite at logical position '%s' as one already exists.", logicalPosition.getString() );
  259. return NULL;
  260. }
  261. // Create the sprite.
  262. SpriteBatchItem* pSpriteBatchItem = SpriteBatch::createSprite();
  263. // Set sprite logical position.
  264. pSpriteBatchItem->setLogicalPosition( logicalPosition );
  265. // Fetch sprite stride.
  266. const Vector2 spriteStride = getDefaultSpriteStride();
  267. // Fetch logical coordinates.
  268. Vector2 position = logicalPosition.getAsVector2();
  269. // Calculate position.
  270. position.Set( (position.x * spriteStride.x) + (position.y * spriteStride.x), (position.x * spriteStride.y) + (position.y * -spriteStride.y) );
  271. // Set the sprite default position.
  272. pSpriteBatchItem->setLocalPosition( position );
  273. // Set the sprite default size and angle.
  274. pSpriteBatchItem->setSize( getDefaultSpriteSize() );
  275. pSpriteBatchItem->setLocalAngle( SpriteBatch::getDefaultSpriteAngle() );
  276. return pSpriteBatchItem;
  277. }
  278. //-----------------------------------------------------------------------------
  279. SpriteBatchItem* CompositeSprite::createCustomLayout( const SpriteBatchItem::LogicalPosition& logicalPosition )
  280. {
  281. // Do we have a valid logical position?
  282. if ( logicalPosition.isValid() )
  283. {
  284. // Does the sprite already exist?
  285. if ( findSpritePosition( logicalPosition ) != NULL )
  286. {
  287. // Yes, so warn.
  288. Con::warnf( "Cannot add sprite at logical position '%s' as one already exists.", logicalPosition.getString() );
  289. return NULL;
  290. }
  291. }
  292. // Create the sprite.
  293. SpriteBatchItem* pSpriteBatchItem = SpriteBatch::createSprite();
  294. // Set sprite logical position if it's valid.
  295. if ( logicalPosition.isValid() )
  296. pSpriteBatchItem->setLogicalPosition( logicalPosition );
  297. // Retrieve the local position from the custom layout callback.
  298. const char* pLocalPosition = Con::executef(this, 2, "onCustomLayout", logicalPosition.getString() );
  299. // Was a local position returned.
  300. if ( pLocalPosition != NULL && dStrlen(pLocalPosition) != 0 )
  301. {
  302. // Fetch the local position.
  303. Vector2 position(0.0f, 0.0f);
  304. Con::setData( TypeVector2, &position, 0, 1, &pLocalPosition );
  305. // Set the sprite default position.
  306. pSpriteBatchItem->setLocalPosition( position );
  307. }
  308. // Set the sprite default size and angle.
  309. pSpriteBatchItem->setSize( getDefaultSpriteSize() );
  310. pSpriteBatchItem->setLocalAngle( SpriteBatch::getDefaultSpriteAngle() );
  311. return pSpriteBatchItem;
  312. }
  313. //-----------------------------------------------------------------------------
  314. void CompositeSprite::onTamlCustomWrite( TamlCustomNodes& customNodes )
  315. {
  316. // Call parent.
  317. Parent::onTamlCustomWrite( customNodes );
  318. // Write node with sprite batch.
  319. SpriteBatch::onTamlCustomWrite( customNodes );
  320. }
  321. //-----------------------------------------------------------------------------
  322. void CompositeSprite::onTamlCustomRead( const TamlCustomNodes& customNodes )
  323. {
  324. // Call parent.
  325. Parent::onTamlCustomRead( customNodes );
  326. // Read node with sprite batch.
  327. SpriteBatch::onTamlCustomRead( customNodes );
  328. }
  329. //-----------------------------------------------------------------------------
  330. static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
  331. {
  332. // Sanity!
  333. AssertFatal( pClassRep != NULL, "CompositeSprite::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
  334. AssertFatal( pParentElement != NULL, "CompositeSprite::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
  335. // Write sprite batch.
  336. SpriteBatch::WriteCustomTamlSchema( pClassRep, pParentElement );
  337. }
  338. //-----------------------------------------------------------------------------
  339. IMPLEMENT_CONOBJECT_SCHEMA(CompositeSprite, WriteCustomTamlSchema);