Engine directory for ticket #1

This commit is contained in:
DavidWyand-GG 2012-09-19 11:15:01 -04:00
parent 352279af7a
commit 7dbfe6994d
3795 changed files with 1363358 additions and 0 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,360 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#ifndef _POST_EFFECT_H_
#define _POST_EFFECT_H_
#ifndef _SIMSET_H_
#include "console/simSet.h"
#endif
#ifndef _MPOINT3_H_
#include "math/mPoint3.h"
#endif
#ifndef _MPOINT2_H_
#include "math/mPoint2.h"
#endif
#ifndef _GFXSHADER_H_
#include "gfx/gfxShader.h"
#endif
#ifndef _GFXSTATEBLOCK_H_
#include "gfx/gfxStateBlock.h"
#endif
#ifndef _GFXTEXTUREHANDLE_H_
#include "gfx/gfxTextureHandle.h"
#endif
#ifndef _GFXTARGET_H_
#include "gfx/gfxTarget.h"
#endif
#ifndef _GFXVERTEXBUFFER_H_
#include "gfx/gfxVertexBuffer.h"
#endif
#ifndef _POSTEFFECTCOMMON_H_
#include "postFx/postEffectCommon.h"
#endif
#ifndef _TDICTIONARY_H_
#include "core/util/tDictionary.h"
#endif
#ifndef _MATTEXTURETARGET_H_
#include "materials/matTextureTarget.h"
#endif
class GFXStateBlockData;
class Frustum;
class SceneRenderState;
class ConditionerFeature;
///
GFX_DeclareTextureProfile( PostFxTargetProfile );
///
class PostEffect : public SimGroup
{
typedef SimGroup Parent;
friend class PostEffectVis;
public:
enum
{
NumTextures = 6,
};
protected:
FileName mTexFilename[NumTextures];
GFXTexHandle mTextures[NumTextures];
NamedTexTarget mNamedTarget;
NamedTexTarget mNamedTargetDepthStencil;
GFXTextureObject *mActiveTextures[NumTextures];
NamedTexTarget *mActiveNamedTarget[NumTextures];
RectI mActiveTextureViewport[NumTextures];
GFXStateBlockData *mStateBlockData;
GFXStateBlockRef mStateBlock;
String mShaderName;
GFXShaderRef mShader;
Vector<GFXShaderMacro> mShaderMacros;
GFXShaderConstBufferRef mShaderConsts;
GFXShaderConstHandle *mRTSizeSC;
GFXShaderConstHandle *mOneOverRTSizeSC;
GFXShaderConstHandle *mTexSizeSC[NumTextures];
GFXShaderConstHandle *mRenderTargetParamsSC[NumTextures];
GFXShaderConstHandle *mViewportOffsetSC;
GFXShaderConstHandle *mFogDataSC;
GFXShaderConstHandle *mFogColorSC;
GFXShaderConstHandle *mEyePosSC;
GFXShaderConstHandle *mMatWorldToScreenSC;
GFXShaderConstHandle *mMatScreenToWorldSC;
GFXShaderConstHandle *mMatPrevScreenToWorldSC;
GFXShaderConstHandle *mNearFarSC;
GFXShaderConstHandle *mInvNearFarSC;
GFXShaderConstHandle *mWorldToScreenScaleSC;
GFXShaderConstHandle *mWaterColorSC;
GFXShaderConstHandle *mWaterFogDataSC;
GFXShaderConstHandle *mAmbientColorSC;
GFXShaderConstHandle *mWaterFogPlaneSC;
GFXShaderConstHandle *mWaterDepthGradMaxSC;
GFXShaderConstHandle *mScreenSunPosSC;
GFXShaderConstHandle *mLightDirectionSC;
GFXShaderConstHandle *mCameraForwardSC;
GFXShaderConstHandle *mAccumTimeSC;
GFXShaderConstHandle *mDeltaTimeSC;
GFXShaderConstHandle *mInvCameraMatSC;
bool mAllowReflectPass;
/// If true update the shader.
bool mUpdateShader;
GFXTextureTargetRef mTarget;
String mTargetName;
GFXTexHandle mTargetTex;
String mTargetDepthStencilName;
GFXTexHandle mTargetDepthStencil;
/// If mTargetSize is zero then this scale is
/// used to make a relative texture size to the
/// active render target.
Point2F mTargetScale;
/// If non-zero this is used as the absolute
/// texture target size.
/// @see mTargetScale
Point2I mTargetSize;
GFXFormat mTargetFormat;
/// The color to prefill the named target when
/// first created by the effect.
ColorF mTargetClearColor;
PFXRenderTime mRenderTime;
PFXTargetClear mTargetClear;
String mRenderBin;
F32 mRenderPriority;
/// This is true if the effect has been succesfully
/// initialized and all requirements are met for use.
bool mIsValid;
/// True if the effect has been enabled by the manager.
bool mEnabled;
/// Skip processing of this PostEffect and its children even if its parent is enabled.
/// Parent and sibling PostEffects in the chain are still processed.
/// This is intended for debugging purposes.
bool mSkip;
bool mOneFrameOnly;
bool mOnThisFrame;
U32 mShaderReloadKey;
class EffectConst
{
public:
EffectConst( const String &name, const String &val )
: mName( name ),
mHandle( NULL ),
mDirty( true )
{
set( val );
}
void set( const String &newVal );
void setToBuffer( GFXShaderConstBufferRef buff );
String mName;
GFXShaderConstHandle *mHandle;
String mStringVal;
bool mDirty;
};
typedef HashTable<StringCase,EffectConst*> EffectConstTable;
EffectConstTable mEffectConsts;
///
virtual void _updateScreenGeometry( const Frustum &frustum,
GFXVertexBufferHandle<PFXVertex> *outVB );
///
virtual void _setupStateBlock( const SceneRenderState *state );
///
virtual void _setupConstants( const SceneRenderState *state );
///
virtual void _setupTransforms();
///
virtual void _setupTarget( const SceneRenderState *state, bool *outClearTarget );
///
virtual void _setupTexture( U32 slot, GFXTexHandle &inputTex, const RectI *inTexViewport );
/// Protected set method for toggling the enabled state.
static bool _setIsEnabled( void *object, const char *index, const char *data );
/// Called from the light manager activate signal.
/// @see LightManager::addActivateCallback
void _onLMActivate( const char*, bool activate )
{
if ( activate )
mUpdateShader = true;
}
/// We handle texture events to release named rendered targets.
/// @see GFXTextureManager::addEventDelegate
void _onTextureEvent( GFXTexCallbackCode code )
{
if ( code == GFXZombify && (mNamedTarget.isRegistered() || mNamedTargetDepthStencil.isRegistered()) )
_cleanTargets();
}
///
void _updateConditioners();
///
void _cleanTargets( bool recurse = false );
///
void _checkRequirements();
///
GFXTextureObject* _getTargetTexture( U32 index );
public:
/// Constructor.
PostEffect();
/// Destructor.
virtual ~PostEffect();
DECLARE_CONOBJECT(PostEffect);
// SimObject
virtual bool onAdd();
virtual void onRemove();
static void initPersistFields();
/// @name Callbacks
/// @{
DECLARE_CALLBACK( void, onAdd, () );
DECLARE_CALLBACK( void, preProcess, () );
DECLARE_CALLBACK( void, setShaderConsts, () );
DECLARE_CALLBACK( bool, onEnabled, () );
DECLARE_CALLBACK( void, onDisabled, () );
/// @}
virtual void process( const SceneRenderState *state,
GFXTexHandle &inOutTex,
const RectI *inTexViewport = NULL );
///
void reload();
///
void enable();
///
void disable();
/// Dump the shader disassembly to a temporary text file.
/// Returns true and sets outFilename to the file if successful.
bool dumpShaderDisassembly( String &outFilename ) const;
/// Returns the SimSet which contains all PostEffects.
SimSet* getSet() const;
///
bool isEnabled() const { return mEnabled; }
/// Is set to skip rendering.
bool isSkipped() const { return mSkip; }
/// Set the effect to skip rendering.
void setSkip( bool skip ) { mSkip = skip; }
PFXRenderTime getRenderTime() const { return mRenderTime; }
const String& getRenderBin() const { return mRenderBin; }
F32 getPriority() const { return mRenderPriority; }
void setTexture( U32 index, const String &filePath );
void setShaderMacro( const String &name, const String &value = String::EmptyString );
bool removeShaderMacro( const String &name );
void clearShaderMacros();
///
void setShaderConst( const String &name, const String &val );
void setOnThisFrame( bool enabled ) { mOnThisFrame = enabled; }
bool isOnThisFrame() { return mOnThisFrame; }
void setOneFrameOnly( bool enabled ) { mOneFrameOnly = enabled; }
bool isOneFrameOnly() { return mOneFrameOnly; }
F32 getAspectRatio() const;
enum PostEffectRequirements
{
RequiresDepth = BIT(0),
RequiresNormals = BIT(1),
RequiresLightInfo = BIT(2),
};
};
#endif // _POST_EFFECT_H_

