terrCell.cpp 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210
  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. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  23. // Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
  24. // Copyright (C) 2015 Faust Logic, Inc.
  25. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  26. #include "platform/platform.h"
  27. #include "terrain/terrCell.h"
  28. #include "math/util/frustum.h"
  29. #include "terrain/terrData.h"
  30. #include "terrain/terrCellMaterial.h"
  31. #include "scene/sceneRenderState.h"
  32. #include "lighting/lightManager.h"
  33. #include "gfx/gfxDrawUtil.h"
  34. GFXImplementVertexFormat( TerrVertex )
  35. {
  36. addElement( "POSITION", GFXDeclType_Float3 );
  37. addElement( "NORMAL", GFXDeclType_Float3 );
  38. addElement( "TangentZ", GFXDeclType_Float, 0 );
  39. addElement( "Empty", GFXDeclType_Float, 1 );
  40. };
  41. const U32 TerrCell::smMinCellSize = 64;
  42. const U32 TerrCell::smVBStride = TerrCell::smMinCellSize + 1; // 129
  43. const U32 TerrCell::smVBSize = ( TerrCell::smVBStride * TerrCell::smVBStride ) +
  44. ( TerrCell::smVBStride * 4 ); // 17,157
  45. const U32 TerrCell::smPBSize = ( TerrCell::smMinCellSize * TerrCell::smMinCellSize * 6 ) +
  46. ( TerrCell::smMinCellSize * 4 * 6 ); // 101,376
  47. const U32 TerrCell::smTriCount = TerrCell::smPBSize / 3; // 33,792
  48. TerrCell::TerrCell()
  49. : mTriCount( 0 ),
  50. mHasEmpty( false ),
  51. mMaterial( NULL ),
  52. mMaterials( 0 ),
  53. mIsInteriorOnly( false )
  54. {
  55. dMemset( mChildren, 0, sizeof( mChildren ) );
  56. zode_vertexBuffer = 0;
  57. }
  58. TerrCell::~TerrCell()
  59. {
  60. SAFE_DELETE( mMaterial );
  61. for ( U32 i=0; i < 4; i++ )
  62. SAFE_DELETE( mChildren[i] );
  63. deleteZodiacVertexBuffer();
  64. }
  65. void TerrCell::createPrimBuffer( GFXPrimitiveBufferHandle *primBuffer )
  66. {
  67. PROFILE_SCOPE( TerrCell_AllocPrimBuffer );
  68. primBuffer->set( GFX, smPBSize, 1, GFXBufferTypeStatic, "TerrCell" );
  69. // We don't use the primitive for normal clipmap
  70. // rendering, but it is used for the shadow pass.
  71. GFXPrimitive *prim = primBuffer->getPointer()->mPrimitiveArray;
  72. prim->type = GFXTriangleList;
  73. prim->numPrimitives = smTriCount;
  74. prim->numVertices = smVBSize;
  75. //
  76. // The vertex pattern for the terrain is as
  77. // follows...
  78. //
  79. // 0----1----2.....n
  80. // |\ | /|
  81. // | \ | / |
  82. // | \ | / |
  83. // | \|/ |
  84. // n----n----n
  85. // | /|\ |
  86. // | / | \ |
  87. // | / | \ |
  88. // |/ | \|
  89. // n----n----n
  90. //
  91. // Lock and fill it up!
  92. U16 *idxBuff;
  93. primBuffer->lock( &idxBuff );
  94. U32 counter = 0;
  95. U32 maxIndex = 0;
  96. for ( U32 y = 0; y < smMinCellSize; y++ )
  97. {
  98. const U32 yTess = y % 2;
  99. for ( U32 x = 0; x < smMinCellSize; x++ )
  100. {
  101. U32 index = ( y * smVBStride ) + x;
  102. const U32 xTess = x % 2;
  103. if ( ( xTess == 0 && yTess == 0 ) ||
  104. ( xTess != 0 && yTess != 0 ) )
  105. {
  106. idxBuff[0] = index + 0;
  107. idxBuff[1] = index + smVBStride;
  108. idxBuff[2] = index + smVBStride + 1;
  109. idxBuff[3] = index + 0;
  110. idxBuff[4] = index + smVBStride + 1;
  111. idxBuff[5] = index + 1;
  112. }
  113. else
  114. {
  115. idxBuff[0] = index + 1;
  116. idxBuff[1] = index;
  117. idxBuff[2] = index + smVBStride;
  118. idxBuff[3] = index + 1;
  119. idxBuff[4] = index + smVBStride;
  120. idxBuff[5] = index + smVBStride + 1;
  121. }
  122. idxBuff += 6;
  123. maxIndex = index + 1 + smVBStride;
  124. counter += 6;
  125. }
  126. }
  127. // Now add indices for the 'skirts'.
  128. // These could probably be reduced to a loop.
  129. // Temporaries that hold triangle indices.
  130. // Top/Bottom - 0,1
  131. U32 t0, t1, b0, b1;
  132. // Top edge skirt...
  133. // Index to the first vert of the top row.
  134. U32 startIndex = 0;
  135. // Index to the first vert of the skirt under the top row.
  136. U32 skirtStartIdx = smVBStride * smVBStride;
  137. // Step to go one vert to the right.
  138. U32 step = 1;
  139. for ( U32 i = 0; i < smMinCellSize; i++ )
  140. {
  141. t0 = startIndex + i * step;
  142. t1 = t0 + step;
  143. b0 = skirtStartIdx + i;
  144. b1 = skirtStartIdx + i + 1;
  145. idxBuff[0] = b0;
  146. idxBuff[1] = t0;
  147. idxBuff[2] = t1;
  148. idxBuff[3] = b1;
  149. idxBuff[4] = b0;
  150. idxBuff[5] = t1;
  151. idxBuff += 6;
  152. maxIndex = b1;
  153. counter += 6;
  154. }
  155. // Bottom edge skirt...
  156. // Index to the first vert of the bottom row.
  157. startIndex = smVBStride * smVBStride - smVBStride;
  158. // Index to the first vert of the skirt under the bottom row.
  159. skirtStartIdx = startIndex + smVBStride * 2;
  160. // Step to go one vert to the right.
  161. step = 1;
  162. for ( U32 i = 0; i < smMinCellSize; i++ )
  163. {
  164. t0 = startIndex + ( i * step );
  165. t1 = t0 + step;
  166. b0 = skirtStartIdx + i;
  167. b1 = skirtStartIdx + i + 1;
  168. idxBuff[0] = t1;
  169. idxBuff[1] = t0;
  170. idxBuff[2] = b0;
  171. idxBuff[3] = t1;
  172. idxBuff[4] = b0;
  173. idxBuff[5] = b1;
  174. idxBuff += 6;
  175. maxIndex = b1;
  176. counter += 6;
  177. }
  178. // Left edge skirt...
  179. // Index to the first vert of the left column.
  180. startIndex = 0;
  181. // Index to the first vert of the skirt under the left column.
  182. skirtStartIdx = smVBStride * smVBStride + smVBStride * 2;
  183. // Step to go one vert down.
  184. step = smVBStride;
  185. for ( U32 i = 0; i < smMinCellSize; i++ )
  186. {
  187. t0 = startIndex + ( i * step );
  188. t1 = t0 + step;
  189. b0 = skirtStartIdx + i;
  190. b1 = skirtStartIdx + i + 1;
  191. idxBuff[0] = t1;
  192. idxBuff[1] = t0;
  193. idxBuff[2] = b0;
  194. idxBuff[3] = t1;
  195. idxBuff[4] = b0;
  196. idxBuff[5] = b1;
  197. idxBuff += 6;
  198. maxIndex = b1;
  199. counter += 6;
  200. }
  201. // Right edge skirt...
  202. // Index to the first vert of the right column.
  203. startIndex = smVBStride - 1;
  204. // Index to the first vert of the skirt under the right column.
  205. skirtStartIdx = smVBStride * smVBStride + smVBStride * 3;
  206. // Step to go one vert down.
  207. step = smVBStride;
  208. for ( U32 i = 0; i < smMinCellSize; i++ )
  209. {
  210. t0 = startIndex + ( i * step );
  211. t1 = t0 + step;
  212. b0 = skirtStartIdx + i;
  213. b1 = skirtStartIdx + i + 1;
  214. idxBuff[0] = b0;
  215. idxBuff[1] = t0;
  216. idxBuff[2] = t1;
  217. idxBuff[3] = b1;
  218. idxBuff[4] = b0;
  219. idxBuff[5] = t1;
  220. idxBuff += 6;
  221. maxIndex = b1;
  222. counter += 6;
  223. }
  224. primBuffer->unlock();
  225. }
  226. TerrCell* TerrCell::init( TerrainBlock *terrain )
  227. {
  228. // Just create the root cell and call the inner init.
  229. TerrCell *root = new TerrCell;
  230. root->_init( terrain,
  231. Point2I( 0, 0 ),
  232. terrain->getBlockSize(),
  233. 0 );
  234. // Set initial states of OBBs.
  235. root->updateOBBs();
  236. return root;
  237. }
  238. void TerrCell::_init( TerrainBlock *terrain,
  239. const Point2I &point,
  240. U32 size,
  241. U32 level )
  242. {
  243. PROFILE_SCOPE( TerrCell_Init );
  244. mTerrain = terrain;
  245. mPoint = point;
  246. mSize = size;
  247. mLevel = level;
  248. // Generate a VB (and maybe a PB) for this cell, unless we are the Root cell.
  249. if ( level > 0 )
  250. {
  251. _updateVertexBuffer();
  252. _updatePrimitiveBuffer();
  253. }
  254. if ( mSize <= smMinCellSize )
  255. {
  256. // Update our bounds and materials... the
  257. // parent will use it to update itself.
  258. _updateBounds();
  259. _updateMaterials();
  260. return;
  261. }
  262. // Create our children and update our
  263. // bounds and materials from them.
  264. const U32 childSize = mSize / 2;
  265. const U32 childLevel = mLevel + 1;
  266. mChildren[0] = new TerrCell;
  267. mChildren[0]->_init( mTerrain,
  268. Point2I( mPoint.x, mPoint.y ),
  269. childSize,
  270. childLevel );
  271. mBounds = mChildren[0]->getBounds();
  272. mMaterials = mChildren[0]->getMaterials();
  273. mChildren[1] = new TerrCell;
  274. mChildren[1]->_init( mTerrain,
  275. Point2I( mPoint.x + childSize, mPoint.y ),
  276. childSize,
  277. childLevel );
  278. mBounds.intersect( mChildren[1]->getBounds() );
  279. mMaterials |= mChildren[1]->getMaterials();
  280. mChildren[2] = new TerrCell;
  281. mChildren[2]->_init( mTerrain,
  282. Point2I( mPoint.x, mPoint.y + childSize ),
  283. childSize,
  284. childLevel );
  285. mBounds.intersect( mChildren[2]->getBounds() );
  286. mMaterials |= mChildren[2]->getMaterials();
  287. mChildren[3] = new TerrCell;
  288. mChildren[3]->_init( mTerrain,
  289. Point2I( mPoint.x + childSize, mPoint.y + childSize ),
  290. childSize,
  291. childLevel );
  292. mBounds.intersect( mChildren[3]->getBounds() );
  293. mMaterials |= mChildren[3]->getMaterials();
  294. mRadius = mBounds.len() * 0.5f;
  295. _updateOBB();
  296. }
  297. void TerrCell::updateGrid( const RectI &gridRect, bool opacityOnly )
  298. {
  299. PROFILE_SCOPE( TerrCell_UpdateGrid );
  300. // If we have a VB... then update it.
  301. if ( mVertexBuffer.isValid() && !opacityOnly )
  302. _updateVertexBuffer();
  303. // Update our PB, if any
  304. _updatePrimitiveBuffer();
  305. // If we don't have children... then we're
  306. // a leaf at the bottom of the cell quadtree
  307. // and we should just update our bounds.
  308. if ( !mChildren[0] )
  309. {
  310. if ( !opacityOnly )
  311. _updateBounds();
  312. _updateMaterials();
  313. return;
  314. }
  315. // Otherwise, we must call updateGrid on our children
  316. // and then update our bounds/materials AFTER to contain them.
  317. mMaterials = 0;
  318. for ( U32 i = 0; i < 4; i++ )
  319. {
  320. TerrCell *cell = mChildren[i];
  321. // The overlap test doesn't hit shared edges
  322. // so grow it a bit when we create it.
  323. const RectI cellRect( cell->mPoint.x - 1,
  324. cell->mPoint.y - 1,
  325. cell->mSize + 2,
  326. cell->mSize + 2 );
  327. // We do an overlap and containment test as it
  328. // properly handles zero sized rects.
  329. if ( cellRect.contains( gridRect ) ||
  330. cellRect.overlaps( gridRect ) )
  331. cell->updateGrid( gridRect, opacityOnly );
  332. // Update the bounds from our children.
  333. if ( !opacityOnly )
  334. {
  335. if ( i == 0 )
  336. mBounds = mChildren[i]->getBounds();
  337. else
  338. mBounds.intersect( mChildren[i]->getBounds() );
  339. mRadius = mBounds.len() * 0.5f;
  340. }
  341. // Update the material flags.
  342. mMaterials |= mChildren[i]->getMaterials();
  343. }
  344. if ( mMaterial )
  345. mMaterial->init( mTerrain, mMaterials );
  346. }
  347. void TerrCell::_updateVertexBuffer()
  348. {
  349. PROFILE_SCOPE( TerrCell_UpdateVertexBuffer );
  350. // Start off with no empty squares
  351. mHasEmpty = false;
  352. mEmptyVertexList.clear();
  353. mVertexBuffer.set( GFX, smVBSize, GFXBufferTypeStatic );
  354. const F32 squareSize = mTerrain->getSquareSize();
  355. const U32 blockSize = mTerrain->getBlockSize();
  356. const U32 stepSize = mSize / smMinCellSize;
  357. U32 vbcounter = 0;
  358. TerrVertex *vert = mVertexBuffer.lock();
  359. Point2I gridPt;
  360. Point2F point;
  361. F32 height;
  362. Point3F normal;
  363. const TerrainFile *file = mTerrain->getFile();
  364. for ( U32 y = 0; y < smVBStride; y++ )
  365. {
  366. for ( U32 x = 0; x < smVBStride; x++ )
  367. {
  368. // We clamp here to keep the geometry from reading across
  369. // one side of the height map to the other causing walls
  370. // around the edges of the terrain.
  371. gridPt.x = mClamp( mPoint.x + x * stepSize, 0, blockSize - 1 );
  372. gridPt.y = mClamp( mPoint.y + y * stepSize, 0, blockSize - 1 );
  373. // Setup this point.
  374. point.x = (F32)gridPt.x * squareSize;
  375. point.y = (F32)gridPt.y * squareSize;
  376. height = fixedToFloat( file->getHeight( gridPt.x, gridPt.y ) );
  377. vert->point.x = point.x;
  378. vert->point.y = point.y;
  379. vert->point.z = height;
  380. // Get the normal.
  381. mTerrain->getSmoothNormal( point, &normal, true, false );
  382. vert->normal = normal;
  383. // Get the tangent z.
  384. vert->tangentZ = fixedToFloat( file->getHeight( gridPt.x + 1, gridPt.y ) ) - height;
  385. // Test the empty state for this vert.
  386. if ( file->isEmptyAt( gridPt.x, gridPt.y ) )
  387. {
  388. mHasEmpty = true;
  389. mEmptyVertexList.push_back( vbcounter );
  390. }
  391. vbcounter++;
  392. ++vert;
  393. }
  394. }
  395. // Add verts for 'skirts' around/beneath the edge verts of this cell.
  396. // This could probably be reduced to a loop...
  397. const F32 skirtDepth = mSize / smMinCellSize * mTerrain->getSquareSize();
  398. // Top edge skirt
  399. for ( U32 i = 0; i < smVBStride; i++ )
  400. {
  401. gridPt.x = mClamp( mPoint.x + i * stepSize, 0, blockSize - 1 );
  402. gridPt.y = mClamp( mPoint.y, 0, blockSize - 1 );
  403. point.x = (F32)gridPt.x * squareSize;
  404. point.y = (F32)gridPt.y * squareSize;
  405. height = fixedToFloat( file->getHeight( gridPt.x, gridPt.y ) );
  406. vert->point.x = point.x;
  407. vert->point.y = point.y;
  408. vert->point.z = height - skirtDepth;
  409. // Get the normal.
  410. mTerrain->getNormal( point, &normal, true, false );
  411. vert->normal = normal;
  412. // Get the tangent.
  413. vert->tangentZ = height - fixedToFloat( file->getHeight( gridPt.x + 1, gridPt.y ) );
  414. vbcounter++;
  415. ++vert;
  416. }
  417. // Bottom edge skirt
  418. for ( U32 i = 0; i < smVBStride; i++ )
  419. {
  420. gridPt.x = mClamp( mPoint.x + i * stepSize, 0, blockSize - 1 );
  421. gridPt.y = mClamp( mPoint.y + smMinCellSize * stepSize, 0, blockSize - 1 );
  422. point.x = (F32)gridPt.x * squareSize;
  423. point.y = (F32)gridPt.y * squareSize;
  424. height = fixedToFloat( file->getHeight( gridPt.x, gridPt.y ) );
  425. vert->point.x = point.x;
  426. vert->point.y = point.y;
  427. vert->point.z = height - skirtDepth;
  428. // Get the normal.
  429. mTerrain->getNormal( point, &normal, true, false );
  430. vert->normal = normal;
  431. // Get the tangent.
  432. vert->tangentZ = height - fixedToFloat( file->getHeight( gridPt.x + 1, gridPt.y ) );
  433. vbcounter++;
  434. ++vert;
  435. }
  436. // Left edge skirt
  437. for ( U32 i = 0; i < smVBStride; i++ )
  438. {
  439. gridPt.x = mClamp( mPoint.x, 0, blockSize - 1 );
  440. gridPt.y = mClamp( mPoint.y + i * stepSize, 0, blockSize - 1 );
  441. point.x = (F32)gridPt.x * squareSize;
  442. point.y = (F32)gridPt.y * squareSize;
  443. height = fixedToFloat( file->getHeight( gridPt.x, gridPt.y ) );
  444. vert->point.x = point.x;
  445. vert->point.y = point.y;
  446. vert->point.z = height - skirtDepth;
  447. // Get the normal.
  448. mTerrain->getNormal( point, &normal, true, false );
  449. vert->normal = normal;
  450. // Get the tangent.
  451. vert->tangentZ = height - fixedToFloat( file->getHeight( gridPt.x + 1, gridPt.y ) );
  452. vbcounter++;
  453. ++vert;
  454. }
  455. // Right edge skirt
  456. for ( U32 i = 0; i < smVBStride; i++ )
  457. {
  458. gridPt.x = mClamp( mPoint.x + smMinCellSize * stepSize, 0, blockSize - 1 );
  459. gridPt.y = mClamp( mPoint.y + i * stepSize, 0, blockSize - 1 );
  460. point.x = (F32)gridPt.x * squareSize;
  461. point.y = (F32)gridPt.y * squareSize;
  462. height = fixedToFloat( file->getHeight( gridPt.x, gridPt.y ) );
  463. vert->point.x = point.x;
  464. vert->point.y = point.y;
  465. vert->point.z = height - skirtDepth;
  466. // Get the normal.
  467. mTerrain->getNormal( point, &normal, true, false );
  468. vert->normal = normal;
  469. // Get the tangent.
  470. vert->tangentZ = height - fixedToFloat( file->getHeight( gridPt.x + 1, gridPt.y ) );
  471. vbcounter++;
  472. ++vert;
  473. }
  474. AssertFatal( vbcounter == smVBSize, "bad" );
  475. mVertexBuffer.unlock();
  476. deleteZodiacVertexBuffer();
  477. }
  478. void TerrCell::_updatePrimitiveBuffer()
  479. {
  480. PROFILE_SCOPE( TerrCell_UpdatePrimitiveBuffer );
  481. if ( !mHasEmpty )
  482. {
  483. if ( mPrimBuffer.isValid() )
  484. {
  485. // There are no more empty squares for this cell, so
  486. // get rid of the primitive buffer to use the standard one.
  487. mPrimBuffer = NULL;
  488. }
  489. return;
  490. }
  491. // Build our custom primitive buffer. We're setting it to the maximum allowed
  492. // size, but should be just shy of it depending on the number of empty squares
  493. // in this cell. We could calculate it, but note that it would be different
  494. // from mEmptyVertexList.size() as that can include vertices on the edges that
  495. // are really considered part of another cell's squares. So we take a slightly
  496. // larger buffer over running through the calculation.
  497. mPrimBuffer.set( GFX, smPBSize, 1, GFXBufferTypeStatic, "TerrCell" );
  498. GFXPrimitive *prim = mPrimBuffer.getPointer()->mPrimitiveArray;
  499. prim->type = GFXTriangleList;
  500. prim->numVertices = smVBSize;
  501. mTriCount = 0;
  502. // Lock and fill it up!
  503. U16 *idxBuff;
  504. mPrimBuffer.lock( &idxBuff );
  505. U32 counter = 0;
  506. U32 maxIndex = 0;
  507. for ( U32 y = 0; y < smMinCellSize; y++ )
  508. {
  509. const U32 yTess = y % 2;
  510. for ( U32 x = 0; x < smMinCellSize; x++ )
  511. {
  512. U32 index = ( y * smVBStride ) + x;
  513. // Should this square be skipped?
  514. if ( _isVertIndexEmpty(index) )
  515. continue;
  516. const U32 xTess = x % 2;
  517. if ( ( xTess == 0 && yTess == 0 ) ||
  518. ( xTess != 0 && yTess != 0 ) )
  519. {
  520. idxBuff[0] = index + 0;
  521. idxBuff[1] = index + smVBStride;
  522. idxBuff[2] = index + smVBStride + 1;
  523. idxBuff[3] = index + 0;
  524. idxBuff[4] = index + smVBStride + 1;
  525. idxBuff[5] = index + 1;
  526. }
  527. else
  528. {
  529. idxBuff[0] = index + 1;
  530. idxBuff[1] = index;
  531. idxBuff[2] = index + smVBStride;
  532. idxBuff[3] = index + 1;
  533. idxBuff[4] = index + smVBStride;
  534. idxBuff[5] = index + smVBStride + 1;
  535. }
  536. idxBuff += 6;
  537. maxIndex = index + 1 + smVBStride;
  538. counter += 6;
  539. mTriCount += 2;
  540. }
  541. }
  542. // Now add indices for the 'skirts'.
  543. // These could probably be reduced to a loop.
  544. // Temporaries that hold triangle indices.
  545. // Top/Bottom - 0,1
  546. U32 t0, t1, b0, b1;
  547. // Top edge skirt...
  548. // Index to the first vert of the top row.
  549. U32 startIndex = 0;
  550. // Index to the first vert of the skirt under the top row.
  551. U32 skirtStartIdx = smVBStride * smVBStride;
  552. // Step to go one vert to the right.
  553. U32 step = 1;
  554. for ( U32 i = 0; i < smMinCellSize; i++ )
  555. {
  556. t0 = startIndex + i * step;
  557. // Should this square be skipped?
  558. if ( _isVertIndexEmpty(t0) )
  559. continue;
  560. t1 = t0 + step;
  561. b0 = skirtStartIdx + i;
  562. b1 = skirtStartIdx + i + 1;
  563. idxBuff[0] = b0;
  564. idxBuff[1] = t0;
  565. idxBuff[2] = t1;
  566. idxBuff[3] = b1;
  567. idxBuff[4] = b0;
  568. idxBuff[5] = t1;
  569. idxBuff += 6;
  570. maxIndex = b1;
  571. counter += 6;
  572. mTriCount += 2;
  573. }
  574. // Bottom edge skirt...
  575. // Index to the first vert of the bottom row.
  576. startIndex = smVBStride * smVBStride - smVBStride;
  577. // Index to the first vert of the skirt under the bottom row.
  578. skirtStartIdx = startIndex + smVBStride * 2;
  579. // Step to go one vert to the right.
  580. step = 1;
  581. for ( U32 i = 0; i < smMinCellSize; i++ )
  582. {
  583. t0 = startIndex + ( i * step );
  584. // Should this square be skipped? We actually need to test
  585. // the vertex one row down as it defines the empty state
  586. // for this square.
  587. if ( _isVertIndexEmpty( t0 - smVBStride ) )
  588. continue;
  589. t1 = t0 + step;
  590. b0 = skirtStartIdx + i;
  591. b1 = skirtStartIdx + i + 1;
  592. idxBuff[0] = t1;
  593. idxBuff[1] = t0;
  594. idxBuff[2] = b0;
  595. idxBuff[3] = t1;
  596. idxBuff[4] = b0;
  597. idxBuff[5] = b1;
  598. idxBuff += 6;
  599. maxIndex = b1;
  600. counter += 6;
  601. mTriCount += 2;
  602. }
  603. // Left edge skirt...
  604. // Index to the first vert of the left column.
  605. startIndex = 0;
  606. // Index to the first vert of the skirt under the left column.
  607. skirtStartIdx = smVBStride * smVBStride + smVBStride * 2;
  608. // Step to go one vert down.
  609. step = smVBStride;
  610. for ( U32 i = 0; i < smMinCellSize; i++ )
  611. {
  612. t0 = startIndex + ( i * step );
  613. // Should this square be skipped?
  614. if ( _isVertIndexEmpty(t0) )
  615. continue;
  616. t1 = t0 + step;
  617. b0 = skirtStartIdx + i;
  618. b1 = skirtStartIdx + i + 1;
  619. idxBuff[0] = t1;
  620. idxBuff[1] = t0;
  621. idxBuff[2] = b0;
  622. idxBuff[3] = t1;
  623. idxBuff[4] = b0;
  624. idxBuff[5] = b1;
  625. idxBuff += 6;
  626. maxIndex = b1;
  627. counter += 6;
  628. mTriCount += 2;
  629. }
  630. // Right edge skirt...
  631. // Index to the first vert of the right column.
  632. startIndex = smVBStride - 1;
  633. // Index to the first vert of the skirt under the right column.
  634. skirtStartIdx = smVBStride * smVBStride + smVBStride * 3;
  635. // Step to go one vert down.
  636. step = smVBStride;
  637. for ( U32 i = 0; i < smMinCellSize; i++ )
  638. {
  639. t0 = startIndex + ( i * step );
  640. // Should this square be skipped? We actually need to test
  641. // the vertex one column to the left as it defines the empty
  642. // state for this square.
  643. if ( _isVertIndexEmpty( t0 - 1 ) )
  644. continue;
  645. t1 = t0 + step;
  646. b0 = skirtStartIdx + i;
  647. b1 = skirtStartIdx + i + 1;
  648. idxBuff[0] = b0;
  649. idxBuff[1] = t0;
  650. idxBuff[2] = t1;
  651. idxBuff[3] = b1;
  652. idxBuff[4] = b0;
  653. idxBuff[5] = t1;
  654. idxBuff += 6;
  655. maxIndex = b1;
  656. counter += 6;
  657. mTriCount += 2;
  658. }
  659. mPrimBuffer.unlock();
  660. prim->numPrimitives = mTriCount;
  661. }
  662. void TerrCell::_updateMaterials()
  663. {
  664. PROFILE_SCOPE( TerrCell_UpdateMaterials );
  665. // This should really only be called for cells of smMinCellSize,
  666. // in which case stepSize is always one.
  667. U32 stepSize = mSize / smMinCellSize;
  668. mMaterials = 0;
  669. U8 index;
  670. U32 x, y;
  671. const TerrainFile *file = mTerrain->getFile();
  672. // Step thru the samples in the map then.
  673. for ( y = 0; y < smVBStride; y++ )
  674. {
  675. for ( x = 0; x < smVBStride; x++ )
  676. {
  677. index = file->getLayerIndex( mPoint.x + x * stepSize,
  678. mPoint.y + y * stepSize );
  679. // Skip empty layers and anything that doesn't fit
  680. // the 64bit material flags.
  681. if ( index == U8_MAX || index > 63 )
  682. continue;
  683. mMaterials |= (U64)((U64)1<<index);
  684. }
  685. }
  686. if ( mMaterial )
  687. mMaterial->init( mTerrain, mMaterials );
  688. }
  689. void TerrCell::_updateBounds()
  690. {
  691. PROFILE_SCOPE( TerrCell_UpdateBounds );
  692. const F32 squareSize = mTerrain->getSquareSize();
  693. // This should really only be called for cells of smMinCellSize,
  694. // in which case stepSize is always one.
  695. const U32 stepSize = mSize / smMinCellSize;
  696. // Prepare to expand the bounds.
  697. mBounds.minExtents.set( F32_MAX, F32_MAX, F32_MAX );
  698. mBounds.maxExtents.set( -F32_MAX, -F32_MAX, -F32_MAX );
  699. Point3F vert;
  700. Point2F texCoord;
  701. const TerrainFile *file = mTerrain->getFile();
  702. for ( U32 y = 0; y < smVBStride; y++ )
  703. {
  704. for ( U32 x = 0; x < smVBStride; x++ )
  705. {
  706. // Setup this point.
  707. vert.x = (F32)( mPoint.x + x * stepSize ) * squareSize;
  708. vert.y = (F32)( mPoint.y + y * stepSize ) * squareSize;
  709. vert.z = fixedToFloat( file->getHeight( mPoint.x + x,
  710. mPoint.y + y ) );
  711. // HACK: Call it twice to deal with the inverted
  712. // inital bounds state... shouldn't be a perf issue.
  713. mBounds.extend( vert );
  714. mBounds.extend( vert );
  715. }
  716. }
  717. mRadius = mBounds.len() * 0.5;
  718. _updateOBB();
  719. }
  720. void TerrCell::_updateOBB()
  721. {
  722. mOBB.set( mTerrain->getTransform(), mBounds );
  723. }
  724. void TerrCell::updateOBBs()
  725. {
  726. _updateOBB();
  727. // Update children.
  728. if( mChildren[ 0 ] )
  729. for( U32 i = 0; i < 4; ++ i )
  730. mChildren[ i ]->updateOBBs();
  731. }
  732. void TerrCell::updateZoning( const SceneZoneSpaceManager *zoneManager )
  733. {
  734. PROFILE_SCOPE( TerrCell_UpdateZoning );
  735. mZoneOverlap.setSize( zoneManager->getNumZones() );
  736. mZoneOverlap.clear();
  737. mIsInteriorOnly = true;
  738. if ( mChildren[0] == NULL )
  739. {
  740. Box3F worldBounds( mBounds );
  741. mTerrain->getTransform().mul( worldBounds );
  742. Vector<U32> zones;
  743. zoneManager->findZones( worldBounds, zones );
  744. for ( U32 i=0; i < zones.size(); i++ )
  745. {
  746. // Set overlap bit for zone except it's the outdoor zone.
  747. if( zones[ i ] != SceneZoneSpaceManager::RootZoneId )
  748. mZoneOverlap.set( zones[i] );
  749. else
  750. mIsInteriorOnly = false;
  751. }
  752. return;
  753. }
  754. for ( U32 i = 0; i < 4; i++ )
  755. {
  756. TerrCell *cell = mChildren[i];
  757. cell->updateZoning( zoneManager );
  758. mZoneOverlap.combineOR( cell->getZoneOverlap() );
  759. mIsInteriorOnly &= cell->mIsInteriorOnly;
  760. }
  761. }
  762. void TerrCell::cullCells( const SceneRenderState *state,
  763. const Point3F &objLodPos,
  764. Vector<TerrCell*> *outCells )
  765. {
  766. // If we have a VB and no children then just add
  767. // ourselves to the results and return.
  768. if ( mVertexBuffer.isValid() && !mChildren[0] )
  769. {
  770. outCells->push_back( this );
  771. return;
  772. }
  773. const F32 screenError = mTerrain->getScreenError();
  774. const BitVector &zoneState = state->getCullingState().getZoneVisibilityFlags();
  775. for ( U32 i = 0; i < 4; i++ )
  776. {
  777. TerrCell *cell = mChildren[i];
  778. // Test cell visibility for interior zones.
  779. const bool visibleInside = !cell->getZoneOverlap().empty() ? zoneState.testAny( cell->getZoneOverlap() ) : false;
  780. // Test cell visibility for outdoor zone, but only
  781. // if we need to.
  782. bool visibleOutside = false;
  783. if( !mIsInteriorOnly && !visibleInside )
  784. {
  785. U32 outdoorZone = SceneZoneSpaceManager::RootZoneId;
  786. visibleOutside = !state->getCullingState().isCulled( cell->mOBB, &outdoorZone, 1 );
  787. }
  788. // Skip cell if neither visible indoors nor outdoors.
  789. if( !visibleInside && !visibleOutside )
  790. continue;
  791. // Lod based on screen error...
  792. // If far enough, just add this child cells vb ( skipping its children ).
  793. F32 dist = cell->getDistanceTo( objLodPos );
  794. F32 errorMeters = ( cell->mSize / smMinCellSize ) * mTerrain->getSquareSize();
  795. U32 errorPixels = mCeil( state->projectRadius( dist, errorMeters ) );
  796. if ( errorPixels < screenError )
  797. {
  798. if ( cell->mVertexBuffer.isValid() )
  799. outCells->push_back( cell );
  800. }
  801. else
  802. cell->cullCells( state, objLodPos, outCells );
  803. }
  804. }
  805. void TerrCell::getRenderPrimitive( GFXPrimitive *prim,
  806. GFXVertexBufferHandleBase *vertBuff,
  807. GFXPrimitiveBufferHandle *primBuff ) const
  808. {
  809. *vertBuff = mVertexBuffer;
  810. // Only supply a primitive buffer if we're using our own
  811. // due to empty squares.
  812. bool useStaticPrimBuffer = true;
  813. if ( mPrimBuffer.isValid() )
  814. {
  815. useStaticPrimBuffer = false;
  816. *primBuff = mPrimBuffer;
  817. }
  818. prim->type = GFXTriangleList;
  819. prim->startVertex = 0;
  820. prim->minIndex = 0;
  821. prim->startIndex = 0;
  822. prim->numVertices = smVBSize;
  823. if ( useStaticPrimBuffer )
  824. {
  825. // Use the standard primitive buffer count
  826. prim->numPrimitives = smTriCount;
  827. }
  828. else
  829. {
  830. // Use our triangle count that matches out primitive buffer
  831. prim->numPrimitives = mTriCount;
  832. }
  833. }
  834. void TerrCell::renderBounds() const
  835. {
  836. LinearColorF color;
  837. color.interpolate( ColorI::RED, ColorI::GREEN, (F32)mLevel / 3.0f );
  838. GFXStateBlockDesc desc;
  839. desc.setZReadWrite( true, false );
  840. desc.fillMode = GFXFillWireframe;
  841. GFX->getDrawUtil()->drawCube( desc, mBounds, color.toColorI());
  842. }
  843. void TerrCell::preloadMaterials()
  844. {
  845. PROFILE_SCOPE( TerrCell_PreloadMaterials );
  846. // If we have a VB then we need a material.
  847. if ( mVertexBuffer.isValid() )
  848. {
  849. TerrainCellMaterial *material = getMaterial();
  850. material->getReflectMat();
  851. if ( GFX->getPixelShaderVersion() > 2.0f &&
  852. dStrcmp( LIGHTMGR->getId(), "BLM" ) != 0)
  853. material->getDeferredMat();
  854. }
  855. for ( U32 i = 0; i < 4; i++ )
  856. if ( mChildren[i] )
  857. mChildren[i]->preloadMaterials();
  858. }
  859. TerrainCellMaterial* TerrCell::getMaterial()
  860. {
  861. if ( !mMaterial )
  862. {
  863. mMaterial = new TerrainCellMaterial;
  864. mMaterial->init( mTerrain, mMaterials );
  865. }
  866. return mMaterial;
  867. }
  868. void TerrCell::deleteMaterials()
  869. {
  870. SAFE_DELETE( mMaterial );
  871. for ( U32 i = 0; i < 4; i++ )
  872. if ( mChildren[i] )
  873. mChildren[i]->deleteMaterials();
  874. }
  875. const Point3F* TerrCell::getZodiacVertexBuffer()
  876. {
  877. if (!zode_vertexBuffer)
  878. createZodiacVertexBuffer();
  879. return zode_vertexBuffer;
  880. }
  881. void TerrCell::createZodiacPrimBuffer(U16** zode_primBuffer)
  882. {
  883. if (*zode_primBuffer != 0)
  884. delete [] *zode_primBuffer;
  885. *zode_primBuffer = new U16[TerrCell::smMinCellSize*TerrCell::smMinCellSize*6];
  886. // Lock and fill it up!
  887. U16* idxBuff = *zode_primBuffer;
  888. U32 counter = 0;
  889. U32 maxIndex = 0;
  890. for ( U32 y = 0; y < smMinCellSize; y++ )
  891. {
  892. const U32 yTess = y % 2;
  893. for ( U32 x = 0; x < smMinCellSize; x++ )
  894. {
  895. U32 index = ( y * smVBStride ) + x;
  896. const U32 xTess = x % 2;
  897. if ( ( xTess == 0 && yTess == 0 ) ||
  898. ( xTess != 0 && yTess != 0 ) )
  899. {
  900. idxBuff[0] = index + 0;
  901. idxBuff[1] = index + smVBStride;
  902. idxBuff[2] = index + smVBStride + 1;
  903. idxBuff[3] = index + 0;
  904. idxBuff[4] = index + smVBStride + 1;
  905. idxBuff[5] = index + 1;
  906. }
  907. else
  908. {
  909. idxBuff[0] = index + 1;
  910. idxBuff[1] = index;
  911. idxBuff[2] = index + smVBStride;
  912. idxBuff[3] = index + 1;
  913. idxBuff[4] = index + smVBStride;
  914. idxBuff[5] = index + smVBStride + 1;
  915. }
  916. idxBuff += 6;
  917. maxIndex = index + 1 + smVBStride;
  918. counter += 6;
  919. }
  920. }
  921. }
  922. void TerrCell::createZodiacVertexBuffer()
  923. {
  924. const F32 squareSize = mTerrain->getSquareSize();
  925. const U32 blockSize = mTerrain->getBlockSize();
  926. const U32 stepSize = mSize / smMinCellSize;
  927. if (zode_vertexBuffer)
  928. delete [] zode_vertexBuffer;
  929. zode_vertexBuffer = new Point3F[smVBStride*smVBStride];
  930. Point3F* vert = zode_vertexBuffer;
  931. Point2I gridPt;
  932. Point2F point;
  933. F32 height;
  934. const TerrainFile *file = mTerrain->getFile();
  935. for ( U32 y = 0; y < smVBStride; y++ )
  936. {
  937. for ( U32 x = 0; x < smVBStride; x++ )
  938. {
  939. // We clamp here to keep the geometry from reading across
  940. // one side of the height map to the other causing walls
  941. // around the edges of the terrain.
  942. gridPt.x = mClamp( mPoint.x + x * stepSize, 0, blockSize - 1 );
  943. gridPt.y = mClamp( mPoint.y + y * stepSize, 0, blockSize - 1 );
  944. // Setup this point.
  945. point.x = (F32)gridPt.x * squareSize;
  946. point.y = (F32)gridPt.y * squareSize;
  947. height = fixedToFloat( file->getHeight( gridPt.x, gridPt.y ) );
  948. vert->x = point.x;
  949. vert->y = point.y;
  950. vert->z = height;
  951. ++vert;
  952. }
  953. }
  954. }
  955. void TerrCell::deleteZodiacVertexBuffer()
  956. {
  957. if (zode_vertexBuffer)
  958. {
  959. delete [] zode_vertexBuffer;
  960. zode_vertexBuffer = 0;
  961. }
  962. }