2012-09-19 15:15:01 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// 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 "postFx/postEffectManager.h"
|
|
|
|
|
|
|
|
|
|
#include "postFx/postEffect.h"
|
|
|
|
|
#include "postFx/postEffectVis.h"
|
|
|
|
|
#include "renderInstance/renderBinManager.h"
|
|
|
|
|
#include "scene/sceneManager.h"
|
|
|
|
|
#include "scene/sceneRenderState.h"
|
|
|
|
|
#include "console/consoleTypes.h"
|
|
|
|
|
#include "core/module.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MODULE_BEGIN( PostEffectManager )
|
|
|
|
|
|
|
|
|
|
MODULE_SHUTDOWN_AFTER( Sim )
|
|
|
|
|
|
|
|
|
|
MODULE_INIT
|
|
|
|
|
{
|
|
|
|
|
ManagedSingleton< PostEffectManager >::createSingleton();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MODULE_SHUTDOWN
|
|
|
|
|
{
|
|
|
|
|
ManagedSingleton< PostEffectManager >::deleteSingleton();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MODULE_END;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool PostEffectManager::smRenderEffects = true;
|
|
|
|
|
|
|
|
|
|
PostEffectManager::PostEffectManager() :
|
2017-04-11 04:45:02 +00:00
|
|
|
mLastBackBufferTarget( NULL ),
|
|
|
|
|
mFrameStateSwitch( false )
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
|
|
|
|
GFXDevice::getDeviceEventSignal().notify( this, &PostEffectManager::_handleDeviceEvent );
|
|
|
|
|
RenderPassManager::getRenderBinSignal().notify( this, &PostEffectManager::_handleBinEvent );
|
|
|
|
|
SceneManager::getPostRenderSignal().notify( this, &PostEffectManager::_onPostRenderPass );
|
|
|
|
|
|
|
|
|
|
Con::addVariable("pref::enablePostEffects", TypeBool, &smRenderEffects,
|
|
|
|
|
"@brief If true, post effects will be eanbled.\n\n"
|
|
|
|
|
"@ingroup Game");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PostEffectManager::~PostEffectManager()
|
|
|
|
|
{
|
|
|
|
|
GFXDevice::getDeviceEventSignal().remove( this, &PostEffectManager::_handleDeviceEvent );
|
|
|
|
|
RenderPassManager::getRenderBinSignal().remove( this, &PostEffectManager::_handleBinEvent );
|
|
|
|
|
SceneManager::getPostRenderSignal().remove( this, &PostEffectManager::_onPostRenderPass );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool PostEffectManager::_handleDeviceEvent( GFXDevice::GFXDeviceEventType evt )
|
|
|
|
|
{
|
|
|
|
|
switch( evt )
|
|
|
|
|
{
|
|
|
|
|
case GFXDevice::deStartOfFrame:
|
|
|
|
|
PFXVIS->onStartOfFrame();
|
|
|
|
|
|
|
|
|
|
// Fall through
|
|
|
|
|
|
|
|
|
|
case GFXDevice::deDestroy:
|
|
|
|
|
|
|
|
|
|
// Free the back buffer as the device or
|
|
|
|
|
// its content is now invalid.
|
|
|
|
|
releaseBackBufferTex();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GFXDevice::deEndOfFrame:
|
|
|
|
|
|
|
|
|
|
renderEffects( NULL, PFXEndOfFrame );
|
|
|
|
|
|
|
|
|
|
// Toggle frame state history switch
|
|
|
|
|
mFrameStateSwitch = !mFrameStateSwitch;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PostEffectManager::_handleBinEvent( RenderBinManager *bin,
|
|
|
|
|
const SceneRenderState* sceneState,
|
|
|
|
|
bool isBinStart )
|
|
|
|
|
{
|
|
|
|
|
if ( sceneState->isShadowPass() ||
|
|
|
|
|
sceneState->isOtherPass() )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// We require a bin name to process effects... without
|
|
|
|
|
// it we can skip the bin entirely.
|
|
|
|
|
String binName( bin->getName() );
|
|
|
|
|
if ( binName.isEmpty() )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
renderEffects( sceneState, isBinStart ? PFXBeforeBin : PFXAfterBin, binName );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PostEffectManager::_onPostRenderPass( SceneManager *sceneGraph, const SceneRenderState *sceneState )
|
|
|
|
|
{
|
|
|
|
|
if ( !sceneState->isDiffusePass() )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
renderEffects( sceneState, PFXAfterDiffuse );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GFXTextureObject* PostEffectManager::getBackBufferTex()
|
|
|
|
|
{
|
|
|
|
|
GFXTarget *target = GFX->getActiveRenderTarget();
|
|
|
|
|
|
|
|
|
|
if ( mBackBufferCopyTex.isNull() ||
|
|
|
|
|
target != mLastBackBufferTarget )
|
|
|
|
|
{
|
|
|
|
|
const Point2I &targetSize = target->getSize();
|
|
|
|
|
GFXFormat targetFormat = target->getFormat();
|
|
|
|
|
|
|
|
|
|
mBackBufferCopyTex.set( targetSize.x, targetSize.y,
|
|
|
|
|
targetFormat,
|
|
|
|
|
&PostFxTargetProfile, "mBackBufferCopyTex" );
|
|
|
|
|
|
|
|
|
|
target->resolveTo( mBackBufferCopyTex );
|
|
|
|
|
mLastBackBufferTarget = target;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return mBackBufferCopyTex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PostEffectManager::releaseBackBufferTex()
|
|
|
|
|
{
|
|
|
|
|
mBackBufferCopyTex = NULL;
|
|
|
|
|
mLastBackBufferTarget = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool PostEffectManager::_addEffect( PostEffect *effect )
|
|
|
|
|
{
|
|
|
|
|
EffectVector *effects = NULL;
|
|
|
|
|
|
|
|
|
|
const String &binName = effect->getRenderBin();
|
|
|
|
|
|
|
|
|
|
switch( effect->getRenderTime() )
|
|
|
|
|
{
|
|
|
|
|
case PFXAfterDiffuse:
|
|
|
|
|
effects = &mAfterDiffuseList;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PFXEndOfFrame:
|
|
|
|
|
effects = &mEndOfFrameList;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PFXBeforeBin:
|
|
|
|
|
effects = &mBeforeBinMap[binName];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PFXAfterBin:
|
|
|
|
|
effects = &mAfterBinMap[binName];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PFXTexGenOnDemand:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( effects == NULL )
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
effects->push_back( effect );
|
|
|
|
|
|
|
|
|
|
// Resort the effects by priority.
|
|
|
|
|
effects->sort( &_effectPrioritySort );
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool PostEffectManager::_removeEffect( PostEffect *effect )
|
|
|
|
|
{
|
|
|
|
|
// Check the end of frame list.
|
2017-12-19 22:04:46 +00:00
|
|
|
EffectVector::iterator iter = T3D::find( mEndOfFrameList.begin(), mEndOfFrameList.end(), effect );
|
2012-09-19 15:15:01 +00:00
|
|
|
if ( iter != mEndOfFrameList.end() )
|
|
|
|
|
{
|
|
|
|
|
mEndOfFrameList.erase( iter );
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check the diffuse list.
|
2017-12-19 22:04:46 +00:00
|
|
|
iter = T3D::find( mAfterDiffuseList.begin(), mAfterDiffuseList.end(), effect );
|
2012-09-19 15:15:01 +00:00
|
|
|
if ( iter != mAfterDiffuseList.end() )
|
|
|
|
|
{
|
|
|
|
|
mAfterDiffuseList.erase( iter );
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now check the bin maps.
|
|
|
|
|
EffectMap::Iterator mapIter = mAfterBinMap.begin();
|
|
|
|
|
for( ; mapIter != mAfterBinMap.end(); mapIter++ )
|
|
|
|
|
{
|
|
|
|
|
EffectVector &effects = mapIter->value;
|
2017-12-19 22:04:46 +00:00
|
|
|
iter = T3D::find( effects.begin(), effects.end(), effect );
|
2012-09-19 15:15:01 +00:00
|
|
|
if ( iter != effects.end() )
|
|
|
|
|
{
|
|
|
|
|
effects.erase( iter );
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mapIter = mBeforeBinMap.begin();
|
|
|
|
|
for( ; mapIter != mBeforeBinMap.end(); mapIter++ )
|
|
|
|
|
{
|
|
|
|
|
EffectVector &effects = mapIter->value;
|
2017-12-19 22:04:46 +00:00
|
|
|
iter = T3D::find( effects.begin(), effects.end(), effect );
|
2012-09-19 15:15:01 +00:00
|
|
|
if ( iter != effects.end() )
|
|
|
|
|
{
|
|
|
|
|
effects.erase( iter );
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PostEffectManager::renderEffects( const SceneRenderState *state,
|
|
|
|
|
const PFXRenderTime effectTiming,
|
|
|
|
|
const String &binName )
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// Check the global render effect state as
|
|
|
|
|
// well as the
|
|
|
|
|
if ( !smRenderEffects ||
|
|
|
|
|
( state && !state->usePostEffects() ))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
EffectVector *effects = NULL;
|
|
|
|
|
|
|
|
|
|
switch( effectTiming )
|
|
|
|
|
{
|
|
|
|
|
case PFXBeforeBin:
|
|
|
|
|
effects = &mBeforeBinMap[binName];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PFXAfterBin:
|
|
|
|
|
effects = &mAfterBinMap[binName];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PFXAfterDiffuse:
|
|
|
|
|
effects = &mAfterDiffuseList;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PFXEndOfFrame:
|
|
|
|
|
effects = &mEndOfFrameList;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PFXTexGenOnDemand:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AssertFatal( effects != NULL, "Bad effect time" );
|
|
|
|
|
|
|
|
|
|
// Skip out if we don't have any effects.
|
|
|
|
|
if ( effects->empty() )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// This is used to pass the output texture
|
|
|
|
|
// of one effect into the next effect.
|
|
|
|
|
GFXTexHandle chainTex;
|
|
|
|
|
|
|
|
|
|
// Process the effects.
|
|
|
|
|
for ( U32 i = 0; i < effects->size(); i++ )
|
|
|
|
|
{
|
|
|
|
|
PostEffect *effect = (*effects)[i];
|
|
|
|
|
AssertFatal( effect != NULL, "Somehow this happened" );
|
|
|
|
|
effect->process( state, chainTex );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PostEffectManager::setFrameMatrices( const MatrixF &worldToCamera, const MatrixF &cameraToScreen )
|
|
|
|
|
{
|
|
|
|
|
PFXFrameState &thisFrame = mFrameState[mFrameStateSwitch];
|
|
|
|
|
thisFrame.worldToCamera = worldToCamera;
|
|
|
|
|
thisFrame.cameraToScreen = cameraToScreen;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
S32 PostEffectManager::_effectPrioritySort( PostEffect* const *e1, PostEffect* const *e2 )
|
|
|
|
|
{
|
|
|
|
|
F32 p1 = (*e1)->getPriority();
|
|
|
|
|
F32 p2 = (*e2)->getPriority();
|
|
|
|
|
|
|
|
|
|
if( p1 > p2 )
|
|
|
|
|
return -1;
|
|
|
|
|
else if( p1 < p2 )
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2019-10-20 07:47:15 +00:00
|
|
|
|
|
|
|
|
void PostEffectManager::dumpActivePostFX()
|
|
|
|
|
{
|
|
|
|
|
EffectVector effects;
|
|
|
|
|
|
|
|
|
|
for (U32 i = 0; i < mEndOfFrameList.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
PostEffect* effect = mEndOfFrameList[i];
|
|
|
|
|
|
|
|
|
|
if(effect->isEnabled())
|
|
|
|
|
effects.push_back(effect);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (U32 i = 0; i < mAfterDiffuseList.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
PostEffect* effect = mAfterDiffuseList[i];
|
|
|
|
|
|
|
|
|
|
if (effect->isEnabled())
|
|
|
|
|
effects.push_back(effect);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Now check the bin maps.
|
|
|
|
|
EffectMap::Iterator mapIter = mAfterBinMap.begin();
|
|
|
|
|
for (; mapIter != mAfterBinMap.end(); mapIter++)
|
|
|
|
|
{
|
|
|
|
|
EffectVector& ef = mapIter->value;
|
|
|
|
|
|
|
|
|
|
for (U32 i = 0; i < ef.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
PostEffect* effect = ef[i];
|
|
|
|
|
|
|
|
|
|
if (effect->isEnabled())
|
|
|
|
|
effects.push_back(effect);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mapIter = mBeforeBinMap.begin();
|
|
|
|
|
for (; mapIter != mBeforeBinMap.end(); mapIter++)
|
|
|
|
|
{
|
|
|
|
|
EffectVector& ef = mapIter->value;
|
|
|
|
|
|
|
|
|
|
for (U32 i = 0; i < ef.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
PostEffect* effect = ef[i];
|
|
|
|
|
|
|
|
|
|
if (effect->isEnabled())
|
|
|
|
|
effects.push_back(effect);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Resort the effects by priority.
|
|
|
|
|
effects.sort(&_effectPrioritySort);
|
|
|
|
|
|
|
|
|
|
Con::printf("PostEffectManager::dumpActivePostFX() - Beginning Dump");
|
|
|
|
|
|
|
|
|
|
for (U32 i = 0; i < effects.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
PostEffect* effect = effects[i];
|
|
|
|
|
|
|
|
|
|
if (effect->isEnabled())
|
|
|
|
|
{
|
|
|
|
|
Con::printf("%s", effect->getName());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Con::printf("PostEffectManager::dumpActivePostFX() - Ending Dump");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DefineEngineFunction(dumpActivePostFX, void, (),, "")
|
|
|
|
|
{
|
|
|
|
|
PFXMGR->dumpActivePostFX();
|
|
|
|
|
}
|