View file

@ -0,0 +1,99 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#ifndef _POSTEFFECTCOMMON_H_
#define _POSTEFFECTCOMMON_H_
#ifndef _DYNAMIC_CONSOLETYPES_H_
#include "console/dynamicTypes.h"
#endif
///
enum PFXRenderTime
{
/// Before a RenderInstManager bin.
PFXBeforeBin,
/// After a RenderInstManager bin.
PFXAfterBin,
/// After the diffuse rendering pass.
PFXAfterDiffuse,
/// When the end of the frame is reached.
PFXEndOfFrame,
/// This PostEffect is not processed by the manager.
/// It will generate its texture when it is requested.
PFXTexGenOnDemand
};
DefineEnumType( PFXRenderTime );
/// PFXTargetClear specifies whether and how
/// often a given PostEffect's target will be cleared.
enum PFXTargetClear
{
/// Never clear the PostEffect target.
PFXTargetClear_None,
/// Clear once on create.
PFXTargetClear_OnCreate,
/// Clear before every draw.
PFXTargetClear_OnDraw,
};
DefineEnumType( PFXTargetClear );
///
struct PFXFrameState
{
MatrixF worldToCamera;
MatrixF cameraToScreen;
PFXFrameState()
: worldToCamera( true ),
cameraToScreen( true )
{
}
};
///
GFX_DeclareTextureProfile( PostFxTextureProfile );
///
GFXDeclareVertexFormat( PFXVertex )
{
/// xyz position.
Point3F point;
/// The screen space texture coord.
Point2F texCoord;
///
Point3F wsEyeRay;
};
#endif // _POSTEFFECTCOMMON_H_

