terrRender.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  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/terrRender.h"
  28. #include "terrain/terrData.h"
  29. #include "terrain/terrCell.h"
  30. #include "terrain/terrMaterial.h"
  31. #include "terrain/terrCellMaterial.h"
  32. #include "materials/shaderData.h"
  33. #include "platform/profiler.h"
  34. #include "scene/sceneRenderState.h"
  35. #include "math/util/frustum.h"
  36. #include "renderInstance/renderPassManager.h"
  37. #include "renderInstance/renderTerrainMgr.h"
  38. #include "lighting/lightInfo.h"
  39. #include "lighting/lightManager.h"
  40. #include "materials/matInstance.h"
  41. #include "materials/materialManager.h"
  42. #include "materials/matTextureTarget.h"
  43. #include "shaderGen/conditionerFeature.h"
  44. #include "gfx/gfxDrawUtil.h"
  45. #ifdef TORQUE_AFX_ENABLED
  46. #include "afx/arcaneFX.h"
  47. #include "afx/ce/afxZodiacMgr.h"
  48. #endif
  49. #include "gfx/gfxTransformSaver.h"
  50. #include "gfx/bitmap/gBitmap.h"
  51. #include "gfx/bitmap/ddsFile.h"
  52. #include "gfx/bitmap/imageUtils.h"
  53. #include "terrain/terrMaterial.h"
  54. #include "gfx/gfxDebugEvent.h"
  55. #include "gfx/gfxCardProfile.h"
  56. #include "core/stream/fileStream.h"
  57. bool TerrainBlock::smDebugRender = false;
  58. GFX_ImplementTextureProfile( TerrainLayerTexProfile,
  59. GFXTextureProfile::DiffuseMap,
  60. GFXTextureProfile::PreserveSize |
  61. GFXTextureProfile::Dynamic,
  62. GFXTextureProfile::NONE );
  63. void TerrainBlock::_onFlushMaterials()
  64. {
  65. if ( mCell )
  66. mCell->deleteMaterials();
  67. SAFE_DELETE( mBaseMaterial );
  68. }
  69. void TerrainBlock::_updateMaterials()
  70. {
  71. if (!mFile)
  72. return;
  73. mBaseTextures.setSize( mFile->mMaterials.size() );
  74. mMaxDetailDistance = 0.0f;
  75. for ( U32 i=0; i < mFile->mMaterials.size(); i++ )
  76. {
  77. TerrainMaterial *mat = mFile->mMaterials[i];
  78. if (mat->getDiffuseMap() != StringTable->EmptyString())
  79. {
  80. mBaseTextures[i] = mat->getDiffuseMapResource();
  81. }
  82. else
  83. mBaseTextures[ i ] = GFXTexHandle();
  84. // Find the maximum detail distance.
  85. if ( mat->getDetailMap() != StringTable->EmptyString() &&
  86. mat->getDetailDistance() > mMaxDetailDistance )
  87. mMaxDetailDistance = mat->getDetailDistance();
  88. if ( mat->getMacroMap() != StringTable->EmptyString() &&
  89. mat->getMacroDistance() > mMaxDetailDistance )
  90. mMaxDetailDistance = mat->getMacroDistance();
  91. }
  92. Vector<GFXTexHandle> detailTexArray;
  93. detailTexArray.setSize(mFile->mMaterials.size());
  94. Vector<GFXTexHandle> macroTexArray;
  95. macroTexArray.setSize(mFile->mMaterials.size());
  96. Vector<GFXTexHandle> normalTexArray;
  97. normalTexArray.setSize(mFile->mMaterials.size());
  98. Vector<GFXTexHandle> ormTexArray;
  99. ormTexArray.setSize(mFile->mMaterials.size());
  100. for (U32 i = 0; i < mFile->mMaterials.size(); i++)
  101. {
  102. TerrainMaterial* mat = mFile->mMaterials[i];
  103. if (mat->getDetailMap() != StringTable->EmptyString())
  104. detailTexArray[i] = mat->getDetailMapResource();
  105. if (mat->getMacroMap() != StringTable->EmptyString())
  106. macroTexArray[i] = mat->getMacroMapResource();
  107. if (mat->getNormalMap() != StringTable->EmptyString())
  108. normalTexArray[i] = mat->getNormalMapResource();
  109. //depending on creation method this may or may not have been shoved into srgb space eroneously
  110. GFXTextureProfile* profile = &GFXStaticTextureProfile;
  111. if (mat->getIsSRGB())
  112. profile = &GFXStaticTextureSRGBProfile;
  113. if (mat->getORMConfigMap() != StringTable->EmptyString())
  114. ormTexArray[i] = TEXMGR->createTexture(mat->getORMConfigMap(), profile);
  115. }
  116. if (mDetailTextureArray.isNull())
  117. {
  118. mDetailTextureArray = GFX->createTextureArray();
  119. }
  120. if (mMacroTextureArray.isNull())
  121. {
  122. mMacroTextureArray = GFX->createTextureArray();
  123. }
  124. if (mNormalTextureArray.isNull())
  125. {
  126. mNormalTextureArray = GFX->createTextureArray();
  127. }
  128. if (mOrmTextureArray.isNull())
  129. {
  130. mOrmTextureArray = GFX->createTextureArray();
  131. }
  132. U32 detailTexArraySize = detailTexArray.size();
  133. U32 macroTexArraySize = macroTexArray.size();
  134. U32 normalTexArraySize = normalTexArray.size();
  135. U32 ormTexArraySize = ormTexArray.size();
  136. #ifdef TORQUE_TOOLS
  137. // For performance improvement when adding terrain layers, we always allocate at least 32 textures to the arrays in tool builds
  138. detailTexArraySize = mMax(32, detailTexArraySize);
  139. macroTexArraySize = mMax(32, macroTexArraySize);
  140. normalTexArraySize = mMax(32, normalTexArraySize);
  141. ormTexArraySize = mMax(32, ormTexArraySize);
  142. #endif
  143. // Format has been explicitly set
  144. const U32 detailTexSize = Con::getIntVariable("Terrain::DetailTextureSize");
  145. const GFXFormat detailTexFormat = static_cast<GFXFormat>(Con::getIntVariable("Terrain::DetailTextureFormat"));
  146. if (detailTexSize != 0)
  147. {
  148. GFXFormat format = GFXFormatR8G8B8A8;
  149. if (detailTexFormat < GFXFormat_COUNT)
  150. {
  151. format = detailTexFormat;
  152. }
  153. mDetailTextureArray->set(detailTexSize, detailTexSize, detailTexArraySize, format);
  154. }
  155. const U32 macroTexSize = Con::getIntVariable("Terrain::MacroTextureSize");
  156. const GFXFormat macroTexFormat = static_cast<GFXFormat>(Con::getIntVariable("Terrain::MacroTextureFormat"));
  157. if (macroTexSize != 0)
  158. {
  159. GFXFormat format = GFXFormatR8G8B8A8;
  160. if (macroTexFormat < GFXFormat_COUNT)
  161. {
  162. format = macroTexFormat;
  163. }
  164. mMacroTextureArray->set(macroTexSize, macroTexSize, macroTexArraySize, format);
  165. }
  166. const U32 normalTexSize = Con::getIntVariable("Terrain::NormalTextureSize");
  167. const GFXFormat normalTexFormat = static_cast<GFXFormat>(Con::getIntVariable("Terrain::NormalTextureFormat"));
  168. if (normalTexSize != 0)
  169. {
  170. GFXFormat format = GFXFormatR8G8B8A8;
  171. if (normalTexFormat < GFXFormat_COUNT)
  172. {
  173. format = normalTexFormat;
  174. }
  175. mNormalTextureArray->set(normalTexSize, normalTexSize, normalTexArraySize, format);
  176. }
  177. const U32 ormTexSize = Con::getIntVariable("Terrain::OrmTextureSize");
  178. const GFXFormat ormTexFormat = static_cast<GFXFormat>(Con::getIntVariable("Terrain::OrmTextureFormat"));
  179. if (ormTexSize != 0)
  180. {
  181. GFXFormat format = GFXFormatR8G8B8A8;
  182. if (ormTexFormat < GFXFormat_COUNT)
  183. {
  184. format = ormTexFormat;
  185. }
  186. mOrmTextureArray->set(ormTexSize, ormTexSize, ormTexArraySize, format);
  187. }
  188. if (!mDetailTextureArray->fromTextureArray(detailTexArray, detailTexArraySize))
  189. {
  190. Con::errorf("TerrainBlock::_updateMaterials - an issue with the diffuse terrain materials was detected. Please ensure they are all of the same size and format!");
  191. }
  192. if (!mMacroTextureArray->fromTextureArray(macroTexArray, macroTexArraySize))
  193. {
  194. Con::errorf("TerrainBlock::_updateMaterials - an issue with the detail terrain materials was detected. Please ensure they are all of the same size and format!");
  195. }
  196. if (!mNormalTextureArray->fromTextureArray(normalTexArray, normalTexArraySize))
  197. {
  198. Con::errorf("TerrainBlock::_updateMaterials - an issue with the normal terrain materials was detected. Please ensure they are all of the same size and format!");
  199. }
  200. if (!mOrmTextureArray->fromTextureArray(ormTexArray, ormTexArraySize))
  201. {
  202. Con::errorf("TerrainBlock::_updateMaterials - an issue with the orm terrain materials was detected. Please ensure they are all of the same size and format!");
  203. }
  204. if ( mCell )
  205. mCell->deleteMaterials();
  206. }
  207. void TerrainBlock::_updateLayerTexture()
  208. {
  209. const U32 layerSize = mFile->mSize;
  210. const Vector<U8> &layerMap = mFile->mLayerMap;
  211. const U32 pixelCount = layerMap.size();
  212. if ( mLayerTex.isNull() ||
  213. mLayerTex.getWidth() != layerSize ||
  214. mLayerTex.getHeight() != layerSize )
  215. mLayerTex.set( layerSize, layerSize, GFXFormatB8G8R8A8, &TerrainLayerTexProfile, "" );
  216. AssertFatal( mLayerTex.getWidth() == layerSize &&
  217. mLayerTex.getHeight() == layerSize,
  218. "TerrainBlock::_updateLayerTexture - The texture size doesn't match the requested size!" );
  219. // Update the layer texture.
  220. GFXLockedRect *lock = mLayerTex.lock();
  221. for ( U32 i=0; i < pixelCount; i++ )
  222. {
  223. lock->bits[0] = layerMap[i];
  224. if ( i + 1 >= pixelCount )
  225. lock->bits[1] = lock->bits[0];
  226. else
  227. lock->bits[1] = layerMap[i+1];
  228. if ( i + layerSize >= pixelCount )
  229. lock->bits[2] = lock->bits[0];
  230. else
  231. lock->bits[2] = layerMap[i + layerSize];
  232. if ( i + layerSize + 1 >= pixelCount )
  233. lock->bits[3] = lock->bits[0];
  234. else
  235. lock->bits[3] = layerMap[i + layerSize + 1];
  236. lock->bits += 4;
  237. }
  238. mLayerTex.unlock();
  239. //mLayerTex->dumpToDisk( "png", "./layerTex.png" );
  240. }
  241. bool TerrainBlock::_initBaseShader()
  242. {
  243. ShaderData *shaderData = NULL;
  244. if ( !Sim::findObject( "TerrainBlendShader", shaderData ) || !shaderData )
  245. return false;
  246. mBaseShader = shaderData->getShader();
  247. mBaseShaderConsts = mBaseShader->allocConstBuffer();
  248. mBaseTexScaleConst = mBaseShader->getShaderConstHandle( "$texScale" );
  249. mBaseTexIdConst = mBaseShader->getShaderConstHandle( "$texId" );
  250. mBaseLayerSizeConst = mBaseShader->getShaderConstHandle( "$layerSize" );
  251. mBaseTarget = GFX->allocRenderToTextureTarget();
  252. GFXStateBlockDesc desc;
  253. desc.samplersDefined = true;
  254. desc.samplers[0] = GFXSamplerStateDesc::getClampPoint();
  255. desc.samplers[1] = GFXSamplerStateDesc::getWrapLinear();
  256. desc.zDefined = true;
  257. desc.zWriteEnable = false;
  258. desc.zEnable = false;
  259. desc.setBlend( true, GFXBlendSrcAlpha, GFXBlendOne );
  260. desc.cullDefined = true;
  261. desc.cullMode = GFXCullNone;
  262. desc.colorWriteAlpha = false;
  263. mBaseShaderSB = GFX->createStateBlock( desc );
  264. return true;
  265. }
  266. void TerrainBlock::_updateBaseTexture(bool writeToCache)
  267. {
  268. if ( !mBaseShader && !_initBaseShader() )
  269. return;
  270. // This can sometimes occur outside a begin/end scene.
  271. const bool sceneBegun = GFX->canCurrentlyRender();
  272. if ( !sceneBegun )
  273. GFX->beginScene();
  274. GFXDEBUGEVENT_SCOPE( TerrainBlock_UpdateBaseTexture, ColorI::GREEN );
  275. PROFILE_SCOPE( TerrainBlock_UpdateBaseTexture );
  276. GFXTransformSaver saver;
  277. const U32 maxTextureSize = GFX->getCardProfiler()->queryProfile( "maxTextureSize", 1024 );
  278. U32 baseTexSize = getNextPow2( mBaseTexSize );
  279. baseTexSize = getMin( maxTextureSize, baseTexSize );
  280. Point2I destSize( baseTexSize, baseTexSize );
  281. // Setup geometry
  282. GFXVertexBufferHandle<GFXVertexPT> vb;
  283. {
  284. F32 copyOffsetX = 2.0f * GFX->getFillConventionOffset() / (F32)destSize.x;
  285. F32 copyOffsetY = 2.0f * GFX->getFillConventionOffset() / (F32)destSize.y;
  286. GFXVertexPT points[4];
  287. points[0].point = Point3F(1.0 - copyOffsetX, -1.0 + copyOffsetY, 0.0);
  288. points[0].texCoord = Point2F(1.0, 1.0f);
  289. points[1].point = Point3F(1.0 - copyOffsetX, 1.0 + copyOffsetY, 0.0);
  290. points[1].texCoord = Point2F(1.0, 0.0f);
  291. points[2].point = Point3F(-1.0 - copyOffsetX, -1.0 + copyOffsetY, 0.0);
  292. points[2].texCoord = Point2F(0.0, 1.0f);
  293. points[3].point = Point3F(-1.0 - copyOffsetX, 1.0 + copyOffsetY, 0.0);
  294. points[3].texCoord = Point2F(0.0, 0.0f);
  295. vb.set( GFX, 4, GFXBufferTypeVolatile );
  296. GFXVertexPT *ptr = vb.lock();
  297. if(ptr)
  298. {
  299. dMemcpy( ptr, points, sizeof(GFXVertexPT) * 4 );
  300. vb.unlock();
  301. }
  302. }
  303. GFXTexHandle blendTex;
  304. // If the base texture is already a valid render target then
  305. // use it to render to else we create one.
  306. if ( mBaseTex.isValid() &&
  307. mBaseTex->isRenderTarget() &&
  308. mBaseTex->getFormat() == GFXFormatR8G8B8A8_SRGB &&
  309. mBaseTex->getWidth() == destSize.x &&
  310. mBaseTex->getHeight() == destSize.y )
  311. blendTex = mBaseTex;
  312. else
  313. blendTex.set( destSize.x, destSize.y, GFXFormatR8G8B8A8_SRGB, &GFXRenderTargetSRGBProfile, "" );
  314. GFX->pushActiveRenderTarget();
  315. // Set our shader stuff
  316. GFX->setShader( mBaseShader );
  317. GFX->setShaderConstBuffer( mBaseShaderConsts );
  318. GFX->setStateBlock( mBaseShaderSB );
  319. GFX->setVertexBuffer( vb );
  320. mBaseTarget->attachTexture( GFXTextureTarget::Color0, blendTex );
  321. GFX->setActiveRenderTarget( mBaseTarget );
  322. GFX->clear( GFXClearTarget, ColorI(0,0,0,255), 1.0f, 0 );
  323. GFX->setTexture( 0, mLayerTex );
  324. mBaseShaderConsts->setSafe( mBaseLayerSizeConst, (F32)mLayerTex->getWidth() );
  325. for ( U32 i=0; i < mBaseTextures.size(); i++ )
  326. {
  327. GFXTextureObject *tex = mBaseTextures[i];
  328. if ( !tex )
  329. continue;
  330. GFX->setTexture( 1, tex );
  331. F32 baseSize = mFile->mMaterials[i]->getDiffuseSize();
  332. F32 scale = 1.0f;
  333. if ( !mIsZero( baseSize ) )
  334. scale = getWorldBlockSize() / baseSize;
  335. // A mistake early in development means that texture
  336. // coords are not flipped correctly. To compensate
  337. // we flip the y scale here.
  338. mBaseShaderConsts->setSafe( mBaseTexScaleConst, Point2F( scale, -scale ) );
  339. mBaseShaderConsts->setSafe( mBaseTexIdConst, (F32)i );
  340. GFX->drawPrimitive( GFXTriangleStrip, 0, 2 );
  341. }
  342. mBaseTarget->resolve();
  343. GFX->setShader( NULL );
  344. //GFX->setStateBlock( NULL ); // WHY NOT?
  345. GFX->setShaderConstBuffer( NULL );
  346. GFX->setVertexBuffer( NULL );
  347. GFX->popActiveRenderTarget();
  348. // End it if we begun it... Yeehaw!
  349. if ( !sceneBegun )
  350. GFX->endScene();
  351. /// Do we cache this sucker?
  352. if (mBaseTexFormat == NONE || !writeToCache)
  353. {
  354. // We didn't cache the result, so set the base texture
  355. // to the render target we updated. This should be good
  356. // for realtime painting cases.
  357. mBaseTex = blendTex;
  358. }
  359. else if (mBaseTexFormat == DDS)
  360. {
  361. String cachePath = _getBaseTexCacheFileName();
  362. FileStream fs;
  363. if ( fs.open( _getBaseTexCacheFileName(), Torque::FS::File::Write ) )
  364. {
  365. // Read back the render target, dxt compress it, and write it to disk.
  366. GBitmap blendBmp( destSize.x, destSize.y, false, GFXFormatR8G8B8A8 );
  367. blendTex.copyToBmp( &blendBmp );
  368. /*
  369. // Test code for dumping uncompressed bitmap to disk.
  370. {
  371. FileStream fs;
  372. if ( fs.open( "./basetex.png", Torque::FS::File::Write ) )
  373. {
  374. blendBmp.writeBitmap( "png", fs );
  375. fs.close();
  376. }
  377. }
  378. */
  379. blendBmp.extrudeMipLevels();
  380. DDSFile *blendDDS = DDSFile::createDDSFileFromGBitmap( &blendBmp );
  381. ImageUtil::ddsCompress( blendDDS, GFXFormatBC1 );
  382. // Write result to file stream
  383. blendDDS->write( fs );
  384. delete blendDDS;
  385. }
  386. fs.close();
  387. }
  388. else
  389. {
  390. FileStream stream;
  391. if (!stream.open(_getBaseTexCacheFileName(), Torque::FS::File::Write))
  392. {
  393. mBaseTex = blendTex;
  394. return;
  395. }
  396. GBitmap bitmap(blendTex->getWidth(), blendTex->getHeight(), false, GFXFormatR8G8B8A8);
  397. blendTex->copyToBmp(&bitmap);
  398. bitmap.writeBitmap(formatToExtension(mBaseTexFormat), stream);
  399. }
  400. }
  401. void TerrainBlock::_renderBlock( SceneRenderState *state )
  402. {
  403. PROFILE_SCOPE( TerrainBlock_RenderBlock );
  404. if (!mFile)
  405. return;
  406. // Prevent rendering shadows if feature is disabled
  407. if ( !mCastShadows && state->isShadowPass() )
  408. return;
  409. MatrixF worldViewXfm = state->getWorldViewMatrix();
  410. worldViewXfm.mul( getRenderTransform() );
  411. MatrixF worldViewProjXfm = state->getProjectionMatrix();
  412. worldViewProjXfm.mul( worldViewXfm );
  413. const MatrixF &objectXfm = getRenderWorldTransform();
  414. Point3F objCamPos = state->getDiffuseCameraPosition();
  415. objectXfm.mulP( objCamPos );
  416. // Get the shadow material.
  417. if ( !mDefaultMatInst )
  418. mDefaultMatInst = TerrainCellMaterial::getShadowMat();
  419. // Make sure we have a base material.
  420. if ( !mBaseMaterial )
  421. {
  422. mBaseMaterial = new TerrainCellMaterial();
  423. mBaseMaterial->init( this, 0, false, false, true );
  424. }
  425. // Did the detail layers change?
  426. if ( mDetailsDirty )
  427. {
  428. _updateMaterials();
  429. mDetailsDirty = false;
  430. }
  431. // If the layer texture has been cleared or is
  432. // dirty then update it.
  433. if ( mLayerTex.isNull() || mLayerTexDirty )
  434. _updateLayerTexture();
  435. // If the layer texture is dirty or we lost the base
  436. // texture then regenerate it.
  437. if ( mLayerTexDirty || mBaseTex.isNull() )
  438. {
  439. _updateBaseTexture( false );
  440. mLayerTexDirty = false;
  441. }
  442. static Vector<TerrCell*> renderCells;
  443. renderCells.clear();
  444. mCell->cullCells( state,
  445. objCamPos,
  446. &renderCells );
  447. RenderPassManager *renderPass = state->getRenderPass();
  448. MatrixF *riObjectToWorldXfm = renderPass->allocUniqueXform( getRenderTransform() );
  449. const bool isColorDrawPass = state->isDiffusePass() || state->isReflectPass();
  450. // This is here for shadows mostly... it allows the
  451. // proper shadow material to be generated.
  452. BaseMatInstance *defaultMatInst = state->getOverrideMaterial( mDefaultMatInst );
  453. // Only pass and use the light manager if this is not a shadow pass.
  454. LightManager *lm = NULL;
  455. if ( isColorDrawPass )
  456. lm = LIGHTMGR;
  457. #ifdef TORQUE_AFX_ENABLED
  458. bool has_zodiacs = afxZodiacMgr::doesBlockContainZodiacs(state, this);
  459. #endif
  460. for ( U32 i=0; i < renderCells.size(); i++ )
  461. {
  462. TerrCell *cell = renderCells[i];
  463. // Ok this cell is fit to render.
  464. TerrainRenderInst *inst = renderPass->allocInst<TerrainRenderInst>();
  465. // Setup lights for this cell.
  466. if ( lm )
  467. {
  468. SphereF bounds = cell->getSphereBounds();
  469. getRenderTransform().mulP( bounds.center );
  470. LightQuery query;
  471. query.init( bounds );
  472. query.getLights( inst->lights, 8 );
  473. }
  474. GFXVertexBufferHandleBase vertBuff;
  475. GFXPrimitiveBufferHandle primBuff;
  476. cell->getRenderPrimitive( &inst->prim, &vertBuff, &primBuff );
  477. inst->mat = defaultMatInst;
  478. inst->vertBuff = vertBuff.getPointer();
  479. if ( primBuff.isValid() )
  480. {
  481. // Use the cell's custom primitive buffer
  482. inst->primBuff = primBuff.getPointer();
  483. }
  484. else
  485. {
  486. // Use the standard primitive buffer for this cell
  487. inst->primBuff = mPrimBuffer.getPointer();
  488. }
  489. inst->objectToWorldXfm = riObjectToWorldXfm;
  490. // If we're not drawing to the shadow map then we need
  491. // to include the normal rendering materials.
  492. if ( isColorDrawPass )
  493. {
  494. const SphereF &bounds = cell->getSphereBounds();
  495. F32 sqDist = ( bounds.center - objCamPos ).lenSquared();
  496. F32 radiusSq = mSquared( ( mMaxDetailDistance + bounds.radius ) * smDetailScale );
  497. // If this cell is near enough to get detail textures then
  498. // use the full detail mapping material. Else we use the
  499. // simple base only material.
  500. if ( !state->isReflectPass() && sqDist < radiusSq )
  501. inst->cellMat = cell->getMaterial();
  502. else if ( state->isReflectPass() )
  503. inst->cellMat = mBaseMaterial->getReflectMat();
  504. else
  505. inst->cellMat = mBaseMaterial;
  506. }
  507. inst->defaultKey = (U32)cell->getMaterials();
  508. #ifdef TORQUE_AFX_ENABLED
  509. if (has_zodiacs)
  510. afxZodiacMgr::renderTerrainZodiacs(state, this, cell);
  511. // Submit it for rendering.
  512. #endif
  513. renderPass->addInst( inst );
  514. }
  515. // Trigger the debug rendering.
  516. if ( state->isDiffusePass() &&
  517. !renderCells.empty() &&
  518. smDebugRender )
  519. {
  520. // Store the render cells for later.
  521. mDebugCells = renderCells;
  522. ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
  523. ri->renderDelegate.bind( this, &TerrainBlock::_renderDebug );
  524. ri->type = RenderPassManager::RIT_Editor;
  525. state->getRenderPass()->addInst( ri );
  526. }
  527. }
  528. void TerrainBlock::_renderDebug( ObjectRenderInst *ri,
  529. SceneRenderState *state,
  530. BaseMatInstance *overrideMat )
  531. {
  532. GFXTransformSaver saver;
  533. GFX->multWorld( getRenderTransform() );
  534. for ( U32 i=0; i < mDebugCells.size(); i++ )
  535. mDebugCells[i]->renderBounds();
  536. mDebugCells.clear();
  537. }