| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386 | //-----------------------------------------------------------------------------// 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/renderFormatChanger.h"#include "console/consoleTypes.h"#include "gfx/gfxStringEnumTranslate.h"#include "gfx/gfxTextureManager.h"#include "gfx/gfxDebugEvent.h"#include "postFx/postEffect.h"#include "postFx/postEffectManager.h"extern ColorI gCanvasClearColor;IMPLEMENT_CONOBJECT(RenderFormatToken);ConsoleDocClass( RenderFormatToken,   "@brief Used to change the render target format when rendering in AL.\n\n"   "RenderFormatToken is an implementation which changes the format of the "   "back buffer and/or the depth buffer.\n\n"      "The RenderPassStateBin manager changes the rendering state associated with "   "this token. In stock Torque 3D, a single example exists in the "   "way of AL_FormatToken (found in renderManager.cs). In that script file, all the "   "render managers are intialized, and a single RenderFormatToken is used. This "   "implementation basically exists to ensure Advanced Lighting works with MSAA.\n\n"   "The actions for this token toggle the format of the back/depth buffers "   "and it lets you specify a custom shader to \"copy\" the data so it can "   "be reformatted or altered. This is done through the variables copyEffect and "   "resolveEffect (which are post processes just like fog or glow)\n\n"   "@tsexample\n"   "// This token, and the associated render managers, ensure "   "that driver MSAA does not get used for Advanced Lighting renders.\n"   "// The 'AL_FormatResolve' PostEffect copies the result to the backbuffer.\n"   "new RenderFormatToken(AL_FormatToken)\n"   "{\n"   "   enabled = \"false\";\n\n"   "   format = \"GFXFormatR8G8B8A8\";\n"   "   depthFormat = \"GFXFormatD24S8\";\n"   "   aaLevel = 0; // -1 = match backbuffer\n\n"   "   // The contents of the back buffer before this format token is executed\n"   "   // is provided in $inTex\n"   "   copyEffect = \"AL_FormatCopy\";\n\n"   "   // The contents of the render target created by this format token is\n"   "   // provided in $inTex\n"   "   resolveEffect = \"AL_FormatCopy\";\n"   "};\n"   "@endtsexample\n\n"   "@see RenderPassToken\n\n"   "@see RenderPassStateBin\n"   "@see game/core/scripts/client/renderManager.cs\n"   "@ingroup GFX\n");RenderFormatToken::RenderFormatToken()    :  Parent(),       mFCState(FTSDisabled),       mColorFormat(GFXFormat_COUNT),       mDepthFormat(GFXFormat_COUNT),      mTargetUpdatePending(true),      mTargetChainIdx(0),      mTargetSize(Point2I::Zero),      mTargetAALevel(GFXTextureManager::AA_MATCH_BACKBUFFER),      mCopyPostEffect(NULL),      mResolvePostEffect(NULL){   GFXDevice::getDeviceEventSignal().notify(this, &RenderFormatToken::_handleGFXEvent);   GFXTextureManager::addEventDelegate(this, &RenderFormatToken::_onTextureEvent);}RenderFormatToken::~RenderFormatToken(){   GFXTextureManager::removeEventDelegate(this, &RenderFormatToken::_onTextureEvent);   GFXDevice::getDeviceEventSignal().remove(this, &RenderFormatToken::_handleGFXEvent);   _teardownTargets();}void RenderFormatToken::process(SceneRenderState *state, RenderPassStateBin *callingBin){   switch(mFCState)   {   case FTSWaiting:      {         GFXDEBUGEVENT_SCOPE_EX(RFT_Waiting, ColorI::BLUE, avar("[%s Activate] (%s)", getName(), GFXStringTextureFormat[mColorFormat]));         mFCState = FTSActive;         mTarget.setViewport( GFX->getViewport() );         // Update targets         _updateTargets();         // If we have a copy PostEffect then get the active backbuffer copy          // now before we swap the render targets.         GFXTexHandle curBackBuffer;         if(mCopyPostEffect.isValid())            curBackBuffer = PFXMGR->getBackBufferTex();         // Push target         GFX->pushActiveRenderTarget();         GFX->setActiveRenderTarget(mTargetChain[mTargetChainIdx]);         // Set viewport         GFX->setViewport( mTarget.getViewport() );         // Clear         GFX->clear(GFXClearTarget | GFXClearZBuffer | GFXClearStencil, gCanvasClearColor, 1.0f, 0);         // Set active z target on render pass         if(mTargetDepthStencilTexture[mTargetChainIdx].isValid())         {            if(callingBin->getRenderPass()->getDepthTargetTexture() != GFXTextureTarget::sDefaultDepthStencil)               mStoredPassZTarget = callingBin->getRenderPass()->getDepthTargetTexture();            else               mStoredPassZTarget = NULL;            callingBin->getRenderPass()->setDepthTargetTexture(mTargetDepthStencilTexture[mTargetChainIdx]);         }         // Run the PostEffect which copies data into the new target.         if ( mCopyPostEffect.isValid() )            mCopyPostEffect->process( state, curBackBuffer, &mTarget.getViewport() );      }      break;   case FTSActive:      {         GFXDEBUGEVENT_SCOPE_EX(RFT_Active, ColorI::BLUE, avar("[%s Deactivate]", getName()));         mFCState = FTSComplete;         // Pop target         AssertFatal(GFX->getActiveRenderTarget() == mTargetChain[mTargetChainIdx], "Render target stack went wrong somewhere");         mTargetChain[mTargetChainIdx]->resolve();         GFX->popActiveRenderTarget();         mTarget.setTexture( mTargetColorTexture[mTargetChainIdx] );                   // This is the GFX viewport when we were first processed.         GFX->setViewport( mTarget.getViewport() );         // Restore active z-target         if(mTargetDepthStencilTexture[mTargetChainIdx].isValid())         {            callingBin->getRenderPass()->setDepthTargetTexture(mStoredPassZTarget.getPointer());            mStoredPassZTarget = NULL;         }         // Run the PostEffect which copies data to the backbuffer         if(mResolvePostEffect.isValid())         {		      // Need to create a texhandle here, since inOutTex gets assigned during process()            GFXTexHandle inOutTex = mTargetColorTexture[mTargetChainIdx];            mResolvePostEffect->process( state, inOutTex, &mTarget.getViewport() );         }      }      break;   case FTSComplete:      AssertFatal(false, "process() called on a RenderFormatToken which was already complete.");      // fall through   case FTSDisabled:      break;   }}void RenderFormatToken::reset(){   AssertFatal(mFCState != FTSActive, "RenderFormatToken still active during reset()!");   if(mFCState != FTSDisabled)      mFCState = FTSWaiting;}void RenderFormatToken::_updateTargets(){   if ( GFX->getActiveRenderTarget() == NULL )      return;   const Point2I &rtSize = GFX->getActiveRenderTarget()->getSize();   if ( rtSize.x <= mTargetSize.x &&         rtSize.y <= mTargetSize.y &&         !mTargetUpdatePending )      return;      mTargetSize = rtSize;   mTargetUpdatePending = false;      mTargetChainIdx = 0;   for( U32 i = 0; i < TargetChainLength; i++ )   {      if( !mTargetChain[i] )         mTargetChain[i] = GFX->allocRenderToTextureTarget();      // Update color target      if(mColorFormat != GFXFormat_COUNT)      {         // try reuse of old color texture         if( !mTargetColorTexture[i] || mTargetColorTexture[i].getFormat() != mColorFormat             || mTargetColorTexture[i].getWidthHeight() != rtSize)         {         mTargetColorTexture[i].set( rtSize.x, rtSize.y, mColorFormat,             &GFXDefaultRenderTargetProfile, avar( "%s() - (line %d)", __FUNCTION__, __LINE__ ),            1, mTargetAALevel );         mTargetChain[i]->attachTexture( GFXTextureTarget::Color0, mTargetColorTexture[i] );      }      }            // Update depth target      if(mDepthFormat != GFXFormat_COUNT)      {         // try reuse of old depth texture         if( !mTargetDepthStencilTexture[i] || mTargetDepthStencilTexture[i].getFormat() != mColorFormat             || mTargetDepthStencilTexture[i].getWidthHeight() != rtSize)         {         mTargetDepthStencilTexture[i].set( rtSize.x, rtSize.y, mDepthFormat,             &GFXDefaultZTargetProfile, avar( "%s() - (line %d)", __FUNCTION__, __LINE__ ),            1, mTargetAALevel );            mTargetChain[i]->attachTexture( GFXTextureTarget::DepthStencil, mTargetDepthStencilTexture[i] );         }      }        }}void RenderFormatToken::_teardownTargets(){   mTarget.release();   for(S32 i = 0; i < TargetChainLength; i++)   {      mTargetColorTexture[i] = NULL;      mTargetDepthStencilTexture[i] = NULL;      mTargetChain[i] = NULL;   }}bool RenderFormatToken::_setFmt( void *object, const char *index, const char *data ){   // Flag update pending   reinterpret_cast<RenderFormatToken *>( object )->mTargetUpdatePending = true;   // Allow console system to assign value   return true;}const char* RenderFormatToken::_getCopyPostEffect( void* object, const char* data ){   RenderFormatToken* token = reinterpret_cast< RenderFormatToken* >( object );   if( token->mCopyPostEffect.isValid() )      return token->mCopyPostEffect->getIdString();   return "0";}const char* RenderFormatToken::_getResolvePostEffect( void* object, const char* data ){   RenderFormatToken* token = reinterpret_cast< RenderFormatToken* >( object );   if( token->mResolvePostEffect.isValid() )      return token->mResolvePostEffect->getIdString();   return "0";}bool RenderFormatToken::_setCopyPostEffect( void* object, const char* index, const char* data ){   RenderFormatToken* token = reinterpret_cast< RenderFormatToken* >( object );   PostEffect* effect;   Sim::findObject( data, effect );   token->mCopyPostEffect = effect;   return false;}bool RenderFormatToken::_setResolvePostEffect( void* object, const char* index, const char* data ){   RenderFormatToken* token = reinterpret_cast< RenderFormatToken* >( object );   PostEffect* effect;   Sim::findObject( data, effect );   token->mResolvePostEffect = effect;   return false;}void RenderFormatToken::enable( bool enabled /*= true*/ ){   AssertFatal(mFCState != FTSActive, "RenderFormatToken is active, cannot change state now!");   if(enabled)      mFCState = FTSWaiting;   else      mFCState = FTSDisabled;}bool RenderFormatToken::isEnabled() const{   return (mFCState != FTSDisabled);}void RenderFormatToken::initPersistFields(){   addProtectedField("format", TypeGFXFormat, Offset(mColorFormat, RenderFormatToken), &_setFmt, &defaultProtectedGetFn,       "Sets the color buffer format for this token.");   addProtectedField("depthFormat", TypeGFXFormat, Offset(mDepthFormat, RenderFormatToken), &_setFmt, &defaultProtectedGetFn,       "Sets the depth/stencil buffer format for this token.");   addProtectedField("copyEffect", TYPEID<PostEffect>(), Offset(mCopyPostEffect, RenderFormatToken),      &_setCopyPostEffect, &_getCopyPostEffect,      "This PostEffect will be run when the render target is changed to the format specified "      "by this token. It is used to copy/format data into the token rendertarget");   addProtectedField("resolveEffect", TYPEID<PostEffect>(), Offset(mResolvePostEffect, RenderFormatToken),      &_setResolvePostEffect, &_getResolvePostEffect,      "This PostEffect will be run when the render target is changed back to the format "      "active prior to this token. It is used to copy/format data from the token rendertarget to the backbuffer.");   addField("aaLevel", TypeS32, Offset(mTargetAALevel, RenderFormatToken),       "Anti-ailiasing level for the this token. 0 disables, -1 uses adapter default.");   Parent::initPersistFields();}bool RenderFormatToken::_handleGFXEvent(GFXDevice::GFXDeviceEventType event_){   if ( event_ == GFXDevice::deStartOfFrame )   {      mTargetChainIdx++;      if ( mTargetChainIdx >= TargetChainLength )         mTargetChainIdx = 0;   }   return true;}void RenderFormatToken::_onTextureEvent( GFXTexCallbackCode code ){   if(code == GFXZombify)   {      _teardownTargets();      mTargetUpdatePending = true;   }}bool RenderFormatToken::onAdd(){   if(!Parent::onAdd())      return false;   mTarget.registerWithName( getName() );   mTarget.setSamplerState( GFXSamplerStateDesc::getClampPoint() );   return true;}void RenderFormatToken::onRemove(){   mTarget.unregister();   mTarget.release();   Parent::onRemove();}
 |