View file

@ -0,0 +1,321 @@
//-----------------------------------------------------------------------------
// 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() :
mFrameStateSwitch( false ),
mLastBackBufferTarget( NULL )
{
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.
EffectVector::iterator iter = find( mEndOfFrameList.begin(), mEndOfFrameList.end(), effect );
if ( iter != mEndOfFrameList.end() )
{
mEndOfFrameList.erase( iter );
return true;
}
// Check the diffuse list.
iter = find( mAfterDiffuseList.begin(), mAfterDiffuseList.end(), effect );
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;
iter = find( effects.begin(), effects.end(), effect );
if ( iter != effects.end() )
{
effects.erase( iter );
return true;
}
}
mapIter = mBeforeBinMap.begin();
for( ; mapIter != mBeforeBinMap.end(); mapIter++ )
{
EffectVector &effects = mapIter->value;
iter = find( effects.begin(), effects.end(), effect );
if ( iter != effects.end() )
{
effects.erase( iter );
return true;
}
}
return false;
}
void PostEffectManager::renderEffects( const SceneRenderState *state,
const PFXRenderTime effectTiming,
const String &binName )
{
// MACHAX - The proper fix is to ensure that PostFX do not get rendered if
// their shader failed to load.
#ifdef TORQUE_OS_MAC
return;
#endif
// 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;
}

