| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101 | //-----------------------------------------------------------------------------// Copyright (c) 2012 GarageGames, LLC//// Permission is hereby granted, free of charge, to any person obtaining a copy// of this software and associated documentation files (the "Software"), to// deal in the Software without restriction, including without limitation the// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or// sell copies of the Software, and to permit persons to whom the Software is// furnished to do so, subject to the following conditions://// The above copyright notice and this permission notice shall be included in// all copies or substantial portions of the Software.//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS// IN THE SOFTWARE.//-----------------------------------------------------------------------------#include "platform/platform.h"#include "renderInstance/renderDeferredMgr.h"#include "gfx/gfxTransformSaver.h"#include "materials/sceneData.h"#include "materials/materialManager.h"#include "materials/materialFeatureTypes.h"#include "core/util/safeDelete.h"#include "shaderGen/featureMgr.h"#include "shaderGen/HLSL/depthHLSL.h"#include "shaderGen/GLSL/depthGLSL.h"#include "shaderGen/conditionerFeature.h"#include "shaderGen/shaderGenVars.h"#include "scene/sceneRenderState.h"#include "gfx/gfxStringEnumTranslate.h"#include "gfx/gfxDebugEvent.h"#include "gfx/gfxCardProfile.h"#include "materials/customMaterialDefinition.h"#include "lighting/advanced/advancedLightManager.h"#include "lighting/advanced/advancedLightBinManager.h"#include "terrain/terrCell.h"#include "renderInstance/renderTerrainMgr.h"#include "terrain/terrCellMaterial.h"#include "math/mathUtils.h"#include "math/util/matrixSet.h"#include "gfx/gfxTextureManager.h"#include "gfx/primBuilder.h"#include "gfx/gfxDrawUtil.h"#include "materials/shaderData.h"#include "gfx/sim/cubemapData.h"#include "materials/customShaderBindingData.h"const MatInstanceHookType DeferredMatInstanceHook::Type( "Deferred" );const String RenderDeferredMgr::BufferName("deferred");const RenderInstType RenderDeferredMgr::RIT_Deferred("Deferred");const String RenderDeferredMgr::ColorBufferName("color");const String RenderDeferredMgr::MatInfoBufferName("matinfo");IMPLEMENT_CONOBJECT(RenderDeferredMgr);ConsoleDocClass( RenderDeferredMgr,    "@brief The render bin which performs a z+normals deferred used in Advanced Lighting.\n\n"   "This render bin is used in Advanced Lighting to gather all opaque mesh render instances "   "and render them to the g-buffer for use in lighting the scene and doing effects.\n\n"   "PostEffect and other shaders can access the output of this bin by using the #deferred "   "texture target name.  See the edge anti-aliasing post effect for an example.\n\n"   "@see game/core/scripts/client/postFx/edgeAA." TORQUE_SCRIPT_EXTENSION "\n"   "@ingroup RenderBin\n" );RenderDeferredMgr::RenderSignal& RenderDeferredMgr::getRenderSignal(){   static RenderSignal theSignal;   return theSignal;}RenderDeferredMgr::RenderDeferredMgr( bool gatherDepth,                                    GFXFormat format )   :  Parent(  RIT_Deferred,               0.01f,               0.01f,               format,               Point2I( Parent::DefaultTargetSize, Parent::DefaultTargetSize),               gatherDepth ? Parent::DefaultTargetChainLength : 0 ),      mDeferredMatInstance( NULL ){   notifyType( RenderPassManager::RIT_Decal );   notifyType( RenderPassManager::RIT_DecalRoad );   notifyType( RenderPassManager::RIT_Mesh );   notifyType( RenderPassManager::RIT_Terrain );   notifyType( RenderPassManager::RIT_Object );   notifyType( RenderPassManager::RIT_Probes );   // We want a full-resolution buffer   mTargetSizeType = RenderTexTargetBinManager::WindowSize;   if(getTargetChainLength() > 0)      GFXShader::addGlobalMacro( "TORQUE_LINEAR_DEPTH" );   mNamedTarget.registerWithName( BufferName );   mColorTarget.registerWithName( ColorBufferName );   mMatInfoTarget.registerWithName( MatInfoBufferName );   _registerFeatures();}RenderDeferredMgr::~RenderDeferredMgr(){   GFXShader::removeGlobalMacro( "TORQUE_LINEAR_DEPTH" );   mColorTarget.release();   mMatInfoTarget.release();   _unregisterFeatures();   SAFE_DELETE( mDeferredMatInstance );}void RenderDeferredMgr::_registerFeatures(){   ConditionerFeature *cond = new LinearEyeDepthConditioner( getTargetFormat() );   FEATUREMGR->registerFeature( MFT_DeferredConditioner, cond );   mNamedTarget.setConditioner( cond );}void RenderDeferredMgr::_unregisterFeatures(){   mNamedTarget.setConditioner( NULL );   FEATUREMGR->unregisterFeature(MFT_DeferredConditioner);}bool RenderDeferredMgr::setTargetSize(const Point2I &newTargetSize){   bool ret = Parent::setTargetSize( newTargetSize );   mNamedTarget.setViewport( GFX->getViewport() );   mColorTarget.setViewport( GFX->getViewport() );   mMatInfoTarget.setViewport( GFX->getViewport() );   return ret;}bool RenderDeferredMgr::_updateTargets(){   PROFILE_SCOPE(RenderDeferredMgr_updateTargets);   bool ret = Parent::_updateTargets();   // check for an output conditioner, and update it's format   ConditionerFeature *outputConditioner = dynamic_cast<ConditionerFeature *>(FEATUREMGR->getByType(MFT_DeferredConditioner));   if( outputConditioner && outputConditioner->setBufferFormat(mTargetFormat) )   {      // reload materials, the conditioner needs to alter the generated shaders   }   // TODO: these formats should be passed in and not hard-coded   const GFXFormat colorFormat = GFXFormatR8G8B8A8_SRGB;   const GFXFormat matInfoFormat = GFXFormatR8G8B8A8;   // andrewmac: Deferred Shading Color Buffer   if (mColorTex.getFormat() != colorFormat || mColorTex.getWidthHeight() != mTargetSize || GFX->recentlyReset())   {      mColorTarget.release();      mColorTex.set(mTargetSize.x, mTargetSize.y, colorFormat,         &GFXRenderTargetSRGBProfile, avar("%s() - (line %d)", __FUNCTION__, __LINE__),         1, GFXTextureManager::AA_MATCH_BACKBUFFER);      mColorTarget.setTexture(mColorTex);       for (U32 i = 0; i < mTargetChainLength; i++)         mTargetChain[i]->attachTexture(GFXTextureTarget::Color1, mColorTarget.getTexture());   }    // andrewmac: Deferred Shading Material Info Buffer   if (mMatInfoTex.getFormat() != matInfoFormat || mMatInfoTex.getWidthHeight() != mTargetSize || GFX->recentlyReset())   {      mMatInfoTarget.release();      mMatInfoTex.set(mTargetSize.x, mTargetSize.y, matInfoFormat,         &GFXRenderTargetProfile, avar("%s() - (line %d)", __FUNCTION__, __LINE__),         1, GFXTextureManager::AA_MATCH_BACKBUFFER);      mMatInfoTarget.setTexture(mMatInfoTex);       for (U32 i = 0; i < mTargetChainLength; i++)         mTargetChain[i]->attachTexture(GFXTextureTarget::Color2, mMatInfoTarget.getTexture());   }   //scene color target   NamedTexTargetRef sceneColorTargetRef = NamedTexTarget::find("AL_FormatToken");   if (sceneColorTargetRef.isValid())   {      for (U32 i = 0; i < mTargetChainLength; i++)         mTargetChain[i]->attachTexture(GFXTextureTarget::Color3, sceneColorTargetRef->getTexture(0));   }   else   {      Con::errorf("RenderDeferredMgr: Could not find AL_FormatToken");      return false;   }   GFX->finalizeReset();   return ret;}void RenderDeferredMgr::_createDeferredMaterial(){   SAFE_DELETE(mDeferredMatInstance);   const GFXVertexFormat *vertexFormat = getGFXVertexFormat<GFXVertexPNTTB>();   MatInstance* deferredMat = static_cast<MatInstance*>(MATMGR->createMatInstance("AL_DefaultDeferredMaterial", vertexFormat));   AssertFatal( deferredMat, "TODO: Handle this better." );   mDeferredMatInstance = new DeferredMatInstance(deferredMat, this);   mDeferredMatInstance->init( MATMGR->getDefaultFeatures(), vertexFormat);   delete deferredMat;}void RenderDeferredMgr::setDeferredMaterial( DeferredMatInstance *mat ){   SAFE_DELETE(mDeferredMatInstance);   mDeferredMatInstance = mat;}void RenderDeferredMgr::addElement( RenderInst *inst ){   PROFILE_SCOPE( RenderDeferredMgr_addElement )   // Skip out if this bin is disabled.   if (  gClientSceneGraph->getCurrentRenderState() &&         gClientSceneGraph->getCurrentRenderState()->disableAdvancedLightingBins() )      return;   // First what type of render instance is it?   const bool isDecalMeshInst = ((inst->type == RenderPassManager::RIT_Decal)||(inst->type == RenderPassManager::RIT_DecalRoad));   const bool isMeshInst = inst->type == RenderPassManager::RIT_Mesh;   const bool isTerrainInst = inst->type == RenderPassManager::RIT_Terrain;   const bool isProbeInst = inst->type == RenderPassManager::RIT_Probes;   // Get the material if its a mesh.   BaseMatInstance* matInst = NULL;   if ( isMeshInst || isDecalMeshInst )      matInst = static_cast<MeshRenderInst*>(inst)->matInst;   if (matInst)   {      // If its a custom material and it refracts... skip it.      if (matInst->isCustomMaterial() &&         static_cast<CustomMaterial*>(matInst->getMaterial())->mRefract)         return;      // Make sure we got a deferred material.      matInst = getDeferredMaterial(matInst);      if (!matInst || !matInst->isValid())         return;   }   // We're gonna add it to the bin... get the right element list.   Vector< MainSortElem > *elementList;   if ( isMeshInst || isDecalMeshInst )      elementList = &mElementList;   else if ( isTerrainInst )      elementList = &mTerrainElementList;   else if (isProbeInst)      elementList = &mProbeElementList;   else      elementList = &mObjectElementList;   elementList->increment();   MainSortElem &elem = elementList->last();   elem.inst = inst;   // Store the original key... we might need it.   U32 originalKey = elem.key;   // Sort front-to-back first to get the most fillrate savings.   const F32 invSortDistSq = F32_MAX - inst->sortDistSq;   elem.key = *((U32*)&invSortDistSq);   // Next sort by pre-pass material if its a mesh... use the original sort key.   if (isMeshInst && matInst)      elem.key2 = matInst->getStateHint();   else      elem.key2 = originalKey;}void RenderDeferredMgr::sort(){   PROFILE_SCOPE( RenderDeferredMgr_sort );   Parent::sort();   dQsort( mTerrainElementList.address(), mTerrainElementList.size(), sizeof(MainSortElem), cmpKeyFunc);   dQsort( mObjectElementList.address(), mObjectElementList.size(), sizeof(MainSortElem), cmpKeyFunc);}void RenderDeferredMgr::clear(){   Parent::clear();   mProbeElementList.clear();   mTerrainElementList.clear();   mObjectElementList.clear();}void RenderDeferredMgr::render( SceneRenderState *state ){   PROFILE_SCOPE(RenderDeferredMgr_render);   // Take a look at the SceneRenderState and see if we should skip drawing the pre-pass   if ( state->disableAdvancedLightingBins() )      return;   // NOTE: We don't early out here when the element list is   // zero because we need the deferred to be cleared.   // Automagically save & restore our viewport and transforms.   GFXTransformSaver saver;   GFXDEBUGEVENT_SCOPE( RenderDeferredMgr_Render, ColorI::RED );   // Tell the superclass we're about to render   const bool isRenderingToTarget = _onPreRender(state);   // Clear z-buffer and g-buffer.   GFX->clear(GFXClearZBuffer | GFXClearStencil, LinearColorF::ZERO, 0.0f, 0);   GFX->clearColorAttachment(0, LinearColorF::ONE);//normdepth   GFX->clearColorAttachment(1, LinearColorF::ZERO);//albedo   GFX->clearColorAttachment(2, LinearColorF::ZERO);//matinfo   //AL_FormatToken is cleared by it's own class   // Restore transforms   MatrixSet &matrixSet = getRenderPass()->getMatrixSet();   matrixSet.restoreSceneViewProjection();   const MatrixF worldViewXfm = GFX->getWorldMatrix();   // Setup the default deferred material for object instances.   if ( !mDeferredMatInstance )      _createDeferredMaterial();   if ( mDeferredMatInstance )   {      matrixSet.setWorld(MatrixF::Identity);      mDeferredMatInstance->setTransforms(matrixSet, state);   }   // Signal start of deferred   getRenderSignal().trigger( state, this, true );      // First do a loop and render all the terrain... these are    // usually the big blockers in a scene and will save us fillrate   // on the smaller meshes and objects.   // The terrain doesn't need any scene graph data   // in the the deferred... so just clear it.   SceneData sgData;   sgData.init( state, SceneData::DeferredBin );   Vector< MainSortElem >::const_iterator itr = mTerrainElementList.begin();   for ( ; itr != mTerrainElementList.end(); itr++ )   {      TerrainRenderInst *ri = static_cast<TerrainRenderInst*>( itr->inst );      TerrainCellMaterial *mat = ri->cellMat->getDeferredMat();      GFX->setPrimitiveBuffer( ri->primBuff );      GFX->setVertexBuffer( ri->vertBuff );      mat->setTransformAndEye(   *ri->objectToWorldXfm,                                 worldViewXfm,                                 GFX->getProjectionMatrix(),                                 state->getFarPlane() );      while ( mat->setupPass( state, sgData ) )         GFX->drawPrimitive( ri->prim );   }   // init loop data   GFXTextureObject *lastLM = NULL;   GFXCubemap *lastCubemap = NULL;   GFXTextureObject *lastReflectTex = NULL;   GFXTextureObject *lastAccuTex = NULL;      // Next render all the meshes.   itr = mElementList.begin();   for ( ; itr != mElementList.end(); )   {      MeshRenderInst *ri = static_cast<MeshRenderInst*>( itr->inst );      // Get the deferred material.      BaseMatInstance *mat = getDeferredMaterial( ri->matInst );      // Set up SG data proper like and flag it       // as a pre-pass render      setupSGData( ri, sgData );      Vector< MainSortElem >::const_iterator meshItr, endOfBatchItr = itr;      while ( mat->setupPass( state, sgData ) )      {         meshItr = itr;         for ( ; meshItr != mElementList.end(); meshItr++ )         {            MeshRenderInst *passRI = static_cast<MeshRenderInst*>( meshItr->inst );            // Check to see if we need to break this batch.            //            // NOTE: We're comparing the non-deferred materials             // here so we don't incur the cost of looking up the             // deferred hook on each inst.            //            if ( newPassNeeded( ri, passRI ) )               break;            // Set up SG data for this instance.            setupSGData( passRI, sgData );            mat->setSceneInfo(state, sgData);            matrixSet.setWorld(*passRI->objectToWorld);            matrixSet.setView(*passRI->worldToCamera);            matrixSet.setProjection(*passRI->projection);            mat->setTransforms(matrixSet, state);            // Setup HW skinning transforms if applicable            if (mat->usesHardwareSkinning())            {               mat->setNodeTransforms(passRI->mNodeTransforms, passRI->mNodeTransformCount);            }			   //push along any overriden fields that are instance-specific as well			   if (passRI->mCustomShaderData.size() > 0)			   {				   mat->setCustomShaderData(passRI->mCustomShaderData);			   }            // If we're instanced then don't render yet.            if ( mat->isInstanced() )            {               // Let the material increment the instance buffer, but               // break the batch if it runs out of room for more.               if ( !mat->stepInstance() )               {                  meshItr++;                  break;               }               continue;            }            bool dirty = false;            // set the lightmaps if different            if( passRI->lightmap && passRI->lightmap != lastLM )            {               sgData.lightmap = passRI->lightmap;               lastLM = passRI->lightmap;               dirty = true;            }            // set the cubemap if different.            if ( passRI->cubemap != lastCubemap )            {               sgData.cubemap = passRI->cubemap;               lastCubemap = passRI->cubemap;               dirty = true;            }            if ( passRI->reflectTex != lastReflectTex )            {               sgData.reflectTex = passRI->reflectTex;               lastReflectTex = passRI->reflectTex;               dirty = true;            }                        // Update accumulation texture if it changed.            // Note: accumulation texture can be NULL, and must be updated.            if (passRI->accuTex != lastAccuTex)            {               sgData.accuTex = passRI->accuTex;               lastAccuTex = passRI->accuTex;               dirty = true;            }            if ( dirty )               mat->setTextureStages( state, sgData );            // Setup the vertex and index buffers.            mat->setBuffers( passRI->vertBuff, passRI->primBuff );            // Render this sucker.            if ( passRI->prim )               GFX->drawPrimitive( *passRI->prim );            else               GFX->drawPrimitive( passRI->primBuffIndex );         }         // Draw the instanced batch.         if ( mat->isInstanced() )         {            // Sets the buffers including the instancing stream.            mat->setBuffers( ri->vertBuff, ri->primBuff );            if ( ri->prim )               GFX->drawPrimitive( *ri->prim );            else               GFX->drawPrimitive( ri->primBuffIndex );         }         endOfBatchItr = meshItr;      } // while( mat->setupPass(state, sgData) )      // Force the increment if none happened, otherwise go to end of batch.      itr = ( itr == endOfBatchItr ) ? itr + 1 : endOfBatchItr;   }   // The final loop is for object render instances.   itr = mObjectElementList.begin();   for ( ; itr != mObjectElementList.end(); itr++ )   {      ObjectRenderInst *ri = static_cast<ObjectRenderInst*>( itr->inst );      if ( ri->renderDelegate )         ri->renderDelegate( ri, state, mDeferredMatInstance );   }   // Signal end of pre-pass   getRenderSignal().trigger( state, this, false );   if(isRenderingToTarget)      _onPostRender();}const GFXStateBlockDesc & RenderDeferredMgr::getOpaqueStenciWriteDesc( bool lightmappedGeometry /*= true*/ ){   static bool sbInit = false;   static GFXStateBlockDesc sOpaqueStaticLitStencilWriteDesc;   static GFXStateBlockDesc sOpaqueDynamicLitStencilWriteDesc;   if(!sbInit)   {      sbInit = true;      // Build the static opaque stencil write/test state block descriptions      sOpaqueStaticLitStencilWriteDesc.stencilDefined = true;      sOpaqueStaticLitStencilWriteDesc.stencilEnable = true;      sOpaqueStaticLitStencilWriteDesc.stencilWriteMask = 0x03;      sOpaqueStaticLitStencilWriteDesc.stencilMask = 0x03;      sOpaqueStaticLitStencilWriteDesc.stencilRef = RenderDeferredMgr::OpaqueStaticLitMask;      sOpaqueStaticLitStencilWriteDesc.stencilPassOp = GFXStencilOpReplace;      sOpaqueStaticLitStencilWriteDesc.stencilFailOp = GFXStencilOpKeep;      sOpaqueStaticLitStencilWriteDesc.stencilZFailOp = GFXStencilOpKeep;      sOpaqueStaticLitStencilWriteDesc.stencilFunc = GFXCmpAlways;      // Same only dynamic      sOpaqueDynamicLitStencilWriteDesc = sOpaqueStaticLitStencilWriteDesc;      sOpaqueDynamicLitStencilWriteDesc.stencilRef = RenderDeferredMgr::OpaqueDynamicLitMask;   }   return (lightmappedGeometry ? sOpaqueStaticLitStencilWriteDesc : sOpaqueDynamicLitStencilWriteDesc);}const GFXStateBlockDesc & RenderDeferredMgr::getOpaqueStencilTestDesc(){   static bool sbInit = false;   static GFXStateBlockDesc sOpaqueStencilTestDesc;   if(!sbInit)   {      // Build opaque test      sbInit = true;      sOpaqueStencilTestDesc.stencilDefined = true;      sOpaqueStencilTestDesc.stencilEnable = true;      sOpaqueStencilTestDesc.stencilWriteMask = 0xFE;      sOpaqueStencilTestDesc.stencilMask = 0x03;      sOpaqueStencilTestDesc.stencilRef = 0;      sOpaqueStencilTestDesc.stencilPassOp = GFXStencilOpKeep;      sOpaqueStencilTestDesc.stencilFailOp = GFXStencilOpKeep;      sOpaqueStencilTestDesc.stencilZFailOp = GFXStencilOpKeep;      sOpaqueStencilTestDesc.stencilFunc = GFXCmpLess;   }   return sOpaqueStencilTestDesc;}//------------------------------------------------------------------------------//------------------------------------------------------------------------------ProcessedDeferredMaterial::ProcessedDeferredMaterial( Material& mat, const RenderDeferredMgr *deferredMgr ): Parent(mat), mDeferredMgr(deferredMgr), mIsLightmappedGeometry(false){}void ProcessedDeferredMaterial::_determineFeatures( U32 stageNum,                                                   MaterialFeatureData &fd,                                                   const FeatureSet &features ){   if (GFX->getAdapterType() == NullDevice) return;   Parent::_determineFeatures( stageNum, fd, features );   if (fd.features.hasFeature(MFT_ForwardShading))      return;   // Find this for use down below...   bool bEnableMRTLightmap = false;   AdvancedLightBinManager *lightBin;   if ( Sim::findObject( "AL_LightBinMgr", lightBin ) )      bEnableMRTLightmap = lightBin->MRTLightmapsDuringDeferred();   // If this material has a lightmap or tonemap (texture or baked vertex color),   // it must be static. Otherwise it is dynamic.   mIsLightmappedGeometry = ( fd.features.hasFeature( MFT_ToneMap ) ||                              fd.features.hasFeature( MFT_LightMap ) ||                              fd.features.hasFeature( MFT_VertLit ) ||                              ( bEnableMRTLightmap && (fd.features.hasFeature( MFT_IsTranslucent ) ||                                                      fd.features.hasFeature( MFT_ForwardShading ) ||                                                      fd.features.hasFeature( MFT_IsTranslucentZWrite) ) ) );   // Integrate proper opaque stencil write state   mUserDefined.addDesc( mDeferredMgr->getOpaqueStenciWriteDesc( mIsLightmappedGeometry ) );   FeatureSet newFeatures;   // These are always on for deferred.   newFeatures.addFeature( MFT_EyeSpaceDepthOut );   newFeatures.addFeature( MFT_DeferredConditioner );#ifndef TORQUE_DEDICATED   //tag all materials running through deferred as deferred   newFeatures.addFeature(MFT_isDeferred);   // Deferred Shading : Diffuse   if (mStages[stageNum].getTex( MFT_DiffuseMap ))   {      newFeatures.addFeature(MFT_DiffuseMap);   }   newFeatures.addFeature( MFT_DiffuseColor );      if (mMaterial->mInvertRoughness[stageNum])      newFeatures.addFeature(MFT_InvertRoughness);   // Deferred Shading : PBR Config   if( mStages[stageNum].getTex( MFT_OrmMap ) )   {       newFeatures.addFeature( MFT_OrmMap );   }   else       newFeatures.addFeature( MFT_ORMConfigVars );   if (mStages[stageNum].getTex(MFT_GlowMap))   {      newFeatures.addFeature(MFT_GlowMap);   }   // Deferred Shading : Material Info Flags   newFeatures.addFeature( MFT_MatInfoFlags );   for ( U32 i=0; i < fd.features.getCount(); i++ )   {      const FeatureType &type = fd.features.getAt( i );      // Turn on the diffuse texture only if we      // have alpha test.      if ( type == MFT_AlphaTest )      {         newFeatures.addFeature( MFT_AlphaTest );         newFeatures.addFeature( MFT_DiffuseMap );      }      else if ( type == MFT_IsTranslucentZWrite )      {         newFeatures.addFeature( MFT_IsTranslucentZWrite );         newFeatures.addFeature( MFT_DiffuseMap );      }      // Always allow these.      else if (   type == MFT_IsBC3nm ||                  type == MFT_IsBC5nm ||                  type == MFT_TexAnim ||                  type == MFT_NormalMap ||                  type == MFT_DetailNormalMap ||                  type == MFT_AlphaTest ||                  type == MFT_Parallax ||                  type == MFT_Visibility ||                  type == MFT_UseInstancing ||                  type == MFT_DiffuseVertColor ||                  type == MFT_DetailMap ||                  type == MFT_DiffuseMapAtlas||                  type == MFT_GlowMask)         newFeatures.addFeature( type );      // Add any transform features.      else if (   type.getGroup() == MFG_PreTransform ||                  type.getGroup() == MFG_Transform ||                  type.getGroup() == MFG_PostTransform )         newFeatures.addFeature( type );   }   if (mMaterial->mAccuEnabled[stageNum])   {      newFeatures.addFeature(MFT_AccuMap);      mHasAccumulation = true;   }   // we need both diffuse and normal maps + sm3 to have an accu map   if (newFeatures[MFT_AccuMap] &&      (!newFeatures[MFT_DiffuseMap] ||      !newFeatures[MFT_NormalMap] ||      GFX->getPixelShaderVersion() < 3.0f)) {      AssertWarn(false, "SAHARA: Using an Accu Map requires SM 3.0 and a normal map.");      newFeatures.removeFeature(MFT_AccuMap);      mHasAccumulation = false;   }   // if we still have the AccuMap feature, we add all accu constant features   if (newFeatures[MFT_AccuMap]) {      // add the dependencies of the accu map      newFeatures.addFeature(MFT_AccuScale);      newFeatures.addFeature(MFT_AccuDirection);      newFeatures.addFeature(MFT_AccuStrength);      newFeatures.addFeature(MFT_AccuCoverage);      newFeatures.addFeature(MFT_AccuSpecular);      // now remove some features that are not compatible with this      newFeatures.removeFeature(MFT_UseInstancing);   }   // If there is lightmapped geometry support, add the MRT light buffer features   if(bEnableMRTLightmap)   {      // If this material has a lightmap, pass it through, and flag it to      // send it's output to RenderTarget3      if( fd.features.hasFeature( MFT_ToneMap ) )      {         newFeatures.addFeature( MFT_ToneMap );         newFeatures.addFeature( MFT_LightbufferMRT );      }      else if( fd.features.hasFeature( MFT_LightMap ) )      {         newFeatures.addFeature( MFT_LightMap );         newFeatures.addFeature( MFT_LightbufferMRT );      }      else if( fd.features.hasFeature( MFT_VertLit ) )      {         // Flag un-tone-map if necesasary         if( fd.features.hasFeature( MFT_DiffuseMap ) )            newFeatures.addFeature( MFT_VertLitTone );         newFeatures.addFeature( MFT_VertLit );         newFeatures.addFeature( MFT_LightbufferMRT );      }      else if (!fd.features.hasFeature(MFT_GlowMap))      {            newFeatures.addFeature( MFT_RenderTarget3_Zero );      }   }   // cubemaps only available on stage 0 for now - bramage      if ( stageNum < 1 &&          (  (  mMaterial->mCubemapData && mMaterial->mCubemapData->mCubemap ) ||               mMaterial->mDynamicCubemap ) )   {      if (!mMaterial->mDynamicCubemap)         fd.features.addFeature(MFT_StaticCubemap);      newFeatures.addFeature( MFT_CubeMap );   }   if (mMaterial->mVertLit[stageNum])      newFeatures.addFeature(MFT_VertLit);   if (mMaterial->mMinnaertConstant[stageNum] > 0.0f)      newFeatures.addFeature(MFT_MinnaertShading);   if (mMaterial->mSubSurface[stageNum])      newFeatures.addFeature(MFT_SubSurface);   #endif   // Set the new features.   fd.features = newFeatures;}U32 ProcessedDeferredMaterial::getNumStages(){   // Loops through all stages to determine how many    // stages we actually use.     //    // The first stage is always active else we shouldn't be   // creating the material to begin with.   U32 numStages = 1;   U32 i;   for( i=1; i<Material::MAX_STAGES; i++ )   {      // Assume stage is inactive      bool stageActive = false;      // Cubemaps only on first stage      if( i == 0 )      {         // If we have a cubemap the stage is active         if( mMaterial->mCubemapData || mMaterial->mDynamicCubemap )         {            numStages++;            continue;         }      }      // If we have a texture for the a feature the       // stage is active.      if ( mStages[i].hasValidTex() )         stageActive = true;            // If this stage has diffuse color, it's active      if (  mMaterial->mDiffuse[i].alpha > 0 &&            mMaterial->mDiffuse[i] != LinearColorF::WHITE )         stageActive = true;      // If we have a Material that is vertex lit      // then it may not have a texture      if( mMaterial->mVertLit[i] )         stageActive = true;      // Increment the number of active stages      numStages += stageActive;   }   return numStages;}void ProcessedDeferredMaterial::addStateBlockDesc(const GFXStateBlockDesc& desc){   GFXStateBlockDesc deferredStateBlock = desc;   // Adjust color writes if this is a pure z-fill pass   const bool pixelOutEnabled = mDeferredMgr->getTargetChainLength() > 0;   if ( !pixelOutEnabled )   {      deferredStateBlock.colorWriteDefined = true;      deferredStateBlock.colorWriteRed = pixelOutEnabled;      deferredStateBlock.colorWriteGreen = pixelOutEnabled;      deferredStateBlock.colorWriteBlue = pixelOutEnabled;      deferredStateBlock.colorWriteAlpha = pixelOutEnabled;   }   // Never allow the alpha test state when rendering   // the deferred as we use the alpha channel for the   // depth information... MFT_AlphaTest will handle it.   deferredStateBlock.alphaDefined = true;   deferredStateBlock.alphaTestEnable = false;   // If we're translucent then we're doing deferred blending   // which never writes to the depth channels.   const bool isTranslucent = getMaterial()->isTranslucent();   if ( isTranslucent )   {      deferredStateBlock.setBlend( true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha );      deferredStateBlock.setColorWrites(false, false, false, true);   }   // Enable z reads, but only enable zwrites if we're not translucent.   deferredStateBlock.setZReadWrite( true, isTranslucent ? false : true );   // Pass to parent   Parent::addStateBlockDesc(deferredStateBlock);}DeferredMatInstance::DeferredMatInstance(MatInstance* root, const RenderDeferredMgr *deferredMgr): Parent(*root->getMaterial()), mDeferredMgr(deferredMgr){   mFeatureList = root->getRequestedFeatures();   mVertexFormat = root->getVertexFormat();   mUserObject = root->getUserObject();}DeferredMatInstance::~DeferredMatInstance(){}ProcessedMaterial* DeferredMatInstance::getShaderMaterial(){   return new ProcessedDeferredMaterial(*mMaterial, mDeferredMgr);}bool DeferredMatInstance::init( const FeatureSet &features,                               const GFXVertexFormat *vertexFormat ){   bool vaild = Parent::init(features, vertexFormat);   if (mMaterial && mMaterial->getDiffuseMap(0) != StringTable->EmptyString() && String(mMaterial->getDiffuseMap(0)).startsWith("#"))   {      String difName = mMaterial->getDiffuseMap(0);      String texTargetBufferName = difName.substr(1, difName.length() - 1);      NamedTexTarget *texTarget = NamedTexTarget::find(texTargetBufferName);      RenderPassData* rpd = getPass(0);      if (rpd)      {         rpd->mTexSlot[0].texTarget = texTarget;         rpd->mTexType[0] = Material::TexTarget;         rpd->mSamplerNames[0] = "diffuseMap";      }   }   return vaild;}DeferredMatInstanceHook::DeferredMatInstanceHook( MatInstance *baseMatInst,                                                const RenderDeferredMgr *deferredMgr )   : mHookedDeferredMatInst(NULL), mDeferredManager(deferredMgr){   // If the material is a custom material then   // hope that using DefaultDeferredMaterial gives   // them a good deferred.   if ( baseMatInst->isCustomMaterial() )   {      MatInstance* dummyInst = static_cast<MatInstance*>( MATMGR->createMatInstance( "AL_DefaultDeferredMaterial", baseMatInst->getVertexFormat() ) );      mHookedDeferredMatInst = new DeferredMatInstance( dummyInst, deferredMgr );      mHookedDeferredMatInst->init( dummyInst->getRequestedFeatures(), baseMatInst->getVertexFormat());      delete dummyInst;      return;   }   // Create the deferred material instance.   mHookedDeferredMatInst = new DeferredMatInstance(baseMatInst, deferredMgr);   mHookedDeferredMatInst->getFeaturesDelegate() = baseMatInst->getFeaturesDelegate();   // Get the features, but remove the instancing feature if the   // original material didn't end up using it.   FeatureSet features = baseMatInst->getRequestedFeatures();   if ( !baseMatInst->isInstanced() )      features.removeFeature( MFT_UseInstancing );   // Initialize the material.   mHookedDeferredMatInst->init(features, baseMatInst->getVertexFormat());}DeferredMatInstanceHook::~DeferredMatInstanceHook(){   SAFE_DELETE(mHookedDeferredMatInst);}//------------------------------------------------------------------------------//------------------------------------------------------------------------------void LinearEyeDepthConditioner::processPix( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd ){   // find depth   ShaderFeature *depthFeat = FEATUREMGR->getByType( MFT_EyeSpaceDepthOut );   AssertFatal( depthFeat != NULL, "No eye space depth feature found!" );   Var *depth = (Var*) LangElement::find(depthFeat->getOutputVarName());   AssertFatal( depth, "Something went bad with ShaderGen. The depth should be already generated by the EyeSpaceDepthOut feature." );   MultiLine *meta = new MultiLine;   meta->addStatement( assignOutput( depth ) );   output = meta;}Var *LinearEyeDepthConditioner::_conditionOutput( Var *unconditionedOutput, MultiLine *meta ){   Var *retVar = NULL;   String fracMethodName = (GFX->getAdapterType() == OpenGL) ? "fract" : "frac";   switch(getBufferFormat())   {   case GFXFormatR8G8B8A8:      retVar = new Var;      retVar->setType("float4");      retVar->setName("_ppDepth");      meta->addStatement( new GenOp( "   // depth conditioner: packing to rgba\r\n" ) );      meta->addStatement( new GenOp(         avar( "   @ = %s(@ * (255.0/256) * float4(1, 255, 255 * 255, 255 * 255 * 255));\r\n", fracMethodName.c_str() ),         new DecOp(retVar), unconditionedOutput ) );      break;   default:      retVar = unconditionedOutput;      meta->addStatement( new GenOp( "   // depth conditioner: no conditioning\r\n" ) );      break;   }   AssertFatal( retVar != NULL, avar( "Cannot condition output to buffer format: %s", GFXStringTextureFormat[getBufferFormat()] ) );   return retVar;}Var *LinearEyeDepthConditioner::_unconditionInput( Var *conditionedInput, MultiLine *meta ){   String float4Typename = (GFX->getAdapterType() == OpenGL) ? "vec4" : "float4";   Var *retVar = conditionedInput;   if(getBufferFormat() != GFXFormat_COUNT)   {      retVar = new Var;      retVar->setType(float4Typename.c_str());      retVar->setName("_ppDepth");      meta->addStatement( new GenOp( avar( "   @ = %s(0, 0, 1, 1);\r\n", float4Typename.c_str() ), new DecOp(retVar) ) );      switch(getBufferFormat())      {      case GFXFormatR32F:      case GFXFormatR16F:         meta->addStatement( new GenOp( "   // depth conditioner: float texture\r\n" ) );         meta->addStatement( new GenOp( "   @.w = @.r;\r\n", retVar, conditionedInput ) );         break;      case GFXFormatR8G8B8A8:         meta->addStatement( new GenOp( "   // depth conditioner: unpacking from rgba\r\n" ) );         meta->addStatement( new GenOp(            avar( "   @.w = dot(@ * (256.0/255), %s(1, 1 / 255, 1 / (255 * 255), 1 / (255 * 255 * 255)));\r\n", float4Typename.c_str() )            , retVar, conditionedInput ) );         break;      default:         AssertFatal(false, "LinearEyeDepthConditioner::_unconditionInput - Unrecognized buffer format");      }   }   return retVar;}Var* LinearEyeDepthConditioner::printMethodHeader( MethodType methodType, const String &methodName, Stream &stream, MultiLine *meta ){   const bool isCondition = ( methodType == ConditionerFeature::ConditionMethod );   Var *retVal = NULL;   // The uncondition method inputs are changed   if( isCondition )      retVal = Parent::printMethodHeader( methodType, methodName, stream, meta );   else   {      Var *methodVar = new Var;      methodVar->setName(methodName);      if (GFX->getAdapterType() == OpenGL)         methodVar->setType("vec4");      else         methodVar->setType("inline float4");      DecOp *methodDecl = new DecOp(methodVar);      Var *deferredSampler = new Var;      deferredSampler->setName("deferredSamplerVar");      deferredSampler->setType("sampler2D");      DecOp *deferredSamplerDecl = NULL;      Var *deferredTex = NULL;      DecOp *deferredTexDecl = NULL;      if (GFX->getAdapterType() == Direct3D11)      {         deferredSampler->setType("SamplerState");         deferredTex = new Var;         deferredTex->setName("deferredTexVar");         deferredTex->setType("Texture2D");         deferredTexDecl = new DecOp(deferredTex);      }      deferredSamplerDecl = new DecOp(deferredSampler);      Var *screenUV = new Var;      screenUV->setName("screenUVVar");      if (GFX->getAdapterType() == OpenGL)         screenUV->setType("vec2");      else         screenUV->setType("float2");      DecOp *screenUVDecl = new DecOp(screenUV);      Var *bufferSample = new Var;      bufferSample->setName("bufferSample");      if (GFX->getAdapterType() == OpenGL)         bufferSample->setType("vec4");      else         bufferSample->setType("float4");      DecOp *bufferSampleDecl = new DecOp(bufferSample);      if (deferredTex)         meta->addStatement(new GenOp("@(@, @, @)\r\n", methodDecl, deferredSamplerDecl, deferredTexDecl, screenUVDecl));      else         meta->addStatement(new GenOp("@(@, @)\r\n", methodDecl, deferredSamplerDecl, screenUVDecl));      meta->addStatement(new GenOp("{\r\n"));      meta->addStatement(new GenOp("   // Sampler g-buffer\r\n"));      // The linear depth target has no mipmaps, so use tex2dlod when      // possible so that the shader compiler can optimize.      if (GFX->getAdapterType() == OpenGL)         meta->addStatement(new GenOp("@ = texture2DLod(@, @, 0); \r\n", bufferSampleDecl, deferredSampler, screenUV));      else      {         if (deferredTex)            meta->addStatement(new GenOp("@ = @.SampleLevel(@, @, 0);\r\n", bufferSampleDecl, deferredTex, deferredSampler, screenUV));         else            meta->addStatement(new GenOp("@ = tex2Dlod(@, float4(@,0,0));\r\n", bufferSampleDecl, deferredSampler, screenUV));      }      // We don't use this way of passing var's around, so this should cause a crash      // if something uses this improperly      retVal = bufferSample;   }   return retVal;}
 |