forestCell.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "forest/forestCell.h"
  24. #include "forest/forest.h"
  25. #include "forest/forestCellBatch.h"
  26. #include "forest/forestCollision.h"
  27. #include "T3D/physics/physicsPlugin.h"
  28. #include "T3D/physics/physicsBody.h"
  29. #include "T3D/physics/physicsCollision.h"
  30. #include "collision/concretePolyList.h"
  31. #include "gfx/gfxDrawUtil.h"
  32. #include "math/util/frustum.h"
  33. ForestCell::ForestCell( const RectF &rect ) :
  34. mRect( rect ),
  35. mBounds( Box3F::Invalid ),
  36. mLargestItem( ForestItem::Invalid ),
  37. mIsDirty( false ),
  38. mIsInteriorOnly( false )
  39. {
  40. dMemset( mSubCells, 0, sizeof( mSubCells ) );
  41. dMemset( mPhysicsRep, 0, sizeof( mPhysicsRep ) );
  42. }
  43. ForestCell::~ForestCell()
  44. {
  45. mItems.clear();
  46. for ( U32 i=0; i < 4; i++ )
  47. SAFE_DELETE( mSubCells[i] );
  48. freeBatches();
  49. SAFE_DELETE( mPhysicsRep[0] );
  50. SAFE_DELETE( mPhysicsRep[1] );
  51. }
  52. void ForestCell::freeBatches()
  53. {
  54. for ( U32 i=0; i < mBatches.size(); i++ )
  55. SAFE_DELETE( mBatches[i] );
  56. mBatches.clear();
  57. }
  58. void ForestCell::buildBatches()
  59. {
  60. // Gather items for batches.
  61. Vector<ForestItem> items;
  62. getItems( &items );
  63. // Ask the item to batch itself.
  64. Vector<ForestItem>::const_iterator item = items.begin();
  65. bool batched = false;
  66. for ( ; item != items.end(); item++ )
  67. {
  68. // Loop thru the batches till someone
  69. // takes this guy off our hands.
  70. batched = false;
  71. for ( S32 i=0; i < mBatches.size(); i++ )
  72. {
  73. if ( mBatches[i]->add( *item ) )
  74. {
  75. batched = true;
  76. break;
  77. }
  78. }
  79. if ( batched )
  80. continue;
  81. // Gotta create a new batch.
  82. ForestCellBatch *batch = item->getData()->allocateBatch();
  83. if ( batch )
  84. {
  85. batch->add( *item );
  86. mBatches.push_back( batch );
  87. }
  88. }
  89. }
  90. S32 ForestCell::renderBatches( SceneRenderState *state, Frustum *culler )
  91. {
  92. PROFILE_SCOPE( ForestCell_renderBatches );
  93. if ( !hasBatches() )
  94. return 0;
  95. S32 renderedItems = 0;
  96. for ( S32 i=0; i < mBatches.size(); i++ )
  97. {
  98. // Is this batch entirely culled?
  99. if ( culler && culler->isCulled( mBatches[i]->getWorldBox() ) )
  100. continue;
  101. mBatches[i]->render( state );
  102. renderedItems += mBatches[i]->getItemCount();
  103. }
  104. return renderedItems;
  105. }
  106. S32 ForestCell::render( TSRenderState *rdata, const Frustum *culler )
  107. {
  108. PROFILE_SCOPE( ForestCell_render );
  109. AssertFatal( isLeaf(), "ForestCell::render() - This shouldn't be called on non-leaf cells!" );
  110. U32 itemsRendered = 0;
  111. // TODO: Items are generated in order of type,
  112. // so we can maybe save some overhead by preparing
  113. // the item for rendering once.
  114. Vector<ForestItem>::iterator item = mItems.begin();
  115. for ( ; item != mItems.end(); item++ )
  116. {
  117. // Do we need to cull individual items?
  118. if ( culler && culler->isCulled( item->getWorldBox() ) )
  119. continue;
  120. if ( item->getData()->render( rdata, *item ) )
  121. ++itemsRendered;
  122. }
  123. return itemsRendered;
  124. }
  125. void ForestCell::_updateBounds()
  126. {
  127. mIsDirty = false;
  128. mBounds = Box3F::Invalid;
  129. mLargestItem = ForestItem::Invalid;
  130. F32 radius;
  131. if ( isBranch() )
  132. {
  133. for ( U32 i=0; i < 4; i++ )
  134. {
  135. mBounds.intersect( mSubCells[i]->getBounds() );
  136. radius = mSubCells[i]->mLargestItem.getRadius();
  137. if ( radius > mLargestItem.getRadius() )
  138. mLargestItem = mSubCells[i]->mLargestItem;
  139. }
  140. return;
  141. }
  142. // Loop thru all the items in this cell.
  143. Vector<ForestItem>::const_iterator item = mItems.begin();
  144. for ( ; item != mItems.end(); item++ )
  145. {
  146. mBounds.intersect( (*item).getWorldBox() );
  147. radius = (*item).getRadius();
  148. if ( radius > mLargestItem.getRadius() )
  149. mLargestItem = (*item);
  150. }
  151. }
  152. void ForestCell::_updateZoning( const SceneZoneSpaceManager *zoneManager )
  153. {
  154. PROFILE_SCOPE( ForestCell_UpdateZoning );
  155. mZoneOverlap.setSize( zoneManager->getNumZones() );
  156. mZoneOverlap.clear();
  157. mIsInteriorOnly = true;
  158. if ( isLeaf() )
  159. {
  160. // Skip empty cells... they don't have valid bounds.
  161. if ( mItems.empty() )
  162. return;
  163. Vector<U32> zones;
  164. zoneManager->findZones( getBounds(), zones );
  165. for ( U32 i=0; i < zones.size(); i++ )
  166. {
  167. // Set overlap bit for zone except it's the outdoor zone.
  168. if( zones[ i ] != SceneZoneSpaceManager::RootZoneId )
  169. mZoneOverlap.set( zones[i] );
  170. else
  171. mIsInteriorOnly = false;
  172. }
  173. return;
  174. }
  175. for ( U32 i = 0; i < 4; i++ )
  176. {
  177. ForestCell *cell = mSubCells[i];
  178. cell->_updateZoning( zoneManager );
  179. mZoneOverlap.combineOR( cell->getZoneOverlap() );
  180. mIsInteriorOnly &= cell->mIsInteriorOnly;
  181. }
  182. }
  183. bool ForestCell::findIndexByKey( ForestItemKey key, U32 *outIndex ) const
  184. {
  185. // Do a simple binary search.
  186. U32 i = 0,
  187. lo = 0,
  188. hi = mItems.size();
  189. const ForestItem *items = mItems.address();
  190. while ( lo < hi )
  191. {
  192. i = (lo + hi) / 2;
  193. if ( key < items[i].getKey() )
  194. hi = i;
  195. else if ( key > items[i].getKey() )
  196. lo = i + 1;
  197. else
  198. {
  199. *outIndex = i;
  200. return true;
  201. }
  202. }
  203. *outIndex = lo;
  204. return false;
  205. }
  206. const ForestItem& ForestCell::insertItem( ForestItemKey key,
  207. ForestItemData *data,
  208. const MatrixF &xfm,
  209. F32 scale )
  210. {
  211. AssertFatal( key != 0, "ForestCell::insertItem() - Got null key!" );
  212. AssertFatal( data != NULL, "ForestCell::insertItem() - Got null datablock!" );
  213. // Make sure we update the bounds later.
  214. mIsDirty = true;
  215. // PhysicsBody is now invalid and must be rebuilt later.
  216. SAFE_DELETE( mPhysicsRep[0] );
  217. SAFE_DELETE( mPhysicsRep[1] );
  218. // Destroy batches so we recreate it on
  219. // the next next render.
  220. freeBatches();
  221. // Ok... do we need to split this cell?
  222. if ( isLeaf() && mItems.size() > MaxItems )
  223. {
  224. // Add the children.
  225. for ( U32 i=0; i < 4; i++ )
  226. mSubCells[i] = new ForestCell( _makeChildRect( i ) );
  227. // Now push all our current children down.
  228. Vector<ForestItem>::iterator item = mItems.begin();
  229. for ( ; item != mItems.end(); item++ )
  230. {
  231. U32 index = _getSubCell( item->getPosition().x, item->getPosition().y );
  232. mSubCells[index]->insertItem( item->getKey(),
  233. item->getData(),
  234. item->getTransform(),
  235. item->getScale() );
  236. }
  237. // Clean up.
  238. mItems.clear();
  239. mItems.compact();
  240. }
  241. // Do we have children?
  242. if ( isBranch() )
  243. {
  244. // Ok... kick this item down then.
  245. U32 index = _getSubCell( xfm.getPosition().x, xfm.getPosition().y );
  246. const ForestItem &result = mSubCells[index]->insertItem( key, data, xfm, scale );
  247. AssertFatal( index == _getSubCell( result.getPosition().x, result.getPosition().y ), "ForestCell::insertItem() - binning is hosed." );
  248. return result;
  249. }
  250. // Do the datablock preload here to insure it happens
  251. // before an item is used in the scene.
  252. data->preload();
  253. // First see if we can find it. This is nifty so
  254. // I'll explain it a bit more.
  255. //
  256. // The find function does a binary search thru the
  257. // sorted item list.
  258. //
  259. // If found the index is the position of the item.
  260. //
  261. // If not found the index is the correct insertion
  262. // position for adding the new item.
  263. //
  264. // So not only do we have a fast find which is worst
  265. // case O(log n)... but we also have the proper insert
  266. // position to maintain a sorted item list.
  267. //
  268. U32 index;
  269. bool found = findIndexByKey( key, &index );
  270. // If we didn't find one then insert it.
  271. if ( !found )
  272. mItems.insert( index );
  273. // Update the item settings.
  274. ForestItem &item = mItems[ index ];
  275. item.setData( data );
  276. item.setTransform( xfm, scale );
  277. if ( !found )
  278. item.setKey( key );
  279. return item;
  280. }
  281. bool ForestCell::removeItem( ForestItemKey key, const Point3F &keyPos, bool deleteIfEmpty )
  282. {
  283. PROFILE_SCOPE( ForestCell_removeItem );
  284. AssertFatal( key != 0, "ForestCell::removeItem() - Got null key!" );
  285. // If this cell has no items then check the children.
  286. if ( mItems.empty() )
  287. {
  288. // Let the child deal with it.
  289. U32 index = _getSubCell( keyPos.x, keyPos.y );
  290. if ( !mSubCells[index]->removeItem( key, keyPos, deleteIfEmpty ) )
  291. {
  292. // For debugging lets make sure we didn't pick the wrong subCell...
  293. return false;
  294. }
  295. // If requested by the caller delete our empty subcells.
  296. // Note that by deleting SubCell[0] we have become a leaf with no items
  297. // and will return true to our parent's isEmpty test.
  298. if ( deleteIfEmpty &&
  299. mSubCells[0]->isEmpty() &&
  300. mSubCells[1]->isEmpty() &&
  301. mSubCells[2]->isEmpty() &&
  302. mSubCells[3]->isEmpty() )
  303. {
  304. SAFE_DELETE( mSubCells[0] );
  305. SAFE_DELETE( mSubCells[1] );
  306. SAFE_DELETE( mSubCells[2] );
  307. SAFE_DELETE( mSubCells[3] );
  308. }
  309. }
  310. else
  311. {
  312. // First see if we can find it.
  313. U32 index;
  314. if ( !findIndexByKey( key, &index ) )
  315. return false;
  316. // Erase it.
  317. mItems.erase( index );
  318. }
  319. // Do a full bounds update on the next request.
  320. mIsDirty = true;
  321. // PhysicsBody is now invalid and must be rebuilt later.
  322. SAFE_DELETE( mPhysicsRep[0] );
  323. SAFE_DELETE( mPhysicsRep[1] );
  324. // Destroy batches so we recreate it on
  325. // the next next render.
  326. freeBatches();
  327. return true;
  328. }
  329. void ForestCell::getItems( Vector<ForestItem> *outItems ) const
  330. {
  331. Vector<const ForestCell*> stack;
  332. stack.push_back( this );
  333. // Now loop till we run out of cells.
  334. while ( !stack.empty() )
  335. {
  336. // Pop off the next cell.
  337. const ForestCell *cell = stack.last();
  338. stack.pop_back();
  339. // Recurse thru non-leaf cells.
  340. if ( !cell->isLeaf() )
  341. {
  342. stack.merge( cell->mSubCells, 4 );
  343. continue;
  344. }
  345. // Get the items.
  346. outItems->merge( cell->getItems() );
  347. }
  348. }
  349. void ForestCell::buildPhysicsRep( Forest *forest )
  350. {
  351. AssertFatal( isLeaf(), "ForestCell::buildPhysicsRep() - This shouldn't be called on non-leaf cells!" );
  352. bool isServer = forest->isServerObject();
  353. // Already has a PhysicsBody, if it needed to be rebuilt it would
  354. // already be null.
  355. if ( mPhysicsRep[ isServer ] )
  356. return;
  357. if ( !PHYSICSMGR )
  358. return;
  359. PhysicsCollision *colShape = NULL;
  360. // If we can steal the collision shape from the server-side cell
  361. // then do so as it saves us alot of cpu time and memory.
  362. if ( mPhysicsRep[ 1 ] )
  363. {
  364. colShape = mPhysicsRep[ 1 ]->getColShape();
  365. }
  366. else
  367. {
  368. // We must pass a sphere to buildPolyList but it is not used.
  369. const static SphereF dummySphere( Point3F::Zero, 0 );
  370. // Step thru them and build collision data.
  371. ForestItemVector::iterator itemItr = mItems.begin();
  372. ConcretePolyList polyList;
  373. for ( ; itemItr != mItems.end(); itemItr++ )
  374. {
  375. const ForestItem &item = *itemItr;
  376. const ForestItemData *itemData = item.getData();
  377. // If not collidable don't need to build anything.
  378. if ( !itemData->mCollidable )
  379. continue;
  380. // TODO: When we add breakable tree support this is where
  381. // we would need to store their collision data seperately.
  382. item.buildPolyList( &polyList, item.getWorldBox(), dummySphere );
  383. // TODO: Need to support multiple collision shapes
  384. // for really big forests at some point in the future.
  385. }
  386. if ( !polyList.isEmpty() )
  387. {
  388. colShape = PHYSICSMGR->createCollision();
  389. if ( !colShape->addTriangleMesh( polyList.mVertexList.address(),
  390. polyList.mVertexList.size(),
  391. polyList.mIndexList.address(),
  392. polyList.mIndexList.size() / 3,
  393. MatrixF::Identity ) )
  394. {
  395. SAFE_DELETE( colShape );
  396. }
  397. }
  398. }
  399. // We might not have any trees.
  400. if ( !colShape )
  401. return;
  402. PhysicsWorld *world = PHYSICSMGR->getWorld( isServer ? "server" : "client" );
  403. mPhysicsRep[ isServer ] = PHYSICSMGR->createBody();
  404. mPhysicsRep[ isServer ]->init( colShape, 0, 0, forest, world );
  405. }
  406. void ForestCell::clearPhysicsRep( Forest *forest )
  407. {
  408. bool isServer = forest->isServerObject();
  409. SAFE_DELETE( mPhysicsRep[ isServer ] );
  410. }