View file

@ -0,0 +1,139 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#ifndef _POSTEFFECTMANAGER_H_
#define _POSTEFFECTMANAGER_H_
#ifndef _GFXDEVICE_H_
#include "gfx/gfxDevice.h"
#endif
#ifndef _TVECTOR_H_
#include "core/util/tVector.h"
#endif
#ifndef _TDICTIONARY_H_
#include "core/util/tDictionary.h"
#endif
#ifndef _TSINGLETON_H_
#include "core/util/tSingleton.h"
#endif
#ifndef _POSTEFFECTCOMMON_H_
#include "postFx/postEffectCommon.h"
#endif
class PostEffect;
class RenderBinManager;
class SceneRenderState;
class SceneManager;
class PostEffectManager
{
protected:
friend class PostEffect;
typedef Vector<PostEffect*> EffectVector;
typedef Map<String,EffectVector> EffectMap;
/// A global flag for toggling the post effect system. It
/// is tied to the $pref::enablePostEffects preference.
static bool smRenderEffects;
EffectVector mEndOfFrameList;
EffectVector mAfterDiffuseList;
EffectMap mAfterBinMap;
EffectMap mBeforeBinMap;
/// A copy of the last requested back buffer.
GFXTexHandle mBackBufferCopyTex;
//GFXTexHandle mBackBufferFloatCopyTex;
/// The target at the time the last back buffer
/// was copied. Used to detect the need to recopy.
GFXTarget *mLastBackBufferTarget;
// State for current frame and last frame
bool mFrameStateSwitch;
PFXFrameState mFrameState[2];
bool _handleDeviceEvent( GFXDevice::GFXDeviceEventType evt );
void _handleBinEvent( RenderBinManager *bin,
const SceneRenderState* sceneState,
bool isBinStart );
///
void _onPostRenderPass( SceneManager *sceneGraph, const SceneRenderState *sceneState );
// Helper method
void _updateResources();
///
static S32 _effectPrioritySort( PostEffect* const*e1, PostEffect* const*e2 );
bool _addEffect( PostEffect *effect );
bool _removeEffect( PostEffect *effect );
public:
PostEffectManager();
virtual ~PostEffectManager();
void renderEffects( const SceneRenderState *state,
const PFXRenderTime effectTiming,
const String &binName = String::EmptyString );
/// Returns the current back buffer texture taking
/// a copy of if the target has changed or the buffer
/// was previously released.
GFXTextureObject* getBackBufferTex();
/// Releases the current back buffer so that a
/// new copy is made on the next request.
void releaseBackBufferTex();
/*
bool submitEffect( PostEffect *effect, const PFXRenderTime renderTime = PFXDefaultRenderTime, const GFXRenderBinTypes afterBin = GFXBin_DefaultPostProcessBin )
{
return _addEntry( effect, false, renderTime, afterBin );
}
*/
// State interface
const PFXFrameState &getFrameState() const { return mFrameState[mFrameStateSwitch]; }
const PFXFrameState &getLastFrameState() const { return mFrameState[!mFrameStateSwitch]; }
void setFrameMatrices( const MatrixF &worldToCamera, const MatrixF &cameraToScreen );
// For ManagedSingleton.
static const char* getSingletonName() { return "PostEffectManager"; }
};
/// Returns the PostEffectManager singleton.
#define PFXMGR ManagedSingleton<PostEffectManager>::instance()
#endif // _POSTEFFECTMANAGER_H_

View file

