terrCell.cpp 33 KB

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