terrRender.cpp 16 KB

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