@ -0,0 +1,458 @@
//-----------------------------------------------------------------------------
// 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/postEffectVis.h"
#include "gui/containers/guiWindowCtrl.h"
#include "gui/controls/guiBitmapCtrl.h"
#include "gui/core/guiCanvas.h"
#include "postFx/postEffectManager.h"
#include "core/module.h"
ConsoleDoc(
"@class PfxVis\n"
"@brief Singleton class that exposes ConsoleStaticFunctions for debug visualizing PostEffects.\n\n"
"@tsexample\n"
"// Script interface...\n"
"PfxVis::open( PostEffect ) // Multiple PostEffects can be visualized at the same time\n"
"PfxVis::clear() // Clear all visualizer windows\n"
"PfxVis::hide() // Hide all windows (are not destroyed)\n"
"PfxVis::show()\n"
"@endtsexample\n\n"
"@ingroup GFX\n"
);
MODULE_BEGIN( PostEffectVis )
MODULE_INIT
{
ManagedSingleton< PostEffectVis >::createSingleton();
}
MODULE_SHUTDOWN
{
ManagedSingleton< PostEffectVis >::deleteSingleton();
}
MODULE_END;
PostEffectVis::PostEffectVis()
: mContent( NULL )
{
}
PostEffectVis::~PostEffectVis()
{
}
void PostEffectVis::open( PostEffect *pfx )
{
GuiControl *content = _getContentControl();
// If we already have this PostEffect added
// remove it first so we can recreate its controls.
VisVector::iterator itr = mWindows.begin();
for ( ; itr != mWindows.end(); itr++ )
{
if ( itr->pfx == pfx )
{
for ( U32 i = 0; i < TexCount; i++ )
{
// Deleting the GuiWindowCtrl will automatically also delete
// any child controls we have allocated.
if ( itr->window[i] )
itr->window[i]->deleteObject();
}
mWindows.erase_fast( itr );
break;
}
}
// Allocate VisWindow struct.
mWindows.increment();
VisWindow &window = mWindows.last();
window.pfx = pfx;
for ( U32 i = 0; i < TexCount; i++ )
{
// Only allocate window/bitmaps for input textures that are actually used.
if ( i > Target )
{
if ( pfx->mTexFilename[i-1].isEmpty() )
{
window.window[i] = NULL;
window.bmp[i] = NULL;
continue;
}
}
// Allocate GuiWindowCtrl
GuiWindowCtrl *winCtrl = new GuiWindowCtrl();
winCtrl->setPosition( Point2I( 50, 50 ) + Point2I( 15, 15 ) * i );
winCtrl->setExtent( 347, 209 );
winCtrl->setMinExtent( Point2I( 150, 100 ) );
winCtrl->setMobility( true, true, true, true, false, false );
winCtrl->setCanResize( true, true );
winCtrl->setDataField( StringTable->insert( "closeCommand" ), NULL, "PfxVis::onWindowClosed( $ThisControl );" );
winCtrl->registerObject();
window.window[i] = winCtrl;
_setDefaultCaption( window, i );
// Allocate background GuiBitmapCtrl
GuiBitmapCtrl *bmpCtrl = new GuiBitmapCtrl();
bmpCtrl->setPosition( 3, 23 );
bmpCtrl->setSizing( GuiControl::horizResizeWidth, GuiControl::vertResizeHeight );
bmpCtrl->setExtent( 341, 181 );
bmpCtrl->setDataField( StringTable->insert( "wrap" ), NULL, "1" );
bmpCtrl->setBitmap( "core/art/gui/images/transp_grid" );
bmpCtrl->registerObject();
winCtrl->addObject( bmpCtrl );
// Allocate GuiBitmapCtrl
bmpCtrl = new GuiBitmapCtrl();
bmpCtrl->setPosition( 3, 23 );
bmpCtrl->setSizing( GuiControl::horizResizeWidth, GuiControl::vertResizeHeight );
bmpCtrl->setExtent( 341, 181 );
bmpCtrl->registerObject();
winCtrl->addObject( bmpCtrl );
window.bmp[i] = bmpCtrl;
content->addObject( winCtrl );
}
// Make sure we visible.
setVisible( true );
}
void PostEffectVis::setVisible( bool visible )
{
GuiCanvas *canvas = NULL;
if ( !Sim::findObject( "Canvas", canvas ) )
{
Con::errorf( "PostEffectVis::setVisible, Canvas was not found." );
return;
}
GuiControl *content = _getContentControl();
if ( visible && !content->isAwake() )
canvas->pushDialogControl( content, 100 );
if ( !visible && content->isAwake() )
canvas->popDialogControl( content );
}
void PostEffectVis::clear()
{
GuiControl *content = _getContentControl();
content->clear();
mWindows.clear();
}
void PostEffectVis::onStartOfFrame()
{
if ( mWindows.empty() )
return;
if ( !_getContentControl()->isAwake() )
return;
// Restore vis windows to a default state.
// This ensures to users that open PostEffects that are not
// actively being processed are obvious.
VisVector::iterator itr = mWindows.begin();
for ( ; itr != mWindows.end(); itr++ )
{
for ( U32 i = 0; i < TexCount; i++ )
{
if ( !itr->bmp[i] || itr->pfx->getRenderTime() == PFXTexGenOnDemand )
continue;
itr->bmp[i]->setBitmap( NULL );
_setDefaultCaption( *itr, i );
}
}
}
void PostEffectVis::onPFXProcessed( PostEffect *pfx )
{
// If we have no windows we can early out before even testing
// isAwake so we avoid creating the content control unnecessarily.
if ( mWindows.empty() )
return;
if ( !_getContentControl()->isAwake() )
return;
VisVector::iterator itr = mWindows.begin();
for ( ; itr != mWindows.end(); itr++ )
{
if ( itr->pfx == pfx )
{
GuiBitmapCtrl *pBmpCtrl = NULL;
GuiWindowCtrl *pWinCtrl = NULL;
if ( itr->bmp[Target] != NULL )
{
pBmpCtrl = itr->bmp[Target];
pWinCtrl = itr->window[Target];
GFXTextureObject *tex;
if ( pfx->mTargetTex )
tex = pfx->mTargetTex;
else
tex = PFXMGR->getBackBufferTex();
pBmpCtrl->setBitmapHandle( tex );
char caption[256];
char name[256];
if ( pfx->getName() == NULL || dStrlen( pfx->getName() ) == 0 )
dSprintf( name, 256, "(none)" );
else
dSprintf( name, 256, "%s", pfx->getName() );
if ( tex )
dSprintf( caption, 256, "%s[%i] target - %s [ %ix%i ]", name, pfx->getId(), pfx->mTargetName.c_str(), tex->getWidth(), tex->getHeight() );
else
dSprintf( caption, 256, "%s[%i] target", name, pfx->getId() );
pWinCtrl->setDataField( StringTable->insert("text"), NULL, caption );
}
for ( U32 i = Input1; i < TexCount; i++ )
{
if ( itr->bmp[i] == NULL )
continue;
pBmpCtrl = itr->bmp[i];
pWinCtrl = itr->window[i];
GFXTextureObject *tex = pfx->mActiveTextures[i-1];
pBmpCtrl->setBitmapHandle( tex );
char caption[256];
char name[256];
if ( pfx->getName() == NULL || dStrlen( pfx->getName() ) == 0 )
dSprintf( name, 256, "(none)" );
else
dSprintf( name, 256, "%s", pfx->getName() );
if ( tex )
dSprintf( caption, 256, "%s[%i] input%i - %s [ %ix%i ]", name, pfx->getId(), i-1, pfx->mTexFilename[i-1].c_str(), tex->getWidth(), tex->getHeight() );
else
dSprintf( caption, 256, "%s[%i] input%i - %s", name, pfx->getId(), i-1, pfx->mTexFilename[i-1].c_str() );
pWinCtrl->setDataField( StringTable->insert("text"), NULL, caption );
}
}
}
}
void PostEffectVis::onWindowClosed( GuiWindowCtrl *ctrl )
{
VisVector::iterator itr = mWindows.begin();
for ( ; itr != mWindows.end(); itr++ )
{
for ( U32 i = 0; i < TexCount; i++ )
{
if ( itr->window[i] == ctrl )
{
itr->window[i] = NULL;
itr->bmp[i] = NULL;
ctrl->setVisible( false );
// Avoid deleting immediately since this happens in response to a
// script callback.
Con::evaluate( "%i.schedule( 1, \"delete\" );" );
return;
}
}
}
Con::errorf( "PostEffectVis::onWindowClosed, passed window (%s) [%i] was found.", StringTable->insert( ctrl->getName() ), ctrl->getId() );
}
GuiControl* PostEffectVis::_getContentControl()
{
if ( mContent == NULL )
{
GuiCanvas *canvas = NULL;
if ( !Sim::findObject( "Canvas", canvas ) )
{
AssertFatal( false, "PostEffectVis::_getContentControl, Canvas not found." );
return NULL;
}
mContent = new GuiControl();
mContent->setPosition( 0, 0 );
mContent->setExtent( 1024, 768 );
mContent->setDataField( StringTable->insert( "noCursor" ), NULL, "1" );
mContent->setDataField( StringTable->insert( "profile" ), NULL, "GuiModelessDialogProfile" );
mContent->registerObject( "PfxVisContent" );
canvas->pushDialogControl( mContent, 100 );
}
return mContent;
}
void PostEffectVis::_setDefaultCaption( VisWindow &vis, U32 texIndex )
{
PostEffect *pfx = vis.pfx;
GuiWindowCtrl *winCtrl = vis.window[texIndex];
if ( texIndex == Target )
{
char caption[256];
char name[256];
if ( pfx->getName() == NULL || dStrlen( pfx->getName() ) == 0 )
dSprintf( name, 256, "(none)" );
else
dSprintf( name, 256, "%s", pfx->getName() );
dSprintf( caption, 256, "%s[%i] target [NOT ENABLED]", name, pfx->getId() );
winCtrl->setDataField( StringTable->insert("text"), NULL, caption );
}
else
{
char caption[256];
char name[256];
if ( pfx->getName() == NULL || dStrlen( pfx->getName() ) == 0 )
dSprintf( name, 256, "(none)" );
else
dSprintf( name, 256, "%s", pfx->getName() );
dSprintf( caption, 256, "%s[%i] input%i - %s [NOT ENABLED]", name, pfx->getId(), texIndex-1, pfx->mTexFilename[texIndex-1].c_str() );
winCtrl->setDataField( StringTable->insert("text"), NULL, caption );
}
}
static ConsoleDocFragment _PfxVisclear(
"@brief Close all visualization windows.\n\n"
"@tsexample\n"
"PfxVis::clear();"
"@endtsexample\n\n",
"PfxVis",
"void clear();" );
ConsoleStaticMethod( PfxVis, clear, void, 1, 1, "()"
"@hide")
{
PFXVIS->clear();
}
static ConsoleDocFragment _PfxVisopen(
"@brief Open visualization windows for all input and target textures.\n\n"
"@param effect Name of the PostEffect to open\n"
"@param clear True to close all visualization windows before opening the effect\n\n"
"@tsexample\n"
"// Multiple PostEffects can be visualized at the same time\n"
"PfxVis::open( PostEffect )\n"
"@endtsexample\n\n",
"PfxVis",
"void open(PostEffect effect, bool clear);" );
ConsoleStaticMethod( PfxVis, open, void, 2, 3, "( PostEffect, [bool clear = false] )"
"@hide")
{
if ( argc == 3 && dAtob( argv[2] ) )
PFXVIS->clear();
PostEffect *pfx;
if ( !Sim::findObject( argv[1], pfx ) )
{
Con::errorf( "PfxVis::add, argument %s was not a PostEffect", argv[1] );
return;
}
PFXVIS->open( pfx );
}
static ConsoleDocFragment _PfxVishide(
"@brief Hide all visualization windows (they are not destroyed).\n\n"
"@tsexample\n"
"PfxVis::hide();"
"@endtsexample\n\n",
"PfxVis",
"void hide();" );
ConsoleStaticMethod( PfxVis, hide, void, 1, 1, "()"
"@hide")
{
PFXVIS->setVisible( false );
}
static ConsoleDocFragment _PfxVisshow(
"@brief Show all visualization windows.\n\n"
"@tsexample\n"
"PfxVis::show();"
"@endtsexample\n\n",
"PfxVis",
"void show();" );
ConsoleStaticMethod( PfxVis, show, void, 1, 1, "()"
"@hide")
{
PFXVIS->setVisible( true );
}
static ConsoleDocFragment _PfxVisonWindowClosed(
"@brief Callback when a visualization window is closed.\n\n"
"@param ctrl Name of the GUI control being closed\n"
"@tsexample\n"
"PfxVis::onWindowClosed( VisWindow )\n"
"@endtsexample\n\n",
"PfxVis",
"void onWindowClosed(GuiWindowCtrl *ctrl);" );
ConsoleStaticMethod( PfxVis, onWindowClosed, void, 2, 2, "( GuiWindowCtrl )"
"@hide")
{
GuiWindowCtrl *ctrl;
if ( !Sim::findObject( argv[1], ctrl ) )
{
Con::errorf( "PfxVis::onWindowClosed, argument %s was not a GuiWindowCtrl", argv[1] );
return;
}
PFXVIS->onWindowClosed( ctrl );
}

View file

@ -0,0 +1,110 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#ifndef _POSTEFFECTVIS_H_
#define _POSTEFFECTVIS_H_
#ifndef _TSINGLETON_H_
#include "core/util/tSingleton.h"
#endif
#ifndef _POST_EFFECT_H_
#include "postFx/postEffect.h"
#endif
class GuiWindowCtrl;
class GuiBitmapCtrl;
class GuiControl;
class PostEffectVis
{
// Protected constructor.
// Use PFXVIS define to access singleton.
PostEffectVis();
friend class ManagedSingleton<PostEffectVis>;
public:
~PostEffectVis();
/// Open visualization windows for all input and target textures.
void open( PostEffect *pfx );
/// Close all visualization windows.
void clear();
/// Hide or show all visualization windows.
void setVisible( bool visible );
/// Callback from PostEffectManager at the start of a frame.
void onStartOfFrame();
/// Callback from PostEffect to update visualization.
void onPFXProcessed( PostEffect *pfx );
/// Callback when a visualization window is closed.
void onWindowClosed( GuiWindowCtrl *ctrl );
protected:
/// Get or create the content control, the parent of all visualization windows.
GuiControl* _getContentControl();
protected:
enum TexIndex
{
Target = 0,
Input1,
Input2,
Input3,
Input4,
TexCount
};
/// Structure representing a single 'opened' PostEffect
/// including GuiControls for displaying any input/target textures.
struct VisWindow
{
PostEffect *pfx;
GuiWindowCtrl *window[TexCount];
GuiBitmapCtrl *bmp[TexCount];
};
void _setDefaultCaption( VisWindow &vis, U32 texIndex );
typedef Vector< VisWindow > VisVector;
VisVector mWindows;
GuiControl *mContent;
public:
// For ManagedSingleton.
static const char* getSingletonName() { return "PostEffectVis"; }
};
/// Returns the PostEffectVis singleton.
#define PFXVIS ManagedSingleton<PostEffectVis>::instance()
#endif // _POSTEFFECTVIS_H_