terrRender.cpp
Engine/source/terrain/terrRender.cpp
Public Functions
GFX_ImplementTextureProfile(TerrainLayerTexProfile , GFXTextureProfile::DiffuseMap , GFXTextureProfile::PreserveSize</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82da3dd353f9e8b45762fccd85bd4e7cf25a">GFXTextureProfile::Dynamic , GFXTextureProfile::NONE )
Detailed Description
Public Functions
GFX_ImplementTextureProfile(TerrainLayerTexProfile , GFXTextureProfile::DiffuseMap , GFXTextureProfile::PreserveSize</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82da3dd353f9e8b45762fccd85bd4e7cf25a">GFXTextureProfile::Dynamic , GFXTextureProfile::NONE )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 25// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames 26// Copyright (C) 2015 Faust Logic, Inc. 27//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 28 29#include "platform/platform.h" 30#include "terrain/terrRender.h" 31 32#include "terrain/terrData.h" 33#include "terrain/terrCell.h" 34#include "terrain/terrMaterial.h" 35#include "terrain/terrCellMaterial.h" 36#include "materials/shaderData.h" 37 38#include "platform/profiler.h" 39#include "scene/sceneRenderState.h" 40#include "math/util/frustum.h" 41#include "renderInstance/renderPassManager.h" 42#include "renderInstance/renderTerrainMgr.h" 43 44#include "lighting/lightInfo.h" 45#include "lighting/lightManager.h" 46 47#include "materials/matInstance.h" 48#include "materials/materialManager.h" 49#include "materials/matTextureTarget.h" 50#include "shaderGen/conditionerFeature.h" 51 52#include "gfx/gfxDrawUtil.h" 53 54#ifdef TORQUE_AFX_ENABLED 55#include "afx/arcaneFX.h" 56#include "afx/ce/afxZodiacMgr.h" 57#endif 58 59#include "gfx/gfxTransformSaver.h" 60#include "gfx/bitmap/gBitmap.h" 61#include "gfx/bitmap/ddsFile.h" 62#include "gfx/bitmap/imageUtils.h" 63#include "terrain/terrMaterial.h" 64#include "gfx/gfxDebugEvent.h" 65#include "gfx/gfxCardProfile.h" 66#include "core/stream/fileStream.h" 67 68 69bool TerrainBlock::smDebugRender = false; 70 71 72GFX_ImplementTextureProfile( TerrainLayerTexProfile, 73 GFXTextureProfile::DiffuseMap, 74 GFXTextureProfile::PreserveSize | 75 GFXTextureProfile::Dynamic, 76 GFXTextureProfile::NONE ); 77 78 79void TerrainBlock::_onFlushMaterials() 80{ 81 if ( mCell ) 82 mCell->deleteMaterials(); 83 84 SAFE_DELETE( mBaseMaterial ); 85} 86 87void TerrainBlock::_updateMaterials() 88{ 89 if (!mFile) 90 return; 91 92 mBaseTextures.setSize( mFile->mMaterials.size() ); 93 94 mMaxDetailDistance = 0.0f; 95 96 for ( U32 i=0; i < mFile->mMaterials.size(); i++ ) 97 { 98 TerrainMaterial *mat = mFile->mMaterials[i]; 99 100 if (mat->getDiffuseMap().isNotEmpty()) 101 { 102 mBaseTextures[i].set(mat->getDiffuseMap(), &GFXStaticTextureSRGBProfile, 103 "TerrainBlock::_updateMaterials() - DiffuseMap"); 104 } 105 else 106 mBaseTextures[ i ] = GFXTexHandle(); 107 108 // Find the maximum detail distance. 109 if ( mat->getDetailMap().isNotEmpty() && 110 mat->getDetailDistance() > mMaxDetailDistance ) 111 mMaxDetailDistance = mat->getDetailDistance(); 112 113 if ( mat->getMacroMap().isNotEmpty() && 114 mat->getMacroDistance() > mMaxDetailDistance ) 115 mMaxDetailDistance = mat->getMacroDistance(); 116 } 117 118 Vector<GFXTexHandle> detailTexArray; 119 detailTexArray.setSize(mFile->mMaterials.size()); 120 Vector<GFXTexHandle> macroTexArray; 121 macroTexArray.setSize(mFile->mMaterials.size()); 122 Vector<GFXTexHandle> normalTexArray; 123 normalTexArray.setSize(mFile->mMaterials.size()); 124 Vector<GFXTexHandle> ormTexArray; 125 ormTexArray.setSize(mFile->mMaterials.size()); 126 127 for (U32 i = 0; i < mFile->mMaterials.size(); i++) 128 { 129 TerrainMaterial* mat = mFile->mMaterials[i]; 130 GFXTextureProfile* profile = &GFXStaticTextureProfile; 131 if (mat->getIsSRGB()) 132 profile = &GFXStaticTextureSRGBProfile; 133 134 if (mat->getDetailMap().isNotEmpty()) 135 detailTexArray[i] = TEXMGR->createTexture(mat->getDetailMap(), profile); 136 if (mat->getMacroMap().isNotEmpty()) 137 macroTexArray[i] = TEXMGR->createTexture(mat->getMacroMap(), profile); 138 if (mat->getNormalMap().isNotEmpty()) 139 normalTexArray[i] = TEXMGR->createTexture(mat->getNormalMap(), profile); 140 if (mat->getORMConfigMap().isNotEmpty()) 141 ormTexArray[i] = TEXMGR->createTexture(mat->getORMConfigMap(), profile); 142 } 143 144 if (mDetailTextureArray.isNull()) 145 { 146 mDetailTextureArray = GFX->createTextureArray(); 147 } 148 149 if (mMacroTextureArray.isNull()) 150 { 151 mMacroTextureArray = GFX->createTextureArray(); 152 } 153 154 if (mNormalTextureArray.isNull()) 155 { 156 mNormalTextureArray = GFX->createTextureArray(); 157 } 158 159 if (mOrmTextureArray.isNull()) 160 { 161 mOrmTextureArray = GFX->createTextureArray(); 162 } 163 164 U32 detailTexArraySize = detailTexArray.size(); 165 U32 macroTexArraySize = macroTexArray.size(); 166 U32 normalTexArraySize = normalTexArray.size(); 167 U32 ormTexArraySize = ormTexArray.size(); 168#ifdef TORQUE_TOOLS 169 // For performance improvement when adding terrain layers, we always allocate at least 32 textures to the arrays in tool builds 170 detailTexArraySize = mMax(32, detailTexArraySize); 171 macroTexArraySize = mMax(32, macroTexArraySize); 172 normalTexArraySize = mMax(32, normalTexArraySize); 173 ormTexArraySize = mMax(32, ormTexArraySize); 174#endif 175 176 // Format has been explicitly set 177 const U32 detailTexSize = Con::getIntVariable("Terrain::DetailTextureSize"); 178 const GFXFormat detailTexFormat = static_cast<GFXFormat>(Con::getIntVariable("Terrain::DetailTextureFormat")); 179 if (detailTexSize != 0) 180 { 181 GFXFormat format = GFXFormatR8G8B8A8; 182 if (detailTexFormat < GFXFormat_COUNT) 183 { 184 format = detailTexFormat; 185 } 186 mDetailTextureArray->set(detailTexSize, detailTexSize, detailTexArraySize, format); 187 } 188 189 const U32 macroTexSize = Con::getIntVariable("Terrain::MacroTextureSize"); 190 const GFXFormat macroTexFormat = static_cast<GFXFormat>(Con::getIntVariable("Terrain::MacroTextureFormat")); 191 if (macroTexSize != 0) 192 { 193 GFXFormat format = GFXFormatR8G8B8A8; 194 if (macroTexFormat < GFXFormat_COUNT) 195 { 196 format = macroTexFormat; 197 } 198 mMacroTextureArray->set(macroTexSize, macroTexSize, macroTexArraySize, format); 199 } 200 201 const U32 normalTexSize = Con::getIntVariable("Terrain::NormalTextureSize"); 202 const GFXFormat normalTexFormat = static_cast<GFXFormat>(Con::getIntVariable("Terrain::NormalTextureFormat")); 203 if (normalTexSize != 0) 204 { 205 GFXFormat format = GFXFormatR8G8B8A8; 206 if (normalTexFormat < GFXFormat_COUNT) 207 { 208 format = normalTexFormat; 209 } 210 mNormalTextureArray->set(normalTexSize, normalTexSize, normalTexArraySize, format); 211 } 212 213 const U32 ormTexSize = Con::getIntVariable("Terrain::OrmTextureSize"); 214 const GFXFormat ormTexFormat = static_cast<GFXFormat>(Con::getIntVariable("Terrain::OrmTextureFormat")); 215 if (ormTexSize != 0) 216 { 217 GFXFormat format = GFXFormatR8G8B8A8; 218 if (ormTexFormat < GFXFormat_COUNT) 219 { 220 format = ormTexFormat; 221 } 222 mOrmTextureArray->set(ormTexSize, ormTexSize, ormTexArraySize, format); 223 } 224 225 if (!mDetailTextureArray->fromTextureArray(detailTexArray, detailTexArraySize)) 226 { 227 Con::errorf("TerrainBlock::_updateMaterials - an issue with the diffuse terrain materials was detected. Please ensure they are all of the same size and format!"); 228 } 229 230 if (!mMacroTextureArray->fromTextureArray(macroTexArray, macroTexArraySize)) 231 { 232 Con::errorf("TerrainBlock::_updateMaterials - an issue with the detail terrain materials was detected. Please ensure they are all of the same size and format!"); 233 } 234 235 if (!mNormalTextureArray->fromTextureArray(normalTexArray, normalTexArraySize)) 236 { 237 Con::errorf("TerrainBlock::_updateMaterials - an issue with the normal terrain materials was detected. Please ensure they are all of the same size and format!"); 238 } 239 240 if (!mOrmTextureArray->fromTextureArray(ormTexArray, ormTexArraySize)) 241 { 242 Con::errorf("TerrainBlock::_updateMaterials - an issue with the orm terrain materials was detected. Please ensure they are all of the same size and format!"); 243 } 244 245 if ( mCell ) 246 mCell->deleteMaterials(); 247} 248 249void TerrainBlock::_updateLayerTexture() 250{ 251 const U32 layerSize = mFile->mSize; 252 const Vector<U8> &layerMap = mFile->mLayerMap; 253 const U32 pixelCount = layerMap.size(); 254 255 if ( mLayerTex.isNull() || 256 mLayerTex.getWidth() != layerSize || 257 mLayerTex.getHeight() != layerSize ) 258 mLayerTex.set( layerSize, layerSize, GFXFormatB8G8R8A8, &TerrainLayerTexProfile, "" ); 259 260 AssertFatal( mLayerTex.getWidth() == layerSize && 261 mLayerTex.getHeight() == layerSize, 262 "TerrainBlock::_updateLayerTexture - The texture size doesn't match the requested size!" ); 263 264 // Update the layer texture. 265 GFXLockedRect *lock = mLayerTex.lock(); 266 267 for ( U32 i=0; i < pixelCount; i++ ) 268 { 269 lock->bits[0] = layerMap[i]; 270 271 if ( i + 1 >= pixelCount ) 272 lock->bits[1] = lock->bits[0]; 273 else 274 lock->bits[1] = layerMap[i+1]; 275 276 if ( i + layerSize >= pixelCount ) 277 lock->bits[2] = lock->bits[0]; 278 else 279 lock->bits[2] = layerMap[i + layerSize]; 280 281 if ( i + layerSize + 1 >= pixelCount ) 282 lock->bits[3] = lock->bits[0]; 283 else 284 lock->bits[3] = layerMap[i + layerSize + 1]; 285 286 lock->bits += 4; 287 } 288 289 mLayerTex.unlock(); 290 //mLayerTex->dumpToDisk( "png", "./layerTex.png" ); 291} 292 293bool TerrainBlock::_initBaseShader() 294{ 295 ShaderData *shaderData = NULL; 296 if ( !Sim::findObject( "TerrainBlendShader", shaderData ) || !shaderData ) 297 return false; 298 299 mBaseShader = shaderData->getShader(); 300 301 mBaseShaderConsts = mBaseShader->allocConstBuffer(); 302 mBaseTexScaleConst = mBaseShader->getShaderConstHandle( "$texScale" ); 303 mBaseTexIdConst = mBaseShader->getShaderConstHandle( "$texId" ); 304 mBaseLayerSizeConst = mBaseShader->getShaderConstHandle( "$layerSize" ); 305 306 mBaseTarget = GFX->allocRenderToTextureTarget(); 307 308 GFXStateBlockDesc desc; 309 desc.samplersDefined = true; 310 desc.samplers[0] = GFXSamplerStateDesc::getClampPoint(); 311 desc.samplers[1] = GFXSamplerStateDesc::getWrapLinear(); 312 desc.zDefined = true; 313 desc.zWriteEnable = false; 314 desc.zEnable = false; 315 desc.setBlend( true, GFXBlendSrcAlpha, GFXBlendOne ); 316 desc.cullDefined = true; 317 desc.cullMode = GFXCullNone; 318 desc.colorWriteAlpha = false; 319 mBaseShaderSB = GFX->createStateBlock( desc ); 320 321 return true; 322} 323 324void TerrainBlock::_updateBaseTexture(bool writeToCache) 325{ 326 if ( !mBaseShader && !_initBaseShader() ) 327 return; 328 329 // This can sometimes occur outside a begin/end scene. 330 const bool sceneBegun = GFX->canCurrentlyRender(); 331 if ( !sceneBegun ) 332 GFX->beginScene(); 333 334 GFXDEBUGEVENT_SCOPE( TerrainBlock_UpdateBaseTexture, ColorI::GREEN ); 335 336 PROFILE_SCOPE( TerrainBlock_UpdateBaseTexture ); 337 338 GFXTransformSaver saver; 339 340 const U32 maxTextureSize = GFX->getCardProfiler()->queryProfile( "maxTextureSize", 1024 ); 341 342 U32 baseTexSize = getNextPow2( mBaseTexSize ); 343 baseTexSize = getMin( maxTextureSize, baseTexSize ); 344 Point2I destSize( baseTexSize, baseTexSize ); 345 346 // Setup geometry 347 GFXVertexBufferHandle<GFXVertexPT> vb; 348 { 349 F32 copyOffsetX = 2.0f * GFX->getFillConventionOffset() / (F32)destSize.x; 350 F32 copyOffsetY = 2.0f * GFX->getFillConventionOffset() / (F32)destSize.y; 351 352 GFXVertexPT points[4]; 353 points[0].point = Point3F(1.0 - copyOffsetX, -1.0 + copyOffsetY, 0.0); 354 points[0].texCoord = Point2F(1.0, 1.0f); 355 points[1].point = Point3F(1.0 - copyOffsetX, 1.0 + copyOffsetY, 0.0); 356 points[1].texCoord = Point2F(1.0, 0.0f); 357 points[2].point = Point3F(-1.0 - copyOffsetX, -1.0 + copyOffsetY, 0.0); 358 points[2].texCoord = Point2F(0.0, 1.0f); 359 points[3].point = Point3F(-1.0 - copyOffsetX, 1.0 + copyOffsetY, 0.0); 360 points[3].texCoord = Point2F(0.0, 0.0f); 361 362 vb.set( GFX, 4, GFXBufferTypeVolatile ); 363 GFXVertexPT *ptr = vb.lock(); 364 if(ptr) 365 { 366 dMemcpy( ptr, points, sizeof(GFXVertexPT) * 4 ); 367 vb.unlock(); 368 } 369 } 370 371 GFXTexHandle blendTex; 372 373 // If the base texture is already a valid render target then 374 // use it to render to else we create one. 375 if ( mBaseTex.isValid() && 376 mBaseTex->isRenderTarget() && 377 mBaseTex->getFormat() == GFXFormatR8G8B8A8_SRGB && 378 mBaseTex->getWidth() == destSize.x && 379 mBaseTex->getHeight() == destSize.y ) 380 blendTex = mBaseTex; 381 else 382 blendTex.set( destSize.x, destSize.y, GFXFormatR8G8B8A8_SRGB, &GFXRenderTargetSRGBProfile, "" ); 383 384 GFX->pushActiveRenderTarget(); 385 386 // Set our shader stuff 387 GFX->setShader( mBaseShader ); 388 GFX->setShaderConstBuffer( mBaseShaderConsts ); 389 GFX->setStateBlock( mBaseShaderSB ); 390 GFX->setVertexBuffer( vb ); 391 392 mBaseTarget->attachTexture( GFXTextureTarget::Color0, blendTex ); 393 GFX->setActiveRenderTarget( mBaseTarget ); 394 395 GFX->clear( GFXClearTarget, ColorI(0,0,0,255), 1.0f, 0 ); 396 397 GFX->setTexture( 0, mLayerTex ); 398 mBaseShaderConsts->setSafe( mBaseLayerSizeConst, (F32)mLayerTex->getWidth() ); 399 400 for ( U32 i=0; i < mBaseTextures.size(); i++ ) 401 { 402 GFXTextureObject *tex = mBaseTextures[i]; 403 if ( !tex ) 404 continue; 405 406 GFX->setTexture( 1, tex ); 407 408 F32 baseSize = mFile->mMaterials[i]->getDiffuseSize(); 409 F32 scale = 1.0f; 410 if ( !mIsZero( baseSize ) ) 411 scale = getWorldBlockSize() / baseSize; 412 413 // A mistake early in development means that texture 414 // coords are not flipped correctly. To compensate 415 // we flip the y scale here. 416 mBaseShaderConsts->setSafe( mBaseTexScaleConst, Point2F( scale, -scale ) ); 417 mBaseShaderConsts->setSafe( mBaseTexIdConst, (F32)i ); 418 419 GFX->drawPrimitive( GFXTriangleStrip, 0, 2 ); 420 } 421 422 mBaseTarget->resolve(); 423 424 GFX->setShader( NULL ); 425 //GFX->setStateBlock( NULL ); // WHY NOT? 426 GFX->setShaderConstBuffer( NULL ); 427 GFX->setVertexBuffer( NULL ); 428 429 GFX->popActiveRenderTarget(); 430 431 // End it if we begun it... Yeehaw! 432 if ( !sceneBegun ) 433 GFX->endScene(); 434 435 /// Do we cache this sucker? 436 if (mBaseTexFormat == NONE || !writeToCache) 437 { 438 // We didn't cache the result, so set the base texture 439 // to the render target we updated. This should be good 440 // for realtime painting cases. 441 mBaseTex = blendTex; 442 } 443 else if (mBaseTexFormat == DDS) 444 { 445 String cachePath = _getBaseTexCacheFileName(); 446 447 FileStream fs; 448 if ( fs.open( _getBaseTexCacheFileName(), Torque::FS::File::Write ) ) 449 { 450 // Read back the render target, dxt compress it, and write it to disk. 451 GBitmap blendBmp( destSize.x, destSize.y, false, GFXFormatR8G8B8A8 ); 452 blendTex.copyToBmp( &blendBmp ); 453 454 /* 455 // Test code for dumping uncompressed bitmap to disk. 456 { 457 FileStream fs; 458 if ( fs.open( "./basetex.png", Torque::FS::File::Write ) ) 459 { 460 blendBmp.writeBitmap( "png", fs ); 461 fs.close(); 462 } 463 } 464 */ 465 466 blendBmp.extrudeMipLevels(); 467 468 DDSFile *blendDDS = DDSFile::createDDSFileFromGBitmap( &blendBmp ); 469 ImageUtil::ddsCompress( blendDDS, GFXFormatBC1 ); 470 471 // Write result to file stream 472 blendDDS->write( fs ); 473 474 delete blendDDS; 475 } 476 fs.close(); 477 } 478 else 479 { 480 FileStream stream; 481 if (!stream.open(_getBaseTexCacheFileName(), Torque::FS::File::Write)) 482 { 483 mBaseTex = blendTex; 484 return; 485 } 486 487 GBitmap bitmap(blendTex->getWidth(), blendTex->getHeight(), false, GFXFormatR8G8B8A8); 488 blendTex->copyToBmp(&bitmap); 489 bitmap.writeBitmap(formatToExtension(mBaseTexFormat), stream); 490 } 491} 492 493void TerrainBlock::_renderBlock( SceneRenderState *state ) 494{ 495 PROFILE_SCOPE( TerrainBlock_RenderBlock ); 496 497 if (!mFile) 498 return; 499 500 // Prevent rendering shadows if feature is disabled 501 if ( !mCastShadows && state->isShadowPass() ) 502 return; 503 504 MatrixF worldViewXfm = state->getWorldViewMatrix(); 505 worldViewXfm.mul( getRenderTransform() ); 506 507 MatrixF worldViewProjXfm = state->getProjectionMatrix(); 508 worldViewProjXfm.mul( worldViewXfm ); 509 510 const MatrixF &objectXfm = getRenderWorldTransform(); 511 512 Point3F objCamPos = state->getDiffuseCameraPosition(); 513 objectXfm.mulP( objCamPos ); 514 515 // Get the shadow material. 516 if ( !mDefaultMatInst ) 517 mDefaultMatInst = TerrainCellMaterial::getShadowMat(); 518 519 // Make sure we have a base material. 520 if ( !mBaseMaterial ) 521 { 522 mBaseMaterial = new TerrainCellMaterial(); 523 mBaseMaterial->init( this, 0, false, false, true ); 524 } 525 526 // Did the detail layers change? 527 if ( mDetailsDirty ) 528 { 529 _updateMaterials(); 530 mDetailsDirty = false; 531 } 532 533 // If the layer texture has been cleared or is 534 // dirty then update it. 535 if ( mLayerTex.isNull() || mLayerTexDirty ) 536 _updateLayerTexture(); 537 538 // If the layer texture is dirty or we lost the base 539 // texture then regenerate it. 540 if ( mLayerTexDirty || mBaseTex.isNull() ) 541 { 542 _updateBaseTexture( false ); 543 mLayerTexDirty = false; 544 } 545 546 static Vector<TerrCell*> renderCells; 547 renderCells.clear(); 548 549 mCell->cullCells( state, 550 objCamPos, 551 &renderCells ); 552 553 RenderPassManager *renderPass = state->getRenderPass(); 554 555 MatrixF *riObjectToWorldXfm = renderPass->allocUniqueXform( getRenderTransform() ); 556 557 const bool isColorDrawPass = state->isDiffusePass() || state->isReflectPass(); 558 559 // This is here for shadows mostly... it allows the 560 // proper shadow material to be generated. 561 BaseMatInstance *defaultMatInst = state->getOverrideMaterial( mDefaultMatInst ); 562 563 // Only pass and use the light manager if this is not a shadow pass. 564 LightManager *lm = NULL; 565 if ( isColorDrawPass ) 566 lm = LIGHTMGR; 567 568#ifdef TORQUE_AFX_ENABLED 569 bool has_zodiacs = afxZodiacMgr::doesBlockContainZodiacs(state, this); 570#endif 571 for ( U32 i=0; i < renderCells.size(); i++ ) 572 { 573 TerrCell *cell = renderCells[i]; 574 575 // Ok this cell is fit to render. 576 TerrainRenderInst *inst = renderPass->allocInst<TerrainRenderInst>(); 577 578 // Setup lights for this cell. 579 if ( lm ) 580 { 581 SphereF bounds = cell->getSphereBounds(); 582 getRenderTransform().mulP( bounds.center ); 583 584 LightQuery query; 585 query.init( bounds ); 586 query.getLights( inst->lights, 8 ); 587 } 588 589 GFXVertexBufferHandleBase vertBuff; 590 GFXPrimitiveBufferHandle primBuff; 591 592 cell->getRenderPrimitive( &inst->prim, &vertBuff, &primBuff ); 593 594 inst->mat = defaultMatInst; 595 inst->vertBuff = vertBuff.getPointer(); 596 597 if ( primBuff.isValid() ) 598 { 599 // Use the cell's custom primitive buffer 600 inst->primBuff = primBuff.getPointer(); 601 } 602 else 603 { 604 // Use the standard primitive buffer for this cell 605 inst->primBuff = mPrimBuffer.getPointer(); 606 } 607 608 inst->objectToWorldXfm = riObjectToWorldXfm; 609 610 // If we're not drawing to the shadow map then we need 611 // to include the normal rendering materials. 612 if ( isColorDrawPass ) 613 { 614 const SphereF &bounds = cell->getSphereBounds(); 615 616 F32 sqDist = ( bounds.center - objCamPos ).lenSquared(); 617 618 F32 radiusSq = mSquared( ( mMaxDetailDistance + bounds.radius ) * smDetailScale ); 619 620 // If this cell is near enough to get detail textures then 621 // use the full detail mapping material. Else we use the 622 // simple base only material. 623 if ( !state->isReflectPass() && sqDist < radiusSq ) 624 inst->cellMat = cell->getMaterial(); 625 else if ( state->isReflectPass() ) 626 inst->cellMat = mBaseMaterial->getReflectMat(); 627 else 628 inst->cellMat = mBaseMaterial; 629 } 630 631 inst->defaultKey = (U32)cell->getMaterials(); 632#ifdef TORQUE_AFX_ENABLED 633 if (has_zodiacs) 634 afxZodiacMgr::renderTerrainZodiacs(state, this, cell); 635 // Submit it for rendering. 636#endif 637 renderPass->addInst( inst ); 638 } 639 640 // Trigger the debug rendering. 641 if ( state->isDiffusePass() && 642 !renderCells.empty() && 643 smDebugRender ) 644 { 645 // Store the render cells for later. 646 mDebugCells = renderCells; 647 648 ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>(); 649 ri->renderDelegate.bind( this, &TerrainBlock::_renderDebug ); 650 ri->type = RenderPassManager::RIT_Editor; 651 state->getRenderPass()->addInst( ri ); 652 } 653} 654 655void TerrainBlock::_renderDebug( ObjectRenderInst *ri, 656 SceneRenderState *state, 657 BaseMatInstance *overrideMat ) 658{ 659 GFXTransformSaver saver; 660 GFX->multWorld( getRenderTransform() ); 661 662 for ( U32 i=0; i < mDebugCells.size(); i++ ) 663 mDebugCells[i]->renderBounds(); 664 665 mDebugCells.clear(); 666} 667