terrRender.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  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. mBaseTextures.setSize( mFile->mMaterials.size() );
  72. mMaxDetailDistance = 0.0f;
  73. for ( U32 i=0; i < mFile->mMaterials.size(); i++ )
  74. {
  75. TerrainMaterial *mat = mFile->mMaterials[i];
  76. if (!mat->getDiffuseMap().isEmpty())
  77. {
  78. mBaseTextures[i].set(mat->getDiffuseMap(), &GFXStaticTextureSRGBProfile,
  79. "TerrainBlock::_updateMaterials() - DiffuseMap");
  80. }
  81. else
  82. mBaseTextures[ i ] = GFXTexHandle();
  83. // Find the maximum detail distance.
  84. if ( mat->getDetailMap().isNotEmpty() &&
  85. mat->getDetailDistance() > mMaxDetailDistance )
  86. mMaxDetailDistance = mat->getDetailDistance();
  87. if ( mat->getMacroMap().isNotEmpty() &&
  88. mat->getMacroDistance() > mMaxDetailDistance )
  89. mMaxDetailDistance = mat->getMacroDistance();
  90. }
  91. if ( mCell )
  92. mCell->deleteMaterials();
  93. }
  94. void TerrainBlock::_updateLayerTexture()
  95. {
  96. const U32 layerSize = mFile->mSize;
  97. const Vector<U8> &layerMap = mFile->mLayerMap;
  98. const U32 pixelCount = layerMap.size();
  99. if ( mLayerTex.isNull() ||
  100. mLayerTex.getWidth() != layerSize ||
  101. mLayerTex.getHeight() != layerSize )
  102. mLayerTex.set( layerSize, layerSize, GFXFormatB8G8R8A8, &TerrainLayerTexProfile, "" );
  103. AssertFatal( mLayerTex.getWidth() == layerSize &&
  104. mLayerTex.getHeight() == layerSize,
  105. "TerrainBlock::_updateLayerTexture - The texture size doesn't match the requested size!" );
  106. // Update the layer texture.
  107. GFXLockedRect *lock = mLayerTex.lock();
  108. for ( U32 i=0; i < pixelCount; i++ )
  109. {
  110. lock->bits[0] = layerMap[i];
  111. if ( i + 1 >= pixelCount )
  112. lock->bits[1] = lock->bits[0];
  113. else
  114. lock->bits[1] = layerMap[i+1];
  115. if ( i + layerSize >= pixelCount )
  116. lock->bits[2] = lock->bits[0];
  117. else
  118. lock->bits[2] = layerMap[i + layerSize];
  119. if ( i + layerSize + 1 >= pixelCount )
  120. lock->bits[3] = lock->bits[0];
  121. else
  122. lock->bits[3] = layerMap[i + layerSize + 1];
  123. lock->bits += 4;
  124. }
  125. mLayerTex.unlock();
  126. //mLayerTex->dumpToDisk( "png", "./layerTex.png" );
  127. }
  128. bool TerrainBlock::_initBaseShader()
  129. {
  130. ShaderData *shaderData = NULL;
  131. if ( !Sim::findObject( "TerrainBlendShader", shaderData ) || !shaderData )
  132. return false;
  133. mBaseShader = shaderData->getShader();
  134. mBaseShaderConsts = mBaseShader->allocConstBuffer();
  135. mBaseTexScaleConst = mBaseShader->getShaderConstHandle( "$texScale" );
  136. mBaseTexIdConst = mBaseShader->getShaderConstHandle( "$texId" );
  137. mBaseLayerSizeConst = mBaseShader->getShaderConstHandle( "$layerSize" );
  138. mBaseTarget = GFX->allocRenderToTextureTarget();
  139. GFXStateBlockDesc desc;
  140. desc.samplersDefined = true;
  141. desc.samplers[0] = GFXSamplerStateDesc::getClampPoint();
  142. desc.samplers[1] = GFXSamplerStateDesc::getWrapLinear();
  143. desc.zDefined = true;
  144. desc.zWriteEnable = false;
  145. desc.zEnable = false;
  146. desc.setBlend( true, GFXBlendSrcAlpha, GFXBlendOne );
  147. desc.cullDefined = true;
  148. desc.cullMode = GFXCullNone;
  149. desc.colorWriteAlpha = false;
  150. mBaseShaderSB = GFX->createStateBlock( desc );
  151. return true;
  152. }
  153. void TerrainBlock::_updateBaseTexture(bool writeToCache)
  154. {
  155. if ( !mBaseShader && !_initBaseShader() )
  156. return;
  157. // This can sometimes occur outside a begin/end scene.
  158. const bool sceneBegun = GFX->canCurrentlyRender();
  159. if ( !sceneBegun )
  160. GFX->beginScene();
  161. GFXDEBUGEVENT_SCOPE( TerrainBlock_UpdateBaseTexture, ColorI::GREEN );
  162. PROFILE_SCOPE( TerrainBlock_UpdateBaseTexture );
  163. GFXTransformSaver saver;
  164. const U32 maxTextureSize = GFX->getCardProfiler()->queryProfile( "maxTextureSize", 1024 );
  165. U32 baseTexSize = getNextPow2( mBaseTexSize );
  166. baseTexSize = getMin( maxTextureSize, baseTexSize );
  167. Point2I destSize( baseTexSize, baseTexSize );
  168. // Setup geometry
  169. GFXVertexBufferHandle<GFXVertexPT> vb;
  170. {
  171. F32 copyOffsetX = 2.0f * GFX->getFillConventionOffset() / (F32)destSize.x;
  172. F32 copyOffsetY = 2.0f * GFX->getFillConventionOffset() / (F32)destSize.y;
  173. GFXVertexPT points[4];
  174. points[0].point = Point3F(1.0 - copyOffsetX, -1.0 + copyOffsetY, 0.0);
  175. points[0].texCoord = Point2F(1.0, 1.0f);
  176. points[1].point = Point3F(1.0 - copyOffsetX, 1.0 + copyOffsetY, 0.0);
  177. points[1].texCoord = Point2F(1.0, 0.0f);
  178. points[2].point = Point3F(-1.0 - copyOffsetX, -1.0 + copyOffsetY, 0.0);
  179. points[2].texCoord = Point2F(0.0, 1.0f);
  180. points[3].point = Point3F(-1.0 - copyOffsetX, 1.0 + copyOffsetY, 0.0);
  181. points[3].texCoord = Point2F(0.0, 0.0f);
  182. vb.set( GFX, 4, GFXBufferTypeVolatile );
  183. GFXVertexPT *ptr = vb.lock();
  184. if(ptr)
  185. {
  186. dMemcpy( ptr, points, sizeof(GFXVertexPT) * 4 );
  187. vb.unlock();
  188. }
  189. }
  190. GFXTexHandle blendTex;
  191. // If the base texture is already a valid render target then
  192. // use it to render to else we create one.
  193. if ( mBaseTex.isValid() &&
  194. mBaseTex->isRenderTarget() &&
  195. mBaseTex->getFormat() == GFXFormatR8G8B8A8_SRGB &&
  196. mBaseTex->getWidth() == destSize.x &&
  197. mBaseTex->getHeight() == destSize.y )
  198. blendTex = mBaseTex;
  199. else
  200. blendTex.set( destSize.x, destSize.y, GFXFormatR8G8B8A8_SRGB, &GFXRenderTargetSRGBProfile, "" );
  201. GFX->pushActiveRenderTarget();
  202. // Set our shader stuff
  203. GFX->setShader( mBaseShader );
  204. GFX->setShaderConstBuffer( mBaseShaderConsts );
  205. GFX->setStateBlock( mBaseShaderSB );
  206. GFX->setVertexBuffer( vb );
  207. mBaseTarget->attachTexture( GFXTextureTarget::Color0, blendTex );
  208. GFX->setActiveRenderTarget( mBaseTarget );
  209. GFX->clear( GFXClearTarget, ColorI(0,0,0,255), 1.0f, 0 );
  210. GFX->setTexture( 0, mLayerTex );
  211. mBaseShaderConsts->setSafe( mBaseLayerSizeConst, (F32)mLayerTex->getWidth() );
  212. for ( U32 i=0; i < mBaseTextures.size(); i++ )
  213. {
  214. GFXTextureObject *tex = mBaseTextures[i];
  215. if ( !tex )
  216. continue;
  217. GFX->setTexture( 1, tex );
  218. F32 baseSize = mFile->mMaterials[i]->getDiffuseSize();
  219. F32 scale = 1.0f;
  220. if ( !mIsZero( baseSize ) )
  221. scale = getWorldBlockSize() / baseSize;
  222. // A mistake early in development means that texture
  223. // coords are not flipped correctly. To compensate
  224. // we flip the y scale here.
  225. mBaseShaderConsts->setSafe( mBaseTexScaleConst, Point2F( scale, -scale ) );
  226. mBaseShaderConsts->setSafe( mBaseTexIdConst, (F32)i );
  227. GFX->drawPrimitive( GFXTriangleStrip, 0, 2 );
  228. }
  229. mBaseTarget->resolve();
  230. GFX->setShader( NULL );
  231. //GFX->setStateBlock( NULL ); // WHY NOT?
  232. GFX->setShaderConstBuffer( NULL );
  233. GFX->setVertexBuffer( NULL );
  234. GFX->popActiveRenderTarget();
  235. // End it if we begun it... Yeehaw!
  236. if ( !sceneBegun )
  237. GFX->endScene();
  238. /// Do we cache this sucker?
  239. if (mBaseTexFormat == NONE || !writeToCache)
  240. {
  241. // We didn't cache the result, so set the base texture
  242. // to the render target we updated. This should be good
  243. // for realtime painting cases.
  244. mBaseTex = blendTex;
  245. }
  246. else if (mBaseTexFormat == DDS)
  247. {
  248. String cachePath = _getBaseTexCacheFileName();
  249. FileStream fs;
  250. if ( fs.open( _getBaseTexCacheFileName(), Torque::FS::File::Write ) )
  251. {
  252. // Read back the render target, dxt compress it, and write it to disk.
  253. GBitmap blendBmp( destSize.x, destSize.y, false, GFXFormatR8G8B8A8 );
  254. blendTex.copyToBmp( &blendBmp );
  255. /*
  256. // Test code for dumping uncompressed bitmap to disk.
  257. {
  258. FileStream fs;
  259. if ( fs.open( "./basetex.png", Torque::FS::File::Write ) )
  260. {
  261. blendBmp.writeBitmap( "png", fs );
  262. fs.close();
  263. }
  264. }
  265. */
  266. blendBmp.extrudeMipLevels();
  267. DDSFile *blendDDS = DDSFile::createDDSFileFromGBitmap( &blendBmp );
  268. ImageUtil::ddsCompress( blendDDS, GFXFormatBC1 );
  269. // Write result to file stream
  270. blendDDS->write( fs );
  271. delete blendDDS;
  272. }
  273. fs.close();
  274. }
  275. else
  276. {
  277. FileStream stream;
  278. if (!stream.open(_getBaseTexCacheFileName(), Torque::FS::File::Write))
  279. {
  280. mBaseTex = blendTex;
  281. return;
  282. }
  283. GBitmap bitmap(blendTex->getWidth(), blendTex->getHeight(), false, GFXFormatR8G8B8A8);
  284. blendTex->copyToBmp(&bitmap);
  285. bitmap.writeBitmap(formatToExtension(mBaseTexFormat), stream);
  286. }
  287. }
  288. void TerrainBlock::_renderBlock( SceneRenderState *state )
  289. {
  290. PROFILE_SCOPE( TerrainBlock_RenderBlock );
  291. // Prevent rendering shadows if feature is disabled
  292. if ( !mCastShadows && state->isShadowPass() )
  293. return;
  294. MatrixF worldViewXfm = state->getWorldViewMatrix();
  295. worldViewXfm.mul( getRenderTransform() );
  296. MatrixF worldViewProjXfm = state->getProjectionMatrix();
  297. worldViewProjXfm.mul( worldViewXfm );
  298. const MatrixF &objectXfm = getRenderWorldTransform();
  299. Point3F objCamPos = state->getDiffuseCameraPosition();
  300. objectXfm.mulP( objCamPos );
  301. // Get the shadow material.
  302. if ( !mDefaultMatInst )
  303. mDefaultMatInst = TerrainCellMaterial::getShadowMat();
  304. // Make sure we have a base material.
  305. if ( !mBaseMaterial )
  306. {
  307. mBaseMaterial = new TerrainCellMaterial();
  308. mBaseMaterial->init( this, 0, false, false, true );
  309. }
  310. // Did the detail layers change?
  311. if ( mDetailsDirty )
  312. {
  313. _updateMaterials();
  314. mDetailsDirty = false;
  315. }
  316. // If the layer texture has been cleared or is
  317. // dirty then update it.
  318. if ( mLayerTex.isNull() || mLayerTexDirty )
  319. _updateLayerTexture();
  320. // If the layer texture is dirty or we lost the base
  321. // texture then regenerate it.
  322. if ( mLayerTexDirty || mBaseTex.isNull() )
  323. {
  324. _updateBaseTexture( false );
  325. mLayerTexDirty = false;
  326. }
  327. static Vector<TerrCell*> renderCells;
  328. renderCells.clear();
  329. mCell->cullCells( state,
  330. objCamPos,
  331. &renderCells );
  332. RenderPassManager *renderPass = state->getRenderPass();
  333. MatrixF *riObjectToWorldXfm = renderPass->allocUniqueXform( getRenderTransform() );
  334. const bool isColorDrawPass = state->isDiffusePass() || state->isReflectPass();
  335. // This is here for shadows mostly... it allows the
  336. // proper shadow material to be generated.
  337. BaseMatInstance *defaultMatInst = state->getOverrideMaterial( mDefaultMatInst );
  338. // Only pass and use the light manager if this is not a shadow pass.
  339. LightManager *lm = NULL;
  340. if ( isColorDrawPass )
  341. lm = LIGHTMGR;
  342. #ifdef TORQUE_AFX_ENABLED
  343. bool has_zodiacs = afxZodiacMgr::doesBlockContainZodiacs(state, this);
  344. #endif
  345. for ( U32 i=0; i < renderCells.size(); i++ )
  346. {
  347. TerrCell *cell = renderCells[i];
  348. // Ok this cell is fit to render.
  349. TerrainRenderInst *inst = renderPass->allocInst<TerrainRenderInst>();
  350. // Setup lights for this cell.
  351. if ( lm )
  352. {
  353. SphereF bounds = cell->getSphereBounds();
  354. getRenderTransform().mulP( bounds.center );
  355. LightQuery query;
  356. query.init( bounds );
  357. query.getLights( inst->lights, 8 );
  358. }
  359. GFXVertexBufferHandleBase vertBuff;
  360. GFXPrimitiveBufferHandle primBuff;
  361. cell->getRenderPrimitive( &inst->prim, &vertBuff, &primBuff );
  362. inst->mat = defaultMatInst;
  363. inst->vertBuff = vertBuff.getPointer();
  364. if ( primBuff.isValid() )
  365. {
  366. // Use the cell's custom primitive buffer
  367. inst->primBuff = primBuff.getPointer();
  368. }
  369. else
  370. {
  371. // Use the standard primitive buffer for this cell
  372. inst->primBuff = mPrimBuffer.getPointer();
  373. }
  374. inst->objectToWorldXfm = riObjectToWorldXfm;
  375. // If we're not drawing to the shadow map then we need
  376. // to include the normal rendering materials.
  377. if ( isColorDrawPass )
  378. {
  379. const SphereF &bounds = cell->getSphereBounds();
  380. F32 sqDist = ( bounds.center - objCamPos ).lenSquared();
  381. F32 radiusSq = mSquared( ( mMaxDetailDistance + bounds.radius ) * smDetailScale );
  382. // If this cell is near enough to get detail textures then
  383. // use the full detail mapping material. Else we use the
  384. // simple base only material.
  385. if ( !state->isReflectPass() && sqDist < radiusSq )
  386. inst->cellMat = cell->getMaterial();
  387. else if ( state->isReflectPass() )
  388. inst->cellMat = mBaseMaterial->getReflectMat();
  389. else
  390. inst->cellMat = mBaseMaterial;
  391. }
  392. inst->defaultKey = (U32)cell->getMaterials();
  393. #ifdef TORQUE_AFX_ENABLED
  394. if (has_zodiacs)
  395. afxZodiacMgr::renderTerrainZodiacs(state, this, cell);
  396. // Submit it for rendering.
  397. #endif
  398. renderPass->addInst( inst );
  399. }
  400. // Trigger the debug rendering.
  401. if ( state->isDiffusePass() &&
  402. !renderCells.empty() &&
  403. smDebugRender )
  404. {
  405. // Store the render cells for later.
  406. mDebugCells = renderCells;
  407. ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
  408. ri->renderDelegate.bind( this, &TerrainBlock::_renderDebug );
  409. ri->type = RenderPassManager::RIT_Editor;
  410. state->getRenderPass()->addInst( ri );
  411. }
  412. }
  413. void TerrainBlock::_renderDebug( ObjectRenderInst *ri,
  414. SceneRenderState *state,
  415. BaseMatInstance *overrideMat )
  416. {
  417. GFXTransformSaver saver;
  418. GFX->multWorld( getRenderTransform() );
  419. for ( U32 i=0; i < mDebugCells.size(); i++ )
  420. mDebugCells[i]->renderBounds();
  421. mDebugCells.clear();
  422. }