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

View file

@ -0,0 +1,134 @@
//-----------------------------------------------------------------------------
// 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 "renderInstance/forcedMaterialMeshMgr.h"
#include "gfx/gfxTransformSaver.h"
#include "gfx/gfxPrimitiveBuffer.h"
#include "gfx/gfxDebugEvent.h"
#include "materials/sceneData.h"
#include "materials/materialManager.h"
#include "materials/materialDefinition.h"
#include "console/consoleTypes.h"
#include "math/util/matrixSet.h"
IMPLEMENT_CONOBJECT(ForcedMaterialMeshMgr);
ConsoleDocClass( ForcedMaterialMeshMgr,
"@brief Basically the same as RenderMeshMgr, but will override the material "
"of the instance. Exists for backwards compatibility, not currently used, soon to be deprecated\n\n"
"@internal"
);
ForcedMaterialMeshMgr::ForcedMaterialMeshMgr()
{
mOverrideInstance = NULL;
mOverrideMaterial = NULL;
}
ForcedMaterialMeshMgr::ForcedMaterialMeshMgr(RenderInstType riType, F32 renderOrder, F32 processAddOrder, BaseMatInstance* overrideMaterial)
: RenderMeshMgr(riType, renderOrder, processAddOrder)
{
mOverrideInstance = overrideMaterial;
mOverrideMaterial = NULL;
}
void ForcedMaterialMeshMgr::setOverrideMaterial(BaseMatInstance* overrideMaterial)
{
SAFE_DELETE(mOverrideInstance);
mOverrideInstance = overrideMaterial;
}
ForcedMaterialMeshMgr::~ForcedMaterialMeshMgr()
{
setOverrideMaterial(NULL);
}
void ForcedMaterialMeshMgr::initPersistFields()
{
addProtectedField("material", TYPEID< Material >(), Offset(mOverrideMaterial, ForcedMaterialMeshMgr),
&_setOverrideMat, &_getOverrideMat, "Material used to draw all meshes in the render bin.");
Parent::initPersistFields();
}
void ForcedMaterialMeshMgr::render(SceneRenderState * state)
{
PROFILE_SCOPE(ForcedMaterialMeshMgr_render);
if(!mOverrideInstance && mOverrideMaterial.isValid())
{
mOverrideInstance = mOverrideMaterial->createMatInstance();
mOverrideInstance->init( MATMGR->getDefaultFeatures(), getGFXVertexFormat<GFXVertexPNTBT>() );
}
// Early out if nothing to draw.
if(!mElementList.size() || !mOverrideInstance)
return;
GFXDEBUGEVENT_SCOPE(ForcedMaterialMeshMgr_Render, ColorI::RED);
// Automagically save & restore our viewport and transforms.
GFXTransformSaver saver;
// init loop data
SceneData sgData;
sgData.init( state );
MeshRenderInst *ri = static_cast<MeshRenderInst*>(mElementList[0].inst);
setupSGData( ri, sgData );
while (mOverrideInstance->setupPass(state, sgData))
{
for( U32 j=0; j<mElementList.size(); j++)
{
MeshRenderInst* passRI = static_cast<MeshRenderInst*>(mElementList[j].inst);
if(passRI->primBuff->getPointer()->mPrimitiveArray[passRI->primBuffIndex].numVertices < 1)
continue;
getRenderPass()->getMatrixSet().setWorld(*passRI->objectToWorld);
getRenderPass()->getMatrixSet().setView(*passRI->worldToCamera);
getRenderPass()->getMatrixSet().setProjection(*passRI->projection);
mOverrideInstance->setTransforms(getRenderPass()->getMatrixSet(), state);
mOverrideInstance->setBuffers(passRI->vertBuff, passRI->primBuff);
GFX->drawPrimitive( passRI->primBuffIndex );
}
}
}
const char* ForcedMaterialMeshMgr::_getOverrideMat( void *object, const char *data )
{
ForcedMaterialMeshMgr &mgr = *reinterpret_cast<ForcedMaterialMeshMgr *>( object );
if( mgr.mOverrideMaterial.isValid() )
return mgr.mOverrideMaterial->getIdString();
else
return "0";
}
bool ForcedMaterialMeshMgr::_setOverrideMat( void *object, const char *index, const char *data )
{
ForcedMaterialMeshMgr &mgr = *reinterpret_cast<ForcedMaterialMeshMgr *>( object );
BaseMatInstance* material;
Sim::findObject( data, material );
mgr.setOverrideMaterial( material );
return false;
}

View file

@ -0,0 +1,55 @@
//-----------------------------------------------------------------------------
// 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 _RENDERFORCEDMATMESHMGR_H_
#define _RENDERFORCEDMATMESHMGR_H_
#ifndef _RENDERMESHMGR_H_
#include "renderInstance/renderMeshMgr.h"
#endif
class Material;
/// Basically the same as RenderMeshMgr, but will override the material of the instance.
class ForcedMaterialMeshMgr : public RenderMeshMgr
{
typedef RenderMeshMgr Parent;
public:
ForcedMaterialMeshMgr();
ForcedMaterialMeshMgr(RenderInstType riType, F32 renderOrder, F32 processAddOrder, BaseMatInstance* overrideMaterial);
virtual ~ForcedMaterialMeshMgr();
void setOverrideMaterial(BaseMatInstance* overrideMaterial);
// RenderBinManager interface
virtual void render(SceneRenderState * state);
DECLARE_CONOBJECT(ForcedMaterialMeshMgr);
static void initPersistFields();
private:
BaseMatInstance* mOverrideInstance;
SimObjectPtr<Material> mOverrideMaterial;
static const char* _getOverrideMat( void* object, const char* data );
static bool _setOverrideMat( void *object, const char *index, const char *data );
};
#endif

View file

@ -0,0 +1,177 @@
//-----------------------------------------------------------------------------
// 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/renderBinManager.h"
#include "console/consoleTypes.h"
#include "materials/matInstance.h"
#include "scene/sceneManager.h"
#include "console/engineAPI.h"
IMPLEMENT_CONOBJECT(RenderBinManager);
RenderBinManager::RenderBinManager( const RenderInstType& ritype, F32 renderOrder, F32 processAddOrder ) :
mRenderInstType( ritype ),
mRenderOrder( renderOrder ),
mProcessAddOrder( processAddOrder ),
mRenderPass( NULL )
{
VECTOR_SET_ASSOCIATION( mElementList );
mElementList.reserve( 2048 );
}
ConsoleDocClass( RenderBinManager,
"@brief The abstract base for all render bins.\n\n"
"The render bins are used by the engine as a high level method to order and batch rendering "
"operations.\n"
"@ingroup RenderBin\n" );
void RenderBinManager::initPersistFields()
{
addField( "binType", TypeRealString, Offset(mRenderInstType.mName, RenderBinManager),
"Sets the render bin type which limits what render instances are added to this bin." );
addField("renderOrder", TypeF32, Offset(mRenderOrder, RenderBinManager),
"Defines the order for rendering in relation to other bins." );
addField("processAddOrder", TypeF32, Offset(mProcessAddOrder, RenderBinManager),
"Defines the order for adding instances in relation to other bins." );
Parent::initPersistFields();
}
void RenderBinManager::onRemove()
{
// Tell the render pass to remove us when
// we're being unregistered.
if ( mRenderPass )
mRenderPass->removeManager( this );
Parent::onRemove();
}
void RenderBinManager::notifyType( const RenderInstType &type )
{
// Avoid duplicate types.
if ( !type.isValid() ||
mRenderInstType == type ||
mOtherTypes.contains( type ) )
return;
mOtherTypes.push_back( type );
// Register for the signal if the pass
// has already been assigned.
if ( mRenderPass )
mRenderPass->getAddSignal(type).notify( this, &RenderBinManager::addElement, mProcessAddOrder );
}
void RenderBinManager::setRenderPass( RenderPassManager *rpm )
{
if ( mRenderPass )
{
if ( mRenderInstType.isValid() )
mRenderPass->getAddSignal(mRenderInstType).remove( this, &RenderBinManager::addElement );
for ( U32 i=0; i < mOtherTypes.size(); i++ )
mRenderPass->getAddSignal(mOtherTypes[i]).remove( this, &RenderBinManager::addElement );
}
mRenderPass = rpm;
if ( mRenderPass )
{
if ( mRenderInstType.isValid() )
mRenderPass->getAddSignal(mRenderInstType).notify( this, &RenderBinManager::addElement, mProcessAddOrder );
for ( U32 i=0; i < mOtherTypes.size(); i++ )
mRenderPass->getAddSignal(mOtherTypes[i]).notify( this, &RenderBinManager::addElement, mProcessAddOrder );
}
}
void RenderBinManager::addElement( RenderInst *inst )
{
internalAddElement(inst);
}
void RenderBinManager::internalAddElement(RenderInst* inst)
{
mElementList.increment();
MainSortElem &elem = mElementList.last();
elem.inst = inst;
elem.key = elem.key2 = 0;
elem.key = inst->defaultKey;
elem.key2 = inst->defaultKey2;
}
void RenderBinManager::clear()
{
mElementList.clear();
}
void RenderBinManager::sort()
{
dQsort( mElementList.address(), mElementList.size(), sizeof(MainSortElem), cmpKeyFunc);
}
S32 FN_CDECL RenderBinManager::cmpKeyFunc(const void* p1, const void* p2)
{
const MainSortElem* mse1 = (const MainSortElem*) p1;
const MainSortElem* mse2 = (const MainSortElem*) p2;
S32 test1 = S32(mse2->key) - S32(mse1->key);
return ( test1 == 0 ) ? S32(mse1->key2) - S32(mse2->key2) : test1;
}
void RenderBinManager::setupSGData( MeshRenderInst *ri, SceneData &data )
{
PROFILE_SCOPE( RenderBinManager_setupSGData );
// NOTE: We do not reset or clear the scene state
// here as the caller has initialized non-RI members
// himself and we must preserve them.
//
// It also saves a bunch of CPU as this is called for
// every MeshRenderInst in every pass.
dMemcpy( data.lights, ri->lights, sizeof( data.lights ) );
data.objTrans = ri->objectToWorld;
data.backBuffTex = ri->backBuffTex;
data.cubemap = ri->cubemap;
data.miscTex = ri->miscTex;
data.reflectTex = ri->reflectTex;
data.lightmap = ri->lightmap;
data.visibility = ri->visibility;
data.materialHint = ri->materialHint;
}
DefineEngineMethod( RenderBinManager, getBinType, const char*, (),,
"Returns the bin type string." )
{
return object->getRenderInstType().getName();
}

View file

@ -0,0 +1,170 @@
//-----------------------------------------------------------------------------
// 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 _RENDERBINMANAGER_H_
#define _RENDERBINMANAGER_H_
#ifndef _CONSOLEOBJECT_H_
#include "console/consoleObject.h"
#endif
#ifndef _RENDERPASSMANAGER_H_
#include "renderInstance/renderPassManager.h"
#endif
#ifndef _BASEMATINSTANCE_H_
#include "materials/baseMatInstance.h"
#endif
#ifndef _UTIL_DELEGATE_H_
#include "core/util/delegate.h"
#endif
class SceneRenderState;
/// This delegate is used in derived RenderBinManager classes
/// to allow material instances to be overriden.
typedef Delegate<BaseMatInstance*(BaseMatInstance*)> MaterialOverrideDelegate;
/// The RenderBinManager manages and renders lists of MainSortElem, which
/// is a light wrapper around RenderInst.
class RenderBinManager : public SimObject
{
typedef SimObject Parent;
friend class RenderPassManager;
public:
RenderBinManager( const RenderInstType& ritype = RenderInstType::Invalid,
F32 renderOrder = 1.0f,
F32 processAddOrder = 1.0f );
virtual ~RenderBinManager() {}
// SimObject
void onRemove();
virtual void addElement( RenderInst *inst );
virtual void sort();
virtual void render( SceneRenderState *state ) {}
virtual void clear();
// Manager info
F32 getProcessAddOrder() const { return mProcessAddOrder; }
void setProcessAddOrder(F32 processAddOrder) { mProcessAddOrder = processAddOrder; }
F32 getRenderOrder() const { return mRenderOrder; }
void setRenderOrder(F32 renderOrder) { mRenderOrder = renderOrder; }
/// Returns the primary render instance type.
const RenderInstType& getRenderInstType() { return mRenderInstType; }
/// Returns the render pass this bin is registered to.
RenderPassManager* getRenderPass() const { return mRenderPass; }
/// QSort callback function
static S32 FN_CDECL cmpKeyFunc(const void* p1, const void* p2);
DECLARE_CONOBJECT(RenderBinManager);
static void initPersistFields();
MaterialOverrideDelegate& getMatOverrideDelegate() { return mMatOverrideDelegate; }
protected:
struct MainSortElem
{
RenderInst *inst;
U32 key;
U32 key2;
};
void setRenderPass( RenderPassManager *rpm );
/// Called from derived bins to add additional
/// render instance types to be notified about.
void notifyType( const RenderInstType &type );
Vector< MainSortElem > mElementList; // List of our instances
F32 mProcessAddOrder; // Where in the list do we process RenderInstance additions?
F32 mRenderOrder; // Where in the list do we render?
/// The primary render instance type this bin supports.
RenderInstType mRenderInstType;
/// The list of additional render instance types
/// this bin wants to process.
Vector<RenderInstType> mOtherTypes;
/// The render pass manager this bin is registered with.
RenderPassManager *mRenderPass;
MaterialOverrideDelegate mMatOverrideDelegate;
virtual void setupSGData(MeshRenderInst *ri, SceneData &data );
virtual void internalAddElement(RenderInst* inst);
/// A inlined helper method for testing if the next
/// MeshRenderInst requires a new batch/pass.
inline bool newPassNeeded( MeshRenderInst *ri, MeshRenderInst* nextRI ) const;
/// Inlined utility function which gets the material from the
/// RenderInst if available, otherwise, return NULL.
inline BaseMatInstance* getMaterial( RenderInst *inst ) const;
};
inline bool RenderBinManager::newPassNeeded( MeshRenderInst *ri, MeshRenderInst* nextRI ) const
{
if ( ri == nextRI )
return false;
// We can depend completely on the state hint to check
// for changes in the material as it uniquely identifies it.
if ( ri->matInst->getStateHint() != nextRI->matInst->getStateHint() )
return true;
if ( ri->vertBuff != nextRI->vertBuff ||
ri->primBuff != nextRI->primBuff ||
ri->prim != nextRI->prim ||
ri->primBuffIndex != nextRI->primBuffIndex ||
// NOTE: Keep an eye on this... should we find a more
// optimal test for light set changes?
//
dMemcmp( ri->lights, nextRI->lights, sizeof( ri->lights ) ) != 0 )
return true;
return false;
}
inline BaseMatInstance* RenderBinManager::getMaterial( RenderInst *inst ) const
{
if ( inst->type == RenderPassManager::RIT_Mesh ||
inst->type == RenderPassManager::RIT_Interior ||
inst->type == RenderPassManager::RIT_Decal ||
inst->type == RenderPassManager::RIT_Translucent )
return static_cast<MeshRenderInst*>(inst)->matInst;
return NULL;
}
#endif // _RENDERBINMANAGER_H_

View file

@ -0,0 +1,375 @@
//-----------------------------------------------------------------------------
// 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)
{
mTargetColorTexture[i].set( rtSize.x, rtSize.y, mColorFormat,
&GFXDefaultRenderTargetProfile, avar( "%s() - (line %d)", __FUNCTION__, __LINE__ ),
1, mTargetAALevel );
mTargetChain[i]->attachTexture( GFXTextureTarget::Color0, mTargetColorTexture[i] );
}
mTargetChain[i]->attachTexture( GFXTextureTarget::Color0, mTargetColorTexture[i] );
// Update depth target
if(mDepthFormat != GFXFormat_COUNT)
{
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(int 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();
}

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 _RENDERFORMATCHANGER_H_
#define _RENDERFORMATCHANGER_H_
#ifndef _RENDERPASSSTATETOKEN_H_
#include "renderInstance/renderPassStateToken.h"
#endif
#ifndef _MATTEXTURETARGET_H_
#include "materials/matTextureTarget.h"
#endif
class PostEffect;
class RenderFormatToken : public RenderPassStateToken
{
typedef RenderPassStateToken Parent;
public:
enum FormatTokenState
{
FTSDisabled,
FTSWaiting,
FTSActive,
FTSComplete,
};
const static U32 TargetChainLength = 1;
protected:
FormatTokenState mFCState;
GFXFormat mColorFormat;
GFXFormat mDepthFormat;
bool mTargetUpdatePending;
U32 mTargetChainIdx;
Point2I mTargetSize;
S32 mTargetAALevel;
SimObjectPtr<PostEffect> mCopyPostEffect;
SimObjectPtr<PostEffect> mResolvePostEffect;
NamedTexTarget mTarget;
GFXTexHandle mTargetColorTexture[TargetChainLength];
GFXTexHandle mTargetDepthStencilTexture[TargetChainLength];
GFXTextureTargetRef mTargetChain[TargetChainLength];
GFXTexHandle mStoredPassZTarget;
void _updateTargets();
void _teardownTargets();
void _onTextureEvent( GFXTexCallbackCode code );
virtual bool _handleGFXEvent(GFXDevice::GFXDeviceEventType event);
static bool _setFmt( void *object, const char *index, const char *data );
static const char* _getCopyPostEffect( void* object, const char* data );
static const char* _getResolvePostEffect( void* object, const char* data );
static bool _setCopyPostEffect( void* object, const char* index, const char* data );
static bool _setResolvePostEffect( void* object, const char* index, const char* data );
public:
DECLARE_CONOBJECT(RenderFormatToken);
static void initPersistFields();
virtual bool onAdd();
virtual void onRemove();
RenderFormatToken();
virtual ~RenderFormatToken();
virtual void process(SceneRenderState *state, RenderPassStateBin *callingBin);
virtual void reset();
virtual void enable(bool enabled = true);
virtual bool isEnabled() const;
};
#endif // _RENDERFORMATCHANGER_H_

View file

@ -0,0 +1,223 @@
//-----------------------------------------------------------------------------
// 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/renderGlowMgr.h"
#include "scene/sceneManager.h"
#include "scene/sceneRenderState.h"
#include "materials/sceneData.h"
#include "materials/matInstance.h"
#include "materials/materialFeatureTypes.h"
#include "materials/processedMaterial.h"
#include "postFx/postEffect.h"
#include "gfx/gfxTransformSaver.h"
#include "gfx/gfxDebugEvent.h"
#include "math/util/matrixSet.h"
IMPLEMENT_CONOBJECT( RenderGlowMgr );
ConsoleDocClass( RenderGlowMgr,
"@brief A render bin for the glow pass.\n\n"
"When the glow buffer PostEffect is enabled this bin gathers mesh render "
"instances with glow materials and renders them to the #glowbuffer offscreen "
"render target.\n\n"
"This render target is then used by the 'GlowPostFx' PostEffect to blur and "
"render the glowing portions of the screen.\n\n"
"@ingroup RenderBin\n" );
const MatInstanceHookType RenderGlowMgr::GlowMaterialHook::Type( "Glow" );
RenderGlowMgr::GlowMaterialHook::GlowMaterialHook( BaseMatInstance *matInst )
: mGlowMatInst( NULL )
{
mGlowMatInst = (MatInstance*)matInst->getMaterial()->createMatInstance();
mGlowMatInst->getFeaturesDelegate().bind( &GlowMaterialHook::_overrideFeatures );
mGlowMatInst->init( matInst->getRequestedFeatures(),
matInst->getVertexFormat() );
}
RenderGlowMgr::GlowMaterialHook::~GlowMaterialHook()
{
SAFE_DELETE( mGlowMatInst );
}
void RenderGlowMgr::GlowMaterialHook::_overrideFeatures( ProcessedMaterial *mat,
U32 stageNum,
MaterialFeatureData &fd,
const FeatureSet &features )
{
// If this isn't a glow pass... then add the glow mask feature.
if ( mat->getMaterial() &&
!mat->getMaterial()->mGlow[stageNum] )
fd.features.addFeature( MFT_GlowMask );
// Don't allow fog or HDR encoding on
// the glow materials.
fd.features.removeFeature( MFT_Fog );
fd.features.removeFeature( MFT_HDROut );
}
RenderGlowMgr::RenderGlowMgr()
: RenderTexTargetBinManager( RenderPassManager::RIT_Mesh,
1.0f,
1.0f,
GFXFormatR8G8B8A8,
Point2I( 512, 512 ) )
{
notifyType( RenderPassManager::RIT_Interior );
notifyType( RenderPassManager::RIT_Decal );
notifyType( RenderPassManager::RIT_Translucent );
mNamedTarget.registerWithName( "glowbuffer" );
mTargetSizeType = WindowSize;
}
RenderGlowMgr::~RenderGlowMgr()
{
}
PostEffect* RenderGlowMgr::getGlowEffect()
{
if ( !mGlowEffect )
mGlowEffect = dynamic_cast<PostEffect*>( Sim::findObject( "GlowPostFx" ) );
return mGlowEffect;
}
bool RenderGlowMgr::isGlowEnabled()
{
return getGlowEffect() && getGlowEffect()->isEnabled();
}
void RenderGlowMgr::addElement( RenderInst *inst )
{
// Skip out if we don't have the glow post
// effect enabled at this time.
if ( !isGlowEnabled() )
return;
// TODO: We need to get the scene state here in a more reliable
// manner so we can skip glow in a non-diffuse render pass.
//if ( !mParentManager->getSceneManager()->getSceneState()->isDiffusePass() )
//return RenderBinManager::arSkipped;
// Skip it if we don't have a glowing material.
BaseMatInstance *matInst = getMaterial( inst );
if ( !matInst || !matInst->hasGlow() )
return;
internalAddElement(inst);
}
void RenderGlowMgr::render( SceneRenderState *state )
{
PROFILE_SCOPE( RenderGlowMgr_Render );
if ( !isGlowEnabled() )
return;
const U32 binSize = mElementList.size();
// If this is a non-diffuse pass or we have no objects to
// render then tell the effect to skip rendering.
if ( !state->isDiffusePass() || binSize == 0 )
{
getGlowEffect()->setSkip( true );
return;
}
GFXDEBUGEVENT_SCOPE( RenderGlowMgr_Render, ColorI::GREEN );
GFXTransformSaver saver;
// Tell the superclass we're about to render, preserve contents
const bool isRenderingToTarget = _onPreRender( state, true );
// Clear all the buffers to black.
GFX->clear( GFXClearTarget, ColorI::BLACK, 1.0f, 0);
// Restore transforms
MatrixSet &matrixSet = getRenderPass()->getMatrixSet();
matrixSet.restoreSceneViewProjection();
// init loop data
SceneData sgData;
sgData.init( state, SceneData::GlowBin );
for( U32 j=0; j<binSize; )
{
MeshRenderInst *ri = static_cast<MeshRenderInst*>(mElementList[j].inst);
setupSGData( ri, sgData );
BaseMatInstance *mat = ri->matInst;
GlowMaterialHook *hook = mat->getHook<GlowMaterialHook>();
if ( !hook )
{
hook = new GlowMaterialHook( ri->matInst );
ri->matInst->addHook( hook );
}
BaseMatInstance *glowMat = hook->getMatInstance();
U32 matListEnd = j;
while( glowMat && glowMat->setupPass( state, sgData ) )
{
U32 a;
for( a=j; a<binSize; a++ )
{
MeshRenderInst *passRI = static_cast<MeshRenderInst*>(mElementList[a].inst);
if ( newPassNeeded( ri, passRI ) )
break;
matrixSet.setWorld(*passRI->objectToWorld);
matrixSet.setView(*passRI->worldToCamera);
matrixSet.setProjection(*passRI->projection);
glowMat->setTransforms(matrixSet, state);
glowMat->setSceneInfo(state, sgData);
glowMat->setBuffers(passRI->vertBuff, passRI->primBuff);
if ( passRI->prim )
GFX->drawPrimitive( *passRI->prim );
else
GFX->drawPrimitive( passRI->primBuffIndex );
}
matListEnd = a;
setupSGData( ri, sgData );
}
// force increment if none happened, otherwise go to end of batch
j = ( j == matListEnd ) ? j+1 : matListEnd;
}
// Finish up.
if ( isRenderingToTarget )
_onPostRender();
// Make sure the effect is gonna render.
getGlowEffect()->setSkip( false );
}

View file

@ -0,0 +1,89 @@
//-----------------------------------------------------------------------------
// 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 _RENDERGLOWMGR_H_
#define _RENDERGLOWMGR_H_
#ifndef _TEXTARGETBIN_MGR_H_
#include "renderInstance/renderTexTargetBinManager.h"
#endif
class PostEffect;
///
class RenderGlowMgr : public RenderTexTargetBinManager
{
typedef RenderTexTargetBinManager Parent;
public:
RenderGlowMgr();
virtual ~RenderGlowMgr();
/// Returns the glow post effect.
PostEffect* getGlowEffect();
/// Returns true if the glow post effect is
/// enabled and the glow buffer should be updated.
bool isGlowEnabled();
// RenderBinManager
virtual void addElement( RenderInst *inst );
virtual void render( SceneRenderState *state );
// ConsoleObject
DECLARE_CONOBJECT( RenderGlowMgr );
protected:
class GlowMaterialHook : public MatInstanceHook
{
public:
GlowMaterialHook( BaseMatInstance *matInst );
virtual ~GlowMaterialHook();
virtual BaseMatInstance *getMatInstance() { return mGlowMatInst; }
virtual const MatInstanceHookType& getType() const { return Type; }
/// Our material hook type.
static const MatInstanceHookType Type;
protected:
static void _overrideFeatures( ProcessedMaterial *mat,
U32 stageNum,
MaterialFeatureData &fd,
const FeatureSet &features );
BaseMatInstance *mGlowMatInst;
};
SimObjectPtr<PostEffect> mGlowEffect;
};
#endif // _RENDERGLOWMGR_H_

View file

@ -0,0 +1,351 @@
//-----------------------------------------------------------------------------
// 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/renderImposterMgr.h"
#include "scene/sceneManager.h"
#include "T3D/gameBase/gameConnection.h"
#include "materials/shaderData.h"
#include "lighting/lightManager.h"
#include "lighting/lightInfo.h"
#include "scene/sceneRenderState.h"
#include "gfx/gfxDebugEvent.h"
#include "renderInstance/renderPrePassMgr.h"
#include "gfx/gfxTransformSaver.h"
#include "console/consoleTypes.h"
#include "gfx/util/screenspace.h"
#include "math/util/matrixSet.h"
#include "materials/materialManager.h"
#include "materials/materialFeatureTypes.h"
/*
GFXImplementVertexFormat( ImposterCorner )
{
addElement( "ImposterCorner", GFXDeclType_Float, 4 );
};
*/
const RenderInstType RenderImposterMgr::RIT_Imposter( "Imposter" );
const RenderInstType RenderImposterMgr::RIT_ImposterBatch( "ImposterBatch" );
U32 RenderImposterMgr::smRendered = 0.0f;
U32 RenderImposterMgr::smBatches = 0.0f;
U32 RenderImposterMgr::smDrawCalls = 0.0f;
U32 RenderImposterMgr::smPolyCount = 0.0f;
U32 RenderImposterMgr::smRTChanges = 0.0f;
IMPLEMENT_CONOBJECT(RenderImposterMgr);
ConsoleDocClass( RenderImposterMgr,
"@brief A render bin for batch rendering imposters.\n\n"
"This render bin gathers imposter render instances and renders them in large "
"batches.\n\n"
"You can type 'metrics( imposter )' in the console to see rendering statistics.\n\n"
"@ingroup RenderBin\n" );
RenderImposterMgr::RenderImposterMgr( F32 renderOrder, F32 processAddOrder )
: RenderBinManager( RIT_Imposter, renderOrder, processAddOrder )
{
notifyType( RIT_ImposterBatch );
RenderPrePassMgr::getRenderSignal().notify( this, &RenderImposterMgr::_renderPrePass );
}
void RenderImposterMgr::initPersistFields()
{
GFXDevice::getDeviceEventSignal().notify( &RenderImposterMgr::_clearStats );
Con::addVariable( "$ImposterStats::rendered", TypeS32, &smRendered, "@internal" );
Con::addVariable( "$ImposterStats::batches", TypeS32, &smBatches, "@internal" );
Con::addVariable( "$ImposterStats::drawCalls", TypeS32, &smDrawCalls, "@internal" );
Con::addVariable( "$ImposterStats::polyCount", TypeS32, &smPolyCount, "@internal" );
Con::addVariable( "$ImposterStats::rtChanges", TypeS32, &smRTChanges, "@internal" );
Parent::initPersistFields();
}
RenderImposterMgr::~RenderImposterMgr()
{
RenderPrePassMgr::getRenderSignal().remove( this, &RenderImposterMgr::_renderPrePass );
mIB = NULL;
}
void RenderImposterMgr::render( SceneRenderState *state )
{
PROFILE_SCOPE( RenderImposterMgr_Render );
if ( !mElementList.size() )
return;
GFXDEBUGEVENT_SCOPE( RenderImposterMgr_Render, ColorI::RED );
_innerRender( state, NULL );
}
bool RenderImposterMgr::_clearStats( GFXDevice::GFXDeviceEventType type )
{
if ( type == GFXDevice::deStartOfFrame )
{
smRendered = 0.0f;
smBatches = 0.0f;
smDrawCalls = 0.0f;
smPolyCount = 0.0f;
smRTChanges = 0.0f;
}
return true;
}
void RenderImposterMgr::_renderPrePass( const SceneRenderState *state, RenderPrePassMgr *prePassBin, bool startPrePass )
{
PROFILE_SCOPE( RenderImposterMgr_RenderPrePass );
if ( !mElementList.size() || !startPrePass )
return;
GFXDEBUGEVENT_SCOPE( RenderImposterMgr_RenderPrePass, ColorI::RED );
_innerRender( state, prePassBin );
}
void RenderImposterMgr::_innerRender( const SceneRenderState *state, RenderPrePassMgr *prePassBin )
{
PROFILE_SCOPE( RenderImposterMgr_InnerRender );
// Capture the GFX stats for this render.
GFXDeviceStatistics stats;
stats.start( GFX->getDeviceStatistics() );
GFXTransformSaver saver;
// Restore transforms
MatrixSet &matrixSet = getRenderPass()->getMatrixSet();
matrixSet.restoreSceneViewProjection();
matrixSet.setWorld( MatrixF::Identity );
// Setup the large static index buffer for rendering the imposters.
if ( !mIB.isValid() )
{
// Setup a static index buffer for rendering.
mIB.set( GFX, smImposterBatchSize * 6, 0, GFXBufferTypeStatic );
U16 *idxBuff;
mIB.lock(&idxBuff, NULL, NULL, NULL);
for ( U32 i=0; i < smImposterBatchSize; i++ )
{
//
// The vertex pattern in the VB for each
// imposter is as follows...
//
// 0----1
// |\ |
// | \ |
// | \ |
// | \|
// 3----2
//
// We setup the index order below to ensure
// sequental, cache friendly, access.
//
U32 offset = i * 4;
idxBuff[i*6+0] = 0 + offset;
idxBuff[i*6+1] = 1 + offset;
idxBuff[i*6+2] = 2 + offset;
idxBuff[i*6+3] = 2 + offset;
idxBuff[i*6+4] = 3 + offset;
idxBuff[i*6+5] = 0 + offset;
}
mIB.unlock();
}
/*
if ( !mCornerVB.isValid() )
{
// Setup a static vertex buffer for the corner index for each imposter state.
mCornerVB.set( GFX, smImposterBatchSize * 4, GFXBufferTypeStatic );
ImposterCorner *corner = mCornerVB.lock( 0 );
for ( U32 i=0; i < smImposterBatchSize; i++ )
{
corner->corner = 0; corner++;
corner->corner = 1; corner++;
corner->corner = 2; corner++;
corner->corner = 3; corner++;
}
mCornerVB.unlock();
}
*/
// Set the buffers here once.
GFX->setPrimitiveBuffer( mIB );
// Batch up the imposters into the buffer. These
// are already sorted by texture, to minimize switches
// so just batch them up and render as they come.
ImposterState* statePtr = NULL;
U32 stateCount;
ImposterBaseRenderInst *ri;
ImposterRenderInst *imposter;
ImposterBatchRenderInst *batch;
const U32 binSize = mElementList.size();
BaseMatInstance *setupMat, *currMat;
GFXVertexBufferHandle<ImposterState> vb;
// TODO: We could maybe do better with lights when forward
// rendering the imposters. Just pass a light list with it
// and do some simple tests to break the batch when the light
// list changes.
SceneData sgData;
sgData.init( state, prePassBin ? SceneData::PrePassBin : SceneData::RegularBin );
sgData.lights[0] = LIGHTMGR->getDefaultLight();
// TODO: I should rework this loop to generate the VB first then
// do all the material passes... should be easier to read and faster.
//
// Also consider making this store two element lists... one for
// batches and one for individual imposters.
//
for ( U32 i=0; i < binSize; )
{
currMat = static_cast<ImposterBaseRenderInst*>( mElementList[i].inst )->mat;
setupMat = prePassBin ? prePassBin->getPrePassMaterial( currMat ) : currMat;
// TODO: Fix MatInstance to take a const SceneRenderState!
while ( setupMat->setupPass( (SceneRenderState*)state, sgData ) )
{
setupMat->setSceneInfo( (SceneRenderState*)state, sgData );
setupMat->setTransforms( matrixSet, (SceneRenderState*)state );
for ( ; i < binSize; )
{
ri = static_cast<ImposterBaseRenderInst*>( mElementList[i].inst );
// NOTE: Its safe to compare matinstances here instead of
// the state hint because imposters all share the same
// material instances.... if this changes revise.
if ( ri->mat != currMat )
break;
// Ok if this is a batch then we can just fire off the draw now.
if ( ri->type == RIT_ImposterBatch )
{
batch = static_cast<ImposterBatchRenderInst*>( ri );
GFX->setVertexBuffer( batch->vertBuff->getPointer() );
GFX->drawPrimitive( GFXTriangleList, 0, batch->vertBuff->getPointer()->mNumVerts / 3 );
i++;
continue;
}
// This wasn't a batch so build up all the single imposters into
// a dynamic batch and render it.
statePtr = mBuffer;
stateCount = 0;
// Loop for each individual imposter.
for ( ; i < binSize; i++ )
{
if ( mElementList[i].inst->type == RIT_ImposterBatch )
break;
imposter = static_cast<ImposterRenderInst*>( mElementList[i].inst );
// Stop the loop if the material changed.
if ( imposter->mat != currMat )
break;
++smRendered;
// If we're out of vb space then draw what we got.
if ( stateCount + 1 >= smImposterBatchSize )
{
smBatches++;
vb.set( GFX, stateCount*4, GFXBufferTypeVolatile );
dMemcpy( vb.lock(), mBuffer, stateCount * 4 * sizeof( ImposterState ) );
vb.unlock();
//GFX->setVertexBuffer( mCornerVB, 0, stateCount * 4 );
GFX->setVertexBuffer( vb );
///GFX->setVertexFormat( &mImposterVertDecl );
GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, stateCount * 4, 0, stateCount * 2 );
statePtr = mBuffer;
stateCount = 0;
}
// Setup the imposter state.
*statePtr = imposter->state;
statePtr->corner = 0;
statePtr++;
*statePtr = imposter->state;
statePtr->corner = 1;
statePtr++;
*statePtr = imposter->state;
statePtr->corner = 2;
statePtr++;
*statePtr = imposter->state;
statePtr->corner = 3;
statePtr++;
stateCount++;
} // for ( ; i < binSize; i++ )
// Any remainder to dump?
if ( stateCount > 0 )
{
smBatches++;
vb.set( GFX, stateCount*4, GFXBufferTypeVolatile );
dMemcpy( vb.lock(), mBuffer, stateCount * 4 * sizeof( ImposterState ) );
vb.unlock();
//GFX->setVertexBuffer( mCornerVB, 0, stateCount * 4 );
GFX->setVertexBuffer( vb );
///GFX->setVertexFormat( &mImposterVertDecl );
GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, stateCount * 4, 0, stateCount * 2 );
}
} // for( U32 i=0; i < binSize; )
} // while ( currMat->setupPass( (SceneRenderState*)state, sgData ) )
} // for ( U32 i=0; i < binSize; )
// Capture the GFX stats for this render.
stats.end( GFX->getDeviceStatistics() );
smDrawCalls += stats.mDrawCalls;
smPolyCount += stats.mPolyCount;
smRTChanges += stats.mRenderTargetChanges;
}

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 _IMPOSTERRENDERMGR_H_
#define _IMPOSTERRENDERMGR_H_
#ifndef _RENDERBINMANAGER_H_
#include "renderInstance/renderBinManager.h"
#endif
#ifndef _GFXPRIMITIVEBUFFER_H_
#include "gfx/gfxPrimitiveBuffer.h"
#endif
#ifndef _MATTEXTURETARGET_H_
#include "materials/matTextureTarget.h"
#endif
#ifndef _TSLASTDETAIL_H_
#include "ts/tsLastDetail.h"
#endif
class TSLastDetail;
class GFXTextureObject;
class RenderPrePassMgr;
struct ImposterRenderInst;
/*
GFXDeclareVertexFormat( ImposterCorner )
{
/// billboard corner index
float corner;
};
*/
/// This is a special render manager for processing single
/// billboard imposters typically generated by the tsLastDetail
/// class. It tries to render them in large batches with as
/// few state changes as possible. For an example of use see
/// TSLastDetail::render().
class RenderImposterMgr : public RenderBinManager
{
protected:
typedef RenderBinManager Parent;
static const U32 smImposterBatchSize = 1000;
static U32 smRendered;
static U32 smBatches;
static U32 smDrawCalls;
static U32 smPolyCount;
static U32 smRTChanges;
ImposterState mBuffer[smImposterBatchSize*4];
GFXPrimitiveBufferHandle mIB;
//GFXVertexBufferHandle<ImposterCorner> mCornerVB;
void _innerRender( const SceneRenderState *state, RenderPrePassMgr *prePassBin );
void _renderPrePass( const SceneRenderState *state, RenderPrePassMgr *prePassBin, bool startPrePass );
static bool _clearStats( GFXDevice::GFXDeviceEventType type );
public:
static const RenderInstType RIT_Imposter;
static const RenderInstType RIT_ImposterBatch;
RenderImposterMgr( F32 renderOrder = 1.0f, F32 processAddOrder = 1.0f );
virtual ~RenderImposterMgr();
// ConsoleObject
DECLARE_CONOBJECT(RenderImposterMgr);
static void initPersistFields();
// RenderBinManager
virtual void render( SceneRenderState *state );
};
/// This is a shared base render instance type TSLastDetail imposters.
/// @see TSLastDetail
/// @see RenderImposterMgr
struct ImposterBaseRenderInst : public RenderInst
{
/// The material for this imposter.
BaseMatInstance *mat;
};
/// This is a render instance for a single imposter.
struct ImposterRenderInst : public ImposterBaseRenderInst
{
/// The imposter state.
ImposterState state;
/// Helper for setting this instance to a default state.
void clear()
{
dMemset( this, 0, sizeof( ImposterRenderInst ) );
type = RenderImposterMgr::RIT_Imposter;
}
};
/// This is a render instance for a cached multiple imposter batch.
struct ImposterBatchRenderInst : public ImposterBaseRenderInst
{
/// The pre-built vertex buffer batch of imposters.
GFXVertexBufferHandleBase *vertBuff;
/// Helper for setting this instance to a default state.
void clear()
{
dMemset( this, 0, sizeof( ImposterBatchRenderInst ) );
type = RenderImposterMgr::RIT_ImposterBatch;
}
};
#endif // _TSIMPOSTERRENDERMGR_H_

View file

@ -0,0 +1,261 @@
//-----------------------------------------------------------------------------
// 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/renderMeshMgr.h"
#include "console/consoleTypes.h"
#include "gfx/gfxTransformSaver.h"
#include "gfx/gfxPrimitiveBuffer.h"
#include "materials/sceneData.h"
#include "materials/processedMaterial.h"
#include "materials/materialManager.h"
#include "scene/sceneRenderState.h"
#include "gfx/gfxDebugEvent.h"
#include "math/util/matrixSet.h"
IMPLEMENT_CONOBJECT(RenderMeshMgr);
ConsoleDocClass( RenderMeshMgr,
"@brief A render bin for mesh rendering.\n\n"
"This is the primary render bin in Torque which does most of the "
"work of rendering DTS shapes and arbitrary mesh geometry. It knows "
"how to render mesh instances using materials and supports hardware mesh "
"instancing.\n\n"
"@ingroup RenderBin\n" );
RenderMeshMgr::RenderMeshMgr()
: RenderBinManager(RenderPassManager::RIT_Mesh, 1.0f, 1.0f)
{
}
RenderMeshMgr::RenderMeshMgr(RenderInstType riType, F32 renderOrder, F32 processAddOrder)
: RenderBinManager(riType, renderOrder, processAddOrder)
{
}
void RenderMeshMgr::init()
{
GFXStateBlockDesc d;
d.cullDefined = true;
d.cullMode = GFXCullCCW;
d.samplersDefined = true;
d.samplers[0] = GFXSamplerStateDesc::getWrapLinear();
mNormalSB = GFX->createStateBlock(d);
d.cullMode = GFXCullCW;
mReflectSB = GFX->createStateBlock(d);
}
void RenderMeshMgr::initPersistFields()
{
Parent::initPersistFields();
}
//-----------------------------------------------------------------------------
// add element
//-----------------------------------------------------------------------------
void RenderMeshMgr::addElement( RenderInst *inst )
{
// If this instance is translucent handle it in RenderTranslucentMgr
if (inst->translucentSort)
return;
AssertFatal( inst->defaultKey != 0, "RenderMeshMgr::addElement() - Got null sort key... did you forget to set it?" );
internalAddElement(inst);
}
//-----------------------------------------------------------------------------
// render
//-----------------------------------------------------------------------------
void RenderMeshMgr::render(SceneRenderState * state)
{
PROFILE_SCOPE(RenderMeshMgr_render);
// Early out if nothing to draw.
if(!mElementList.size())
return;
GFXDEBUGEVENT_SCOPE( RenderMeshMgr_Render, ColorI::GREEN );
// Automagically save & restore our viewport and transforms.
GFXTransformSaver saver;
// Restore transforms
MatrixSet &matrixSet = getRenderPass()->getMatrixSet();
matrixSet.restoreSceneViewProjection();
// init loop data
GFXTextureObject *lastLM = NULL;
GFXCubemap *lastCubemap = NULL;
GFXTextureObject *lastReflectTex = NULL;
GFXTextureObject *lastMiscTex = NULL;
SceneData sgData;
sgData.init( state );
U32 binSize = mElementList.size();
for( U32 j=0; j<binSize; )
{
MeshRenderInst *ri = static_cast<MeshRenderInst*>(mElementList[j].inst);
setupSGData( ri, sgData );
BaseMatInstance *mat = ri->matInst;
// If we have an override delegate then give it a
// chance to swap the material with another.
if ( mMatOverrideDelegate )
{
mat = mMatOverrideDelegate( mat );
if ( !mat )
{
j++;
continue;
}
}
if( !mat )
mat = MATMGR->getWarningMatInstance();
U32 matListEnd = j;
lastMiscTex = sgData.miscTex;
U32 a;
while( mat && mat->setupPass(state, sgData ) )
{
for( a=j; a<binSize; a++ )
{
MeshRenderInst *passRI = static_cast<MeshRenderInst*>(mElementList[a].inst);
// Check to see if we need to break this batch.
if ( newPassNeeded( ri, passRI ) ||
lastMiscTex != passRI->miscTex )
{
lastLM = NULL;
break;
}
matrixSet.setWorld(*passRI->objectToWorld);
matrixSet.setView(*passRI->worldToCamera);
matrixSet.setProjection(*passRI->projection);
mat->setTransforms(matrixSet, state);
setupSGData( passRI, sgData );
mat->setSceneInfo( state, sgData );
// 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() )
{
a++;
break;
}
continue;
}
// TODO: This could proably be done in a cleaner way.
//
// This section of code is dangerous, it overwrites the
// lightmap values in sgData. This could be a problem when multiple
// render instances use the same multi-pass material. When
// the first pass is done, setupPass() is called again on
// the material, but the lightmap data has been changed in
// sgData to the lightmaps in the last renderInstance rendered.
// This section sets the lightmap data for the current batch.
// For the first iteration, it sets the same lightmap data,
// however the redundancy will be caught by GFXDevice and not
// actually sent to the card. This is done for simplicity given
// the possible condition mentioned above. Better to set always
// than to get bogged down into special case detection.
//-------------------------------------
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;
}
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 );
// Render the instanced stream.
if ( ri->prim )
GFX->drawPrimitive( *ri->prim );
else
GFX->drawPrimitive( ri->primBuffIndex );
}
matListEnd = a;
}
// force increment if none happened, otherwise go to end of batch
j = ( j == matListEnd ) ? j+1 : matListEnd;
}
}

View file

@ -0,0 +1,54 @@
//-----------------------------------------------------------------------------
// 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 _RENDERMESHMGR_H_
#define _RENDERMESHMGR_H_
#ifndef _RENDERBINMANAGER_H_
#include "renderInstance/renderBinManager.h"
#endif
//**************************************************************************
// RenderMeshMgr
//**************************************************************************
class RenderMeshMgr : public RenderBinManager
{
typedef RenderBinManager Parent;
public:
RenderMeshMgr();
RenderMeshMgr(RenderInstType riType, F32 renderOrder, F32 processAddOrder);
// RenderBinManager interface
virtual void init();
virtual void render(SceneRenderState * state);
virtual void addElement( RenderInst *inst );
// ConsoleObject interface
static void initPersistFields();
DECLARE_CONOBJECT(RenderMeshMgr);
protected:
GFXStateBlockRef mNormalSB;
GFXStateBlockRef mReflectSB;
void construct();
};
#endif // _RENDERMESHMGR_H_

View file

@ -0,0 +1,75 @@
//-----------------------------------------------------------------------------
// 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 "renderObjectMgr.h"
#include "console/consoleTypes.h"
#include "scene/sceneObject.h"
IMPLEMENT_CONOBJECT(RenderObjectMgr);
ConsoleDocClass( RenderObjectMgr,
"@brief A render bin which uses object callbacks for rendering.\n\n"
"This render bin gathers object render instances and calls its delegate "
"method to perform rendering. It is used infrequently for specialized "
"scene objects which perform custom rendering.\n\n"
"@ingroup RenderBin\n" );
RenderObjectMgr::RenderObjectMgr()
: RenderBinManager(RenderPassManager::RIT_Object, 1.0f, 1.0f)
{
mOverrideMat = NULL;
}
RenderObjectMgr::RenderObjectMgr(RenderInstType riType, F32 renderOrder, F32 processAddOrder)
: RenderBinManager(riType, renderOrder, processAddOrder)
{
mOverrideMat = NULL;
}
void RenderObjectMgr::initPersistFields()
{
Parent::initPersistFields();
}
void RenderObjectMgr::setOverrideMaterial(BaseMatInstance* overrideMat)
{
mOverrideMat = overrideMat;
}
//-----------------------------------------------------------------------------
// render objects
//-----------------------------------------------------------------------------
void RenderObjectMgr::render( SceneRenderState *state )
{
PROFILE_SCOPE(RenderObjectMgr_render);
// Early out if nothing to draw.
if(!mElementList.size())
return;
for( U32 i=0; i<mElementList.size(); i++ )
{
ObjectRenderInst *ri = static_cast<ObjectRenderInst*>(mElementList[i].inst);
if ( ri->renderDelegate )
ri->renderDelegate( ri, state, mOverrideMat );
}
}

View file

@ -0,0 +1,51 @@
//-----------------------------------------------------------------------------
// 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 _RENDEROBJECTMGR_H_
#define _RENDEROBJECTMGR_H_
#ifndef _RENDERBINMANAGER_H_
#include "renderInstance/renderBinManager.h"
#endif
//**************************************************************************
// RenderObjectMgr
//**************************************************************************
class RenderObjectMgr : public RenderBinManager
{
typedef RenderBinManager Parent;
public:
RenderObjectMgr();
RenderObjectMgr(RenderInstType riType, F32 renderOrder, F32 processAddOrder);
virtual void setOverrideMaterial(BaseMatInstance* overrideMat);
// RenderBinMgr
virtual void render(SceneRenderState * state);
// ConsoleObject
static void initPersistFields();
DECLARE_CONOBJECT(RenderObjectMgr);
protected:
BaseMatInstance* mOverrideMat;
};
#endif // _RENDEROBJECTMGR_H_

View file

@ -0,0 +1,254 @@
//-----------------------------------------------------------------------------
// 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 "renderOcclusionMgr.h"
#include "console/consoleTypes.h"
#include "scene/sceneObject.h"
#include "gfx/gfxOcclusionQuery.h"
#include "gfx/gfxDrawUtil.h"
#include "gfx/gfxTransformSaver.h"
#include "math/util/sphereMesh.h"
#include "gfx/gfxDebugEvent.h"
IMPLEMENT_CONOBJECT(RenderOcclusionMgr);
ConsoleDocClass( RenderOcclusionMgr,
"@brief A render bin which renders occlusion query requests.\n\n"
"This render bin gathers occlusion query render instances and renders them. "
"It is currently used by light flares and ShapeBase reflection cubemaps.\n\n"
"You can type '$RenderOcclusionMgr::debugRender = true' in the console to "
"see debug rendering of the occlusion geometry.\n\n"
"@ingroup RenderBin\n" );
bool RenderOcclusionMgr::smDebugRender = false;
RenderOcclusionMgr::RenderOcclusionMgr()
: RenderBinManager(RenderPassManager::RIT_Occluder, 1.0f, 1.0f)
{
mOverrideMat = NULL;
mSpherePrimCount = 0;
}
RenderOcclusionMgr::RenderOcclusionMgr(RenderInstType riType, F32 renderOrder, F32 processAddOrder)
: RenderBinManager(riType, renderOrder, processAddOrder)
{
mOverrideMat = NULL;
}
static const Point3F cubePoints[8] =
{
Point3F(-0.5, -0.5, -0.5), Point3F(-0.5, -0.5, 0.5), Point3F(-0.5, 0.5, -0.5), Point3F(-0.5, 0.5, 0.5),
Point3F( 0.5, -0.5, -0.5), Point3F( 0.5, -0.5, 0.5), Point3F( 0.5, 0.5, -0.5), Point3F( 0.5, 0.5, 0.5)
};
static const U32 cubeFaces[6][4] =
{
{ 0, 4, 6, 2 }, { 0, 2, 3, 1 }, { 0, 1, 5, 4 },
{ 3, 2, 6, 7 }, { 7, 6, 4, 5 }, { 3, 7, 5, 1 }
};
void RenderOcclusionMgr::init()
{
GFXStateBlockDesc d;
d.setBlend( false );
d.cullDefined = true;
d.cullMode = GFXCullCCW;
d.setZReadWrite( true, false );
mDebugSB = GFX->createStateBlock(d);
d.setColorWrites( false, false, false, false );
mNormalSB = GFX->createStateBlock(d);
d.setZReadWrite( false, false );
mTestSB = GFX->createStateBlock(d);
mBoxBuff.set( GFX, 36, GFXBufferTypeStatic );
GFXVertexPC *verts = mBoxBuff.lock();
U32 vertexIndex = 0;
U32 idx;
for(int i = 0; i < 6; i++)
{
idx = cubeFaces[i][0];
verts[vertexIndex].point = cubePoints[idx];
verts[vertexIndex].color.set( 1,0,1,1 );
vertexIndex++;
idx = cubeFaces[i][1];
verts[vertexIndex].point = cubePoints[idx];
verts[vertexIndex].color.set( 1,0,1,1 );
vertexIndex++;
idx = cubeFaces[i][3];
verts[vertexIndex].point = cubePoints[idx];
verts[vertexIndex].color.set( 1,0,1,1 );
vertexIndex++;
idx = cubeFaces[i][1];
verts[vertexIndex].point = cubePoints[idx];
verts[vertexIndex].color.set( 1,0,1,1 );
vertexIndex++;
idx = cubeFaces[i][3];
verts[vertexIndex].point = cubePoints[idx];
verts[vertexIndex].color.set( 1,0,1,1 );
vertexIndex++;
idx = cubeFaces[i][2];
verts[vertexIndex].point = cubePoints[idx];
verts[vertexIndex].color.set( 1,0,1,1 );
vertexIndex++;
}
mBoxBuff.unlock();
SphereMesh sphere;
const SphereMesh::TriangleMesh *sphereMesh = sphere.getMesh(1);
mSpherePrimCount = sphereMesh->numPoly;
mSphereBuff.set( GFX, mSpherePrimCount * 3, GFXBufferTypeStatic );
verts = mSphereBuff.lock();
vertexIndex = 0;
for ( S32 i = 0; i < mSpherePrimCount; i++ )
{
verts[vertexIndex].point = sphereMesh->poly[i].pnt[0];
verts[vertexIndex].color.set( 1,0,1,1 );
vertexIndex++;
verts[vertexIndex].point = sphereMesh->poly[i].pnt[1];
verts[vertexIndex].color.set( 1,0,1,1 );
vertexIndex++;
verts[vertexIndex].point = sphereMesh->poly[i].pnt[2];
verts[vertexIndex].color.set( 1,0,1,1 );
vertexIndex++;
}
mSphereBuff.unlock();
}
void RenderOcclusionMgr::consoleInit()
{
Con::addVariable( "$RenderOcclusionMgr::debugRender", TypeBool, &RenderOcclusionMgr::smDebugRender,
"@brief A debugging feature which renders the occlusion volumes to the scene.\n"
"@see RenderOcclusionMgr\n"
"@ingroup RenderBin\n" );
}
void RenderOcclusionMgr::initPersistFields()
{
Parent::initPersistFields();
}
//-----------------------------------------------------------------------------
// render objects
//-----------------------------------------------------------------------------
void RenderOcclusionMgr::render( SceneRenderState *state )
{
PROFILE_SCOPE(RenderOcclusionMgr_render);
// Early out if nothing to draw.
if ( !mElementList.size() )
return;
GFXDEBUGEVENT_SCOPE(RenderOcclusionMgr_Render, ColorI::BLUE);
if ( mNormalSB.isNull() )
init();
GFX->disableShaders();
GFX->setupGenericShaders( GFXDevice::GSColor );
OccluderRenderInst *firstEl = static_cast<OccluderRenderInst*>(mElementList[0].inst);
if ( firstEl->isSphere )
GFX->setVertexBuffer( mSphereBuff );
else
GFX->setVertexBuffer( mBoxBuff );
bool wasSphere = firstEl->isSphere;
for( U32 i=0; i<mElementList.size(); i++ )
{
OccluderRenderInst *ri = static_cast<OccluderRenderInst*>(mElementList[i].inst);
AssertFatal( ri->query != NULL, "RenderOcclusionMgr::render, OcclusionRenderInst has NULL GFXOcclusionQuery" );
if ( ri->isSphere != wasSphere )
{
if ( ri->isSphere )
GFX->setVertexBuffer( mSphereBuff );
else
GFX->setVertexBuffer( mBoxBuff );
wasSphere = ri->isSphere;
}
GFX->pushWorldMatrix();
MatrixF xfm( *ri->orientation );
xfm.setPosition( ri->position );
xfm.scale( ri->scale );
//GFXTransformSaver saver;
GFX->multWorld( xfm );
if ( smDebugRender )
GFX->setStateBlock( mDebugSB );
else
GFX->setStateBlock( mNormalSB );
ri->query->begin();
if ( wasSphere )
GFX->drawPrimitive( GFXTriangleList, 0, mSpherePrimCount );
else
GFX->drawPrimitive( GFXTriangleList, 0, 12 );
ri->query->end();
if ( ri->query2 )
{
GFX->setStateBlock( mTestSB );
ri->query2->begin();
if ( wasSphere )
GFX->drawPrimitive( GFXTriangleList, 0, mSpherePrimCount );
else
GFX->drawPrimitive( GFXTriangleList, 0, 12 );
ri->query2->end();
}
GFX->popWorldMatrix();
}
}

View file

@ -0,0 +1,61 @@
//-----------------------------------------------------------------------------
// 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 _RENDEROCCLUSIONMGR_H_
#define _RENDEROCCLUSIONMGR_H_
#ifndef _RENDERBINMANAGER_H_
#include "renderInstance/renderBinManager.h"
#endif
//**************************************************************************
// RenderOcclusionMgr
//**************************************************************************
class RenderOcclusionMgr : public RenderBinManager
{
typedef RenderBinManager Parent;
public:
RenderOcclusionMgr();
RenderOcclusionMgr(RenderInstType riType, F32 renderOrder, F32 processAddOrder);
// RenderOcclusionMgr
virtual void init();
virtual void render(SceneRenderState * state);
// ConsoleObject
static void consoleInit();
static void initPersistFields();
DECLARE_CONOBJECT(RenderOcclusionMgr);
protected:
BaseMatInstance* mOverrideMat;
GFXStateBlockRef mNormalSB;
GFXStateBlockRef mTestSB;
GFXStateBlockRef mDebugSB;
static bool smDebugRender;
GFXVertexBufferHandle<GFXVertexPC> mBoxBuff;
GFXVertexBufferHandle<GFXVertexPC> mSphereBuff;
U32 mSpherePrimCount;
};
#endif // _RENDEROCCLUSIONMGR_H_

View file

@ -0,0 +1,806 @@
//-----------------------------------------------------------------------------
// 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/renderParticleMgr.h"
#include "renderInstance/renderPrePassMgr.h"
#include "scene/sceneManager.h"
#include "scene/sceneObject.h"
#include "scene/sceneRenderState.h"
#include "gfx/gfxPrimitiveBuffer.h"
#include "gfx/gfxTransformSaver.h"
#include "gfx/gfxDebugEvent.h"
#include "materials/shaderData.h"
#include "materials/sceneData.h"
#include "materials/matInstance.h"
#include "gfx/util/screenspace.h"
#include "gfx/gfxDrawUtil.h"
#include "collision/clippedPolyList.h"
static const Point4F cubePoints[9] =
{
Point4F(-0.5, -0.5, -0.5, 1.0f), Point4F(-0.5, -0.5, 0.5, 1.0f), Point4F(-0.5, 0.5, -0.5, 1.0f), Point4F(-0.5, 0.5, 0.5, 1.0f),
Point4F( 0.5, -0.5, -0.5, 1.0f), Point4F( 0.5, -0.5, 0.5, 1.0f), Point4F( 0.5, 0.5, -0.5, 1.0f), Point4F( 0.5, 0.5, 0.5, 1.0f)
};
GFXImplementVertexFormat( CompositeQuadVert )
{
addElement( "COLOR", GFXDeclType_Color );
}
IMPLEMENT_CONOBJECT(RenderParticleMgr);
ConsoleDocClass( RenderParticleMgr,
"@brief A render bin which renders particle geometry.\n\n"
"This render bin gathers particle render instances, sorts, and renders them. "
"It is currently used by ParticleEmitter and LightFlareData.\n\n"
"@ingroup RenderBin\n" );
const RenderInstType RenderParticleMgr::RIT_Particles("ParticleSystem");
// TODO: Replace these once they are supported via options
const bool RenderToParticleTarget = true;
const bool RenderToSingleTarget = true;
RenderParticleMgr::RenderParticleMgr()
: Parent( RenderParticleMgr::RIT_Particles,
1.0f,
1.0f,
GFXFormatR8G8B8A8,
Point2I( Parent::DefaultTargetSize, Parent::DefaultTargetSize),
RenderToParticleTarget ? Parent::DefaultTargetChainLength : 0 ),
mParticleShader( NULL )
{
// Render particles at 1/4 resolution
mTargetSizeType = WindowSizeScaled;
mTargetScale.set(0.25f, 0.25f);
// We use the target chain like a texture pool, not like a swap chain
if(!RenderToSingleTarget)
setTargetChainLength(5);
else
mOffscreenSystems.setSize(1);
LightManager::smActivateSignal.notify( this, &RenderParticleMgr::_onLMActivate );
}
RenderParticleMgr::~RenderParticleMgr()
{
LightManager::smActivateSignal.remove( this, &RenderParticleMgr::_onLMActivate );
}
void RenderParticleMgr::setTargetChainLength( const U32 chainLength )
{
Parent::setTargetChainLength(chainLength);
if(!RenderToSingleTarget)
mOffscreenSystems.setSize(chainLength);
}
void RenderParticleMgr::addElement( RenderInst *inst )
{
ParticleRenderInst *pri = reinterpret_cast<ParticleRenderInst *>(inst);
// If this system isn't waiting for an offscreen draw, skip it
if( pri->systemState != PSS_AwaitingOffscreenDraw )
return;
// If offscreen rendering isn't enabled, set to high-res, and skip
if(!mOffscreenRenderEnabled)
{
pri->systemState = PSS_AwaitingHighResDraw;
return;
}
// Assign a target index
RectF screenRect;
S32 chainIndex = -1;
if(RenderToSingleTarget)
{
pri->targetIndex = 0;
screenRect.point.set(-1.0f, -1.0f);
screenRect.extent.set(2.0f, 2.0f);
mElementList.setSize(1);
}
else
{
// If we can't fit this into the offscreen systems, skip it, it will render
// high resolution
//
// TODO: Improve this once we are grouping systems
if( mTargetChainIdx == OffscreenPoolSize )
return;
// Transform bounding box into screen space
const static PlaneF planes[] = {
PlaneF(Point3F( 1.0f, 0.0f, 0.0f), Point3F(-1.0f, 0.0f, 0.0f)),
PlaneF(Point3F(-1.0f, 0.0f, 0.0f), Point3F( 1.0f, 0.0f, 0.0f)),
PlaneF(Point3F( 0.0f, 1.0f, 0.0f), Point3F( 0.0f, -1.0f, 0.0f)),
PlaneF(Point3F( 0.0f, -1.0f, 0.0f), Point3F( 0.0f, 1.0f, 0.0f)),
PlaneF(Point3F( 0.0f, 0.0f, 0.0f), Point3F( 0.0f, 0.0f, 1.0f)),
PlaneF(Point3F( 0.0f, 0.0f, 1.0f), Point3F( 0.0f, 0.0f, -1.0f)),
};
const static dsize_t numPlanes = sizeof(planes) / sizeof(PlaneF);
// Set up a clipper
ClippedPolyList screenClipper;
screenClipper.setBaseTransform(MatrixF::Identity);
screenClipper.setTransform(&MatrixF::Identity, Point3F::One);
TORQUE_UNUSED(numPlanes);
Point4F tempPt(0.0f, 0.0f, 0.0f, 1.0f);
pri->bbModelViewProj->mul(tempPt);
tempPt = tempPt / tempPt.w;
for(int i = 0; i < 1; i++)
{
screenClipper.mPlaneList.push_back(planes[i]);
screenClipper.mPlaneList.last() += tempPt.asPoint3F();
}
Box3F screenSpaceBoundingBox;
screenSpaceBoundingBox.minExtents = Point3F::Zero;
screenSpaceBoundingBox.maxExtents = Point3F::Zero;
for(int i = 0; i < 8; i++)
{
tempPt = cubePoints[i];
pri->bbModelViewProj->mul(tempPt);
tempPt = tempPt / tempPt.w;
screenSpaceBoundingBox.maxExtents.setMax(tempPt.asPoint3F());
screenSpaceBoundingBox.minExtents.setMin(tempPt.asPoint3F());
}
screenClipper.addBox(screenSpaceBoundingBox);
screenClipper.cullUnusedVerts();
//screenClipper.triangulate();
// Empty vertex list? Skip!
if(screenClipper.mVertexList.empty())
{
pri->systemState = PSS_AwaitingHighResDraw;
return;
}
Point2F minExtents(0.0f, 0.0f), maxExtents(0.0f, 0.0f);
for(ClippedPolyList::VertexList::const_iterator itr = screenClipper.mVertexList.begin();
itr != screenClipper.mVertexList.end(); itr++)
{
minExtents.x = getMin(minExtents.x, (*itr).point.x);
minExtents.y = getMin(minExtents.y, (*itr).point.y);
maxExtents.x = getMax(maxExtents.x, (*itr).point.x);
maxExtents.y = getMax(maxExtents.y, (*itr).point.y);
}
screenRect.set( minExtents, maxExtents - minExtents );
// Check the size of the system on screen. If it is small, it won't
// be eating fillrate anyway, so just draw it high-resolution.
// The value it checks against is one I found from experimentation,
// not anything really meaningful.
if( screenRect.extent.x < 0.35f || screenRect.extent.y < 0.35f )
{
pri->systemState = PSS_AwaitingHighResDraw;
return;
}
pri->targetIndex = mTargetChainIdx;
chainIndex = mTargetChainIdx;
mTargetChainIdx++;
// TODO: Rewrite this...
mElementList.increment();
}
// Set up system entry
OffscreenSystemEntry &systemEntry = mOffscreenSystems[pri->targetIndex];
systemEntry.screenRect = screenRect;
systemEntry.targetChainIdx = chainIndex;
systemEntry.pInstances.push_back(pri);
// TODO: Rewrite this block
// Assign proper values to sort element
MainSortElem& elem = mElementList.last();
elem.inst = reinterpret_cast<RenderInst *>(&systemEntry);
elem.key = *((U32*)&inst->sortDistSq);
elem.key2 = inst->defaultKey;
// TODO: [re]move this block
systemEntry.clipMatrix.identity();
if(!RenderToSingleTarget)
{
// Construct crop matrix
Point3F scale( getMax(2.0f / systemEntry.screenRect.extent.x, 1.0f),
getMax(2.0f / systemEntry.screenRect.extent.y, 1.0f),
1.0f);
Point3F offset((systemEntry.screenRect.point.x + systemEntry.screenRect.extent.x * 0.5f) * scale.x,
(systemEntry.screenRect.point.y + systemEntry.screenRect.extent.y * 0.5f) * scale.y,
0.0f);
//systemEntry.clipMatrix.scale(scale);
//systemEntry.clipMatrix.setPosition(-offset);
}
// The translucent mgr will also pick up particles, and will call this class
// to composiste the particle systems back into the main scene
}
void RenderParticleMgr::sort()
{
Parent::sort();
}
void RenderParticleMgr::clear()
{
Parent::clear();
// Reset pool index
if(!RenderToSingleTarget)
mTargetChainIdx = 0;
for(Vector<OffscreenSystemEntry>::iterator itr = mOffscreenSystems.begin();
itr != mOffscreenSystems.end(); itr++)
{
(*itr).drawnThisFrame = false;
(*itr).pInstances.clear();
}
}
void RenderParticleMgr::render( SceneRenderState *state )
{
PROFILE_SCOPE(RenderParticleMgr_render);
// Early out if nothing to draw
if( !mElementList.size() ||
(!mParticleShader && !_initShader()) )
return;
GFXDEBUGEVENT_SCOPE(RenderParticleMgr_Render, ColorI::RED);
GFXTransformSaver saver;
// Iterate render instances
for( Vector<MainSortElem>::const_iterator itr = mElementList.begin();
itr != mElementList.end(); itr++ )
{
OffscreenSystemEntry &systemEntry = *reinterpret_cast<OffscreenSystemEntry *>(itr->inst);
// Setup target
// NOTE: If you are using this on the Xbox360 with Basic Lighting,
// you are going to have to mess with either the render order, or
// you are going to have to make this a 'preserve' draw
if(!RenderToSingleTarget)
mTargetChainIdx = systemEntry.targetChainIdx;
_onPreRender(state);
// Clear offscreen target
GFX->clear(GFXClearTarget, ColorI::ZERO, 1.0f, 0);
// Draw offscreen systems
for( Vector<ParticleRenderInst *>::const_iterator itr2 = systemEntry.pInstances.begin();
itr2 != systemEntry.pInstances.end(); itr2++ )
{
ParticleRenderInst *ri = *itr2;
// Sanity check
if(ri->systemState == PSS_AwaitingOffscreenDraw)
{
// If this is not a diffuse path, flag the system appropriately, and skip
// the offscreen processing.
if( !state->isDiffusePass() )
{
if(state->isReflectPass())
ri->systemState = PSS_AwaitingHighResDraw;
else
ri->systemState = PSS_DrawComplete;
continue;
}
// Draw system offscreen
renderInstance(ri, state);
}
}
// Cleanup
_onPostRender();
}
}
void RenderParticleMgr::_initGFXResources()
{
// Screen quad
U16 *prims = NULL;
mScreenQuadPrimBuff.set(GFX, 4, 2, GFXBufferTypeStatic);
mScreenQuadPrimBuff.lock(&prims);
(*prims++) = 0;
(*prims++) = 1;
(*prims++) = 2;
(*prims++) = 3;
mScreenQuadPrimBuff.unlock();
mScreenQuadVertBuff.set(GFX, 4, GFXBufferTypeStatic);
CompositeQuadVert *verts = mScreenQuadVertBuff.lock();
(*verts++).uvCoord.set(0, 0, 0, 0);
(*verts++).uvCoord.set(0, 255, 0, 0);
(*verts++).uvCoord.set(255, 0, 0, 0);
(*verts++).uvCoord.set(255, 255, 0, 0);
mScreenQuadVertBuff.unlock();
// Stencil setup state block
GFXStateBlockDesc d;
d.setCullMode(GFXCullNone);
d.setColorWrites(false, false, false, false);
d.setBlend(false);
d.setZReadWrite(false, false);
d.stencilDefined = true;
d.stencilEnable = true;
d.stencilMask = RenderParticleMgr::ParticleSystemStencilMask;
d.stencilWriteMask = RenderParticleMgr::ParticleSystemStencilMask;
d.stencilFunc = GFXCmpAlways;
d.stencilPassOp = GFXStencilOpZero;
mStencilClearSB = GFX->createStateBlock(d);
}
void RenderParticleMgr::renderInstance(ParticleRenderInst *ri, SceneRenderState *state)
{
// Draw system path, or draw composite path
if(ri->systemState == PSS_DrawComplete)
return;
if(ri->systemState != PSS_AwaitingCompositeDraw)
{
// Set proper stateblock, and update state
if(ri->systemState == PSS_AwaitingOffscreenDraw)
{
GFX->setStateBlock( _getOffscreenStateBlock(ri) );
ri->systemState = PSS_AwaitingCompositeDraw;
mParticleShaderConsts.mShaderConsts->setSafe( mParticleShaderConsts.mModelViewProjSC,
*ri->modelViewProj * mOffscreenSystems[ri->targetIndex].clipMatrix );
}
else
{
if(ri->systemState == PSS_AwaitingMixedResDraw)
GFX->setStateBlock( _getMixedResStateBlock( ri ) );
else
GFX->setStateBlock( _getHighResStateBlock( ri ) );
ri->systemState = PSS_DrawComplete;
mParticleShaderConsts.mShaderConsts->setSafe( mParticleShaderConsts.mModelViewProjSC, *ri->modelViewProj );
}
// We want to turn everything into variation on a pre-multiplied alpha blend
F32 alphaFactor = 0.0f, alphaScale = 1.0f;
switch(ri->blendStyle)
{
// SrcAlpha, InvSrcAlpha
case ParticleRenderInst::BlendNormal:
alphaFactor = 1.0f;
break;
// SrcAlpha, One
case ParticleRenderInst::BlendAdditive:
alphaFactor = 1.0f;
alphaScale = 0.0f;
break;
// SrcColor, One
case ParticleRenderInst::BlendGreyscale:
alphaFactor = -1.0f;
alphaScale = 0.0f;
break;
}
mParticleShaderConsts.mShaderConsts->setSafe( mParticleShaderConsts.mAlphaFactorSC, alphaFactor );
mParticleShaderConsts.mShaderConsts->setSafe( mParticleShaderConsts.mAlphaScaleSC, alphaScale );
mParticleShaderConsts.mShaderConsts->setSafe( mParticleShaderConsts.mFSModelViewProjSC, *ri->modelViewProj );
mParticleShaderConsts.mShaderConsts->setSafe( mParticleShaderConsts.mOneOverFarSC, 1.0f / state->getFarPlane() );
if ( mParticleShaderConsts.mOneOverSoftnessSC->isValid() )
{
F32 oneOverSoftness = 1.0f;
if ( ri->softnessDistance > 0.0f )
oneOverSoftness = 1.0f / ( ri->softnessDistance / state->getFarPlane() );
mParticleShaderConsts.mShaderConsts->set( mParticleShaderConsts.mOneOverSoftnessSC, oneOverSoftness );
}
GFX->setShader( mParticleShader );
GFX->setShaderConstBuffer( mParticleShaderConsts.mShaderConsts );
GFX->setTexture( 0, ri->diffuseTex );
// Set up the prepass texture.
if ( mParticleShaderConsts.mPrePassTargetParamsSC->isValid() )
{
GFXTextureObject *texObject = mPrepassTarget ? mPrepassTarget->getTexture(0) : NULL;
GFX->setTexture( 1, texObject );
Point4F rtParams( 0.0f, 0.0f, 1.0f, 1.0f );
if ( texObject )
ScreenSpace::RenderTargetParameters(texObject->getSize(), mPrepassTarget->getViewport(), rtParams);
mParticleShaderConsts.mShaderConsts->set( mParticleShaderConsts.mPrePassTargetParamsSC, rtParams );
}
GFX->setPrimitiveBuffer( *ri->primBuff );
GFX->setVertexBuffer( *ri->vertBuff );
GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, ri->count * 4, 0, ri->count * 2 );
}
else if(ri->systemState == PSS_AwaitingCompositeDraw)
{
OffscreenSystemEntry &systemEntry = mOffscreenSystems[ri->targetIndex];
// If this system has already been composited this frame, skip it
if(systemEntry.drawnThisFrame)
return;
// Non-target render, composite the particle system back into the scene
GFX->setVertexBuffer(mScreenQuadVertBuff);
GFX->setPrimitiveBuffer(mScreenQuadPrimBuff);
// Set up shader constants
mParticleCompositeShaderConsts.mShaderConsts->setSafe( mParticleCompositeShaderConsts.mScreenRect, *((Point4F *)&systemEntry.screenRect) );
// Set offscreen texture
Point4F rtParams;
GFXTextureObject *particleSource = mNamedTarget.getTexture();
GFX->setTexture( 0, particleSource );
if(particleSource)
{
ScreenSpace::RenderTargetParameters(particleSource->getSize(), mNamedTarget.getViewport(), rtParams);
mParticleCompositeShaderConsts.mShaderConsts->setSafe( mParticleCompositeShaderConsts.mOffscreenTargetParamsSC, rtParams );
}
// And edges
GFXTextureObject *texObject = mEdgeTarget ? mEdgeTarget->getTexture() : NULL;
GFX->setTexture( 1, texObject );
if(texObject)
{
ScreenSpace::RenderTargetParameters(texObject->getSize(), mEdgeTarget->getViewport(), rtParams);
mParticleCompositeShaderConsts.mShaderConsts->setSafe( mParticleCompositeShaderConsts.mEdgeTargetParamsSC, rtParams );
}
// Set shader and constant buffer
GFX->setShader( mParticleCompositeShader );
GFX->setShaderConstBuffer( mParticleCompositeShaderConsts.mShaderConsts );
// Draw to stencil buffer only to clear the stencil values
GFX->setStateBlock( mStencilClearSB );
GFX->drawIndexedPrimitive( GFXTriangleStrip, 0, 0, 4, 0, 2 );
// composite particle system back into the scene
GFX->setStateBlock( _getCompositeStateBlock(ri) );
GFX->drawIndexedPrimitive( GFXTriangleStrip, 0, 0, 4, 0, 2 );
// Re-draw the particle systems in high-res, but only to the stenciled
// areas which were enabled via the edge buffer
for( Vector<ParticleRenderInst *>::const_iterator itr = systemEntry.pInstances.begin();
itr != systemEntry.pInstances.end(); itr++ )
{
ParticleRenderInst *pri = *itr;
if(pri->systemState == PSS_AwaitingCompositeDraw)
{
pri->systemState = PSS_AwaitingMixedResDraw;
renderInstance(pri, state);
}
}
// Mark this system as having been composited this frame
systemEntry.drawnThisFrame = true;
}
}
bool RenderParticleMgr::_initShader()
{
ShaderData *shaderData = NULL;
bool ret = true;
// Need depth from pre-pass, so get the macros
Vector<GFXShaderMacro> macros;
if ( mPrepassTarget )
mPrepassTarget->getShaderMacros( &macros );
// Create particle shader
if ( !Sim::findObject( "ParticlesShaderData", shaderData ) || !shaderData )
Con::warnf( "RenderParticleMgr::_initShader - failed to locate shader ParticlesShaderData!" );
if( shaderData )
mParticleShader = shaderData->getShader( macros );
ret &= (mParticleShader != NULL);
if ( mParticleShader )
{
mParticleShaderConsts.mShaderConsts = mParticleShader->allocConstBuffer();
mParticleShaderConsts.mModelViewProjSC = mParticleShader->getShaderConstHandle( "$modelViewProj" );
mParticleShaderConsts.mOneOverFarSC = mParticleShader->getShaderConstHandle( "$oneOverFar" );
mParticleShaderConsts.mOneOverSoftnessSC = mParticleShader->getShaderConstHandle( "$oneOverSoftness" );
mParticleShaderConsts.mAlphaFactorSC = mParticleShader->getShaderConstHandle( "$alphaFactor" );
mParticleShaderConsts.mAlphaScaleSC = mParticleShader->getShaderConstHandle( "$alphaScale" );
mParticleShaderConsts.mFSModelViewProjSC = mParticleShader->getShaderConstHandle( "$fsModelViewProj" );
mParticleShaderConsts.mPrePassTargetParamsSC = mParticleShader->getShaderConstHandle( "$prePassTargetParams" );
}
shaderData = NULL;
// Create off screen particle composite shader
if ( !Sim::findObject( "OffscreenParticleCompositeShaderData", shaderData ) || !shaderData )
Con::warnf( "RenderParticleMgr::_initShader - failed to locate shader OffscreenParticleCompositeShaderData!" );
if( shaderData )
mParticleCompositeShader = shaderData->getShader( macros );
ret &= (mParticleCompositeShader != NULL);
if ( mParticleCompositeShader )
{
mParticleCompositeShaderConsts.mShaderConsts = mParticleCompositeShader->allocConstBuffer();
mParticleCompositeShaderConsts.mScreenRect = mParticleCompositeShader->getShaderConstHandle( "$screenRect" );
mParticleCompositeShaderConsts.mEdgeTargetParamsSC = mParticleCompositeShader->getShaderConstHandle( "$edgeTargetParams" );
mParticleCompositeShaderConsts.mOffscreenTargetParamsSC = mParticleCompositeShader->getShaderConstHandle( "$offscreenTargetParams" );
}
return ret;
}
void RenderParticleMgr::_onLMActivate( const char*, bool activate )
{
RenderPassManager *rpm = getRenderPass();
if ( !rpm )
return;
// Hunt for the pre-pass manager/target
RenderPrePassMgr *prePassBin = NULL;
for( U32 i = 0; i < rpm->getManagerCount(); i++ )
{
RenderBinManager *bin = rpm->getManager(i);
if( bin->getRenderInstType() == RenderPrePassMgr::RIT_PrePass )
{
prePassBin = (RenderPrePassMgr*)bin;
break;
}
}
// If we found the prepass bin, set this bin to render very shortly afterwards
// and re-add this render-manager. If there is no pre-pass bin, or it doesn't
// have a depth-texture, we can't render offscreen.
mOffscreenRenderEnabled = prePassBin && (prePassBin->getTargetChainLength() > 0);
if(mOffscreenRenderEnabled)
{
rpm->removeManager(this);
setRenderOrder( prePassBin->getRenderOrder() + 0.011f );
rpm->addManager(this);
}
// Find the targets we use
mPrepassTarget = NamedTexTarget::find( "prepass" );
mEdgeTarget = NamedTexTarget::find( "edge" );
// Setup the shader
if ( activate )
_initShader();
if ( mScreenQuadVertBuff.isNull() )
_initGFXResources();
}
GFXStateBlockRef RenderParticleMgr::_getOffscreenStateBlock(ParticleRenderInst *ri)
{
const U8 blendStyle = ri->blendStyle;
if ( mOffscreenBlocks[blendStyle].isValid() )
return mOffscreenBlocks[blendStyle];
GFXStateBlockDesc d;
d.setCullMode(GFXCullNone);
d.setZReadWrite(false, false); // No zreads or writes, all z-testing is done in the pixel shader
// Draw everything either subtractive, or using a variation on premultiplied
// alpha
if(blendStyle == ParticleRenderInst::BlendSubtractive)
d.setBlend(true, GFXBlendZero, GFXBlendInvSrcColor);
else
d.setBlend(true, GFXBlendOne, GFXBlendInvSrcAlpha);
// Offscreen target, we need to add alpha.
d.separateAlphaBlendDefined = true;
d.separateAlphaBlendEnable = true;
d.separateAlphaBlendSrc = GFXBlendOne;
d.separateAlphaBlendDest = GFXBlendInvSrcAlpha;
d.samplersDefined = true;
// Diffuse texture sampler
d.samplers[0] = GFXSamplerStateDesc::getClampLinear();
d.samplers[0].alphaOp = GFXTOPModulate;
d.samplers[0].alphaArg1 = GFXTATexture;
d.samplers[0].alphaArg2 = GFXTADiffuse;
// Prepass sampler
d.samplers[1] = GFXSamplerStateDesc::getClampPoint();
mOffscreenBlocks[blendStyle] = GFX->createStateBlock(d);
return mOffscreenBlocks[blendStyle];
}
GFXStateBlockRef RenderParticleMgr::_getHighResStateBlock(ParticleRenderInst *ri)
{
const U8 blendStyle = ri->blendStyle;
if ( mHighResBlocks[blendStyle].isValid() )
return mHighResBlocks[blendStyle];
GFXStateBlockDesc d;
d.setZReadWrite(true, false);
d.setCullMode(GFXCullNone);
// Draw everything either subtractive, or using a variation on premultiplied
// alpha
if(blendStyle == ParticleRenderInst::BlendSubtractive)
d.setBlend(true, GFXBlendZero, GFXBlendInvSrcColor);
else
d.setBlend(true, GFXBlendOne, GFXBlendInvSrcAlpha);
d.samplersDefined = true;
// Diffuse texture sampler
d.samplers[0] = GFXSamplerStateDesc::getClampLinear();
d.samplers[0].alphaOp = GFXTOPModulate;
d.samplers[0].alphaArg1 = GFXTATexture;
d.samplers[0].alphaArg2 = GFXTADiffuse;
// Prepass sampler
d.samplers[1] = GFXSamplerStateDesc::getClampPoint();
mHighResBlocks[blendStyle] = GFX->createStateBlock(d);
return mHighResBlocks[blendStyle];
}
GFXStateBlockRef RenderParticleMgr::_getMixedResStateBlock(ParticleRenderInst *ri)
{
const U8 blendStyle = ri->blendStyle;
if ( mHighResBlocks[blendStyle].isValid() )
return mHighResBlocks[blendStyle];
GFXStateBlockDesc d;
d.setZReadWrite(true, false);
d.setCullMode(GFXCullNone);
/*
// Old blend styles...
switch (blendStyle)
{
case ParticleRenderInst::BlendNormal:
d.blendSrc = GFXBlendSrcAlpha;
d.blendDest = GFXBlendInvSrcAlpha;
break;
case ParticleRenderInst::BlendSubtractive:
d.blendSrc = GFXBlendZero;
d.blendDest = GFXBlendInvSrcColor;
break;
case ParticleRenderInst::BlendPremultAlpha:
d.blendSrc = GFXBlendOne;
d.blendDest = GFXBlendInvSrcAlpha;
break;
// Default to additive blend mode
case ParticleRenderInst::BlendAdditive:
case ParticleRenderInst::BlendUndefined:
default:
d.blendSrc = GFXBlendSrcAlpha;
d.blendDest = GFXBlendOne;
break;
}
*/
// Draw everything either subtractive, or using a variation on premultiplied
// alpha
if(blendStyle == ParticleRenderInst::BlendSubtractive)
d.setBlend(true, GFXBlendZero, GFXBlendInvSrcColor);
else
d.setBlend(true, GFXBlendOne, GFXBlendInvSrcAlpha);
// Draw to anything but the stencil ref value (the edges)
d.stencilDefined = true;
d.stencilEnable = true;
d.stencilRef = RenderParticleMgr::HighResStencilRef;
d.stencilMask = RenderParticleMgr::ParticleSystemStencilMask;
d.stencilPassOp = GFXStencilOpKeep;
d.stencilFailOp = GFXStencilOpKeep;
d.stencilZFailOp = GFXStencilOpKeep;
d.stencilFunc = GFXCmpNotEqual;
d.samplersDefined = true;
// Diffuse texture sampler
d.samplers[0] = GFXSamplerStateDesc::getClampLinear();
d.samplers[0].alphaOp = GFXTOPModulate;
d.samplers[0].alphaArg1 = GFXTATexture;
d.samplers[0].alphaArg2 = GFXTADiffuse;
// Prepass sampler
d.samplers[1] = GFXSamplerStateDesc::getClampPoint();
mHighResBlocks[blendStyle] = GFX->createStateBlock(d);
return mHighResBlocks[blendStyle];
}
GFXStateBlockRef RenderParticleMgr::_getCompositeStateBlock(ParticleRenderInst *ri)
{
const U8 blendStyle = ri->blendStyle;
if ( mBackbufferBlocks[blendStyle].isValid() )
return mBackbufferBlocks[blendStyle];
GFXStateBlockDesc d;
// This is a billboard
d.setCullMode(GFXCullNone);
d.setZReadWrite(false, false);
// When we re-composite the particles, it is always either a pre-mult alpha
// blend, or a subtractive blend!
if(blendStyle == ParticleRenderInst::BlendSubtractive)
d.setBlend(true, GFXBlendZero, GFXBlendInvSrcColor);
else
d.setBlend(true, GFXBlendOne, GFXBlendInvSrcAlpha);
// All areas which are not along the edges of geometry where the particle system
// is being drawn get assigned a stencil ref value as the system is composited
// back into the scene. The high-res stateblock uses this value as a mask, and
// draws only in areas which are NOT this ref value. This causes high resolution
// draws to ONLY the edge areas.
d.stencilDefined = true;
d.stencilEnable = true;
d.stencilRef = RenderParticleMgr::HighResStencilRef;
d.stencilWriteMask = RenderParticleMgr::ParticleSystemStencilMask;
d.stencilMask = RenderParticleMgr::ParticleSystemStencilMask;
d.stencilPassOp = GFXStencilOpReplace;
d.stencilFunc = GFXCmpGreater;
// Diffuse texture sampler and
d.samplersDefined = true;
d.samplers[0] = GFXSamplerStateDesc::getClampLinear();
d.samplers[1] = GFXSamplerStateDesc::getClampLinear();
mBackbufferBlocks[blendStyle] = GFX->createStateBlock(d);
return mBackbufferBlocks[blendStyle];
}
bool RenderParticleMgr::_handleGFXEvent( GFXDevice::GFXDeviceEventType event )
{
if(RenderToSingleTarget)
return Parent::_handleGFXEvent( event );
// Do nothing. This render manager uses its target chain as a pool of targets.
return true;
}

View file

@ -0,0 +1,141 @@
//-----------------------------------------------------------------------------
// 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 _RENDER_PARTICLE_MGR_H_
#define _RENDER_PARTICLE_MGR_H_
#ifndef _TEXTARGETBIN_MGR_H_
#include "renderInstance/renderTexTargetBinManager.h"
#endif
#ifndef _GFXPRIMITIVEBUFFER_H_
#include "gfx/gfxPrimitiveBuffer.h"
#endif
GFXDeclareVertexFormat( CompositeQuadVert )
{
GFXVertexColor uvCoord;
};
class RenderParticleMgr : public RenderTexTargetBinManager
{
typedef RenderTexTargetBinManager Parent;
friend class RenderTranslucentMgr;
public:
// Generic PrePass Render Instance Type
static const RenderInstType RIT_Particles;
RenderParticleMgr();
RenderParticleMgr( F32 renderOrder, F32 processAddOrder );
virtual ~RenderParticleMgr();
// RenderBinManager
void render(SceneRenderState * state);
void sort();
void clear();
void addElement( RenderInst *inst );
// ConsoleObject
DECLARE_CONOBJECT(RenderParticleMgr);
const static U8 HighResStencilRef = 0x80;
const static U8 ParticleSystemStencilMask = 0x80; // We are using the top bit
const static U32 OffscreenPoolSize = 5;
virtual void setTargetChainLength(const U32 chainLength);
protected:
// Override
virtual bool _handleGFXEvent(GFXDevice::GFXDeviceEventType event);
bool _initShader();
void _initGFXResources();
void _onLMActivate( const char*, bool activate );
// Not only a helper method, but a method for the RenderTranslucentMgr to
// request a particle system draw
void renderInstance(ParticleRenderInst *ri, SceneRenderState *state);
bool mOffscreenRenderEnabled;
/// The prepass render target used for the
/// soft particle shader effect.
NamedTexTargetRef mPrepassTarget;
/// The shader used for particle rendering.
GFXShaderRef mParticleShader;
GFXShaderRef mParticleCompositeShader;
NamedTexTargetRef mEdgeTarget;
struct OffscreenSystemEntry
{
S32 targetChainIdx;
MatrixF clipMatrix;
RectF screenRect;
bool drawnThisFrame;
Vector<ParticleRenderInst *> pInstances;
};
Vector<OffscreenSystemEntry> mOffscreenSystems;
struct ShaderConsts
{
GFXShaderConstBufferRef mShaderConsts;
GFXShaderConstHandle *mModelViewProjSC;
GFXShaderConstHandle *mFSModelViewProjSC;
GFXShaderConstHandle *mOneOverFarSC;
GFXShaderConstHandle *mOneOverSoftnessSC;
GFXShaderConstHandle *mPrePassTargetParamsSC;
GFXShaderConstHandle *mAlphaFactorSC;
GFXShaderConstHandle *mAlphaScaleSC;
} mParticleShaderConsts;
struct CompositeShaderConsts
{
GFXShaderConstBufferRef mShaderConsts;
GFXShaderConstHandle *mSystemDepth;
GFXShaderConstHandle *mScreenRect;
GFXShaderConstHandle *mEdgeTargetParamsSC;
GFXShaderConstHandle *mOffscreenTargetParamsSC;
} mParticleCompositeShaderConsts;
GFXVertexBufferHandle<CompositeQuadVert> mScreenQuadVertBuff;
GFXPrimitiveBufferHandle mScreenQuadPrimBuff;
GFXStateBlockRef mStencilClearSB;
GFXStateBlockRef mHighResBlocks[ParticleRenderInst::BlendStyle_COUNT];
GFXStateBlockRef mOffscreenBlocks[ParticleRenderInst::BlendStyle_COUNT];
GFXStateBlockRef mBackbufferBlocks[ParticleRenderInst::BlendStyle_COUNT];
GFXStateBlockRef mMixedResBlocks[ParticleRenderInst::BlendStyle_COUNT];
GFXStateBlockRef _getHighResStateBlock(ParticleRenderInst *ri);
GFXStateBlockRef _getMixedResStateBlock(ParticleRenderInst *ri);
GFXStateBlockRef _getOffscreenStateBlock(ParticleRenderInst *ri);
GFXStateBlockRef _getCompositeStateBlock(ParticleRenderInst *ri);
};
#endif // _RENDER_TRANSLUCENT_MGR_H_

View file

@ -0,0 +1,365 @@
//-----------------------------------------------------------------------------
// 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/renderPassManager.h"
#include "materials/sceneData.h"
#include "materials/matInstance.h"
#include "materials/customMaterialDefinition.h"
#include "materials/materialManager.h"
#include "scene/sceneManager.h"
#include "scene/sceneObject.h"
#include "gfx/primBuilder.h"
#include "platform/profiler.h"
#include "renderInstance/renderBinManager.h"
#include "renderInstance/renderObjectMgr.h"
#include "renderInstance/renderMeshMgr.h"
#include "renderInstance/renderTranslucentMgr.h"
#include "renderInstance/renderGlowMgr.h"
#include "renderInstance/renderTerrainMgr.h"
#include "core/util/safeDelete.h"
#include "math/util/matrixSet.h"
#include "console/engineAPI.h"
const RenderInstType RenderInstType::Invalid( String::EmptyString );
const RenderInstType RenderPassManager::RIT_Interior("Interior");
const RenderInstType RenderPassManager::RIT_Mesh("Mesh");
const RenderInstType RenderPassManager::RIT_Shadow("Shadow");
const RenderInstType RenderPassManager::RIT_Sky("Sky");
const RenderInstType RenderPassManager::RIT_Terrain("Terrain");
const RenderInstType RenderPassManager::RIT_Object("Object");
const RenderInstType RenderPassManager::RIT_ObjectTranslucent("ObjectTranslucent");
const RenderInstType RenderPassManager::RIT_Decal("Decal");
const RenderInstType RenderPassManager::RIT_Water("Water");
const RenderInstType RenderPassManager::RIT_Foliage("Foliage");
const RenderInstType RenderPassManager::RIT_Translucent("Translucent");
const RenderInstType RenderPassManager::RIT_Begin("Begin");
const RenderInstType RenderPassManager::RIT_Custom("Custom");
const RenderInstType RenderPassManager::RIT_Particle("Particle");
const RenderInstType RenderPassManager::RIT_Occluder("Occluder");
const RenderInstType RenderPassManager::RIT_Editor("Editor");
//*****************************************************************************
// RenderInstance
//*****************************************************************************
void RenderInst::clear()
{
dMemset( this, 0, sizeof(RenderInst) );
}
void MeshRenderInst::clear()
{
dMemset( this, 0, sizeof(MeshRenderInst) );
visibility = 1.0f;
}
void ParticleRenderInst::clear()
{
dMemset( this, 0, sizeof(ParticleRenderInst) );
}
void ObjectRenderInst::clear()
{
userData = NULL;
dMemset( this, 0, sizeof( ObjectRenderInst ) );
// The memset here is kinda wrong... it clears the
// state initialized by the delegate constructor.
//
// This fixes it... but we probably need to have a
// real constructor for RenderInsts.
renderDelegate.clear();
}
void OccluderRenderInst::clear()
{
dMemset( this, 0, sizeof(OccluderRenderInst) );
}
IMPLEMENT_CONOBJECT(RenderPassManager);
ConsoleDocClass( RenderPassManager,
"@brief A grouping of render bin managers which forms a render pass.\n\n"
"The render pass is used to order a set of RenderBinManager objects which are used "
"when rendering a scene. This class does little work itself other than managing "
"its list of render bins.\n\n"
"In 'core/scripts/client/renderManager.cs' you will find the DiffuseRenderPassManager "
"which is used by the C++ engine to render the scene.\n\n"
"@see RenderBinManager\n"
"@ingroup RenderBin\n" );
RenderPassManager::RenderBinEventSignal& RenderPassManager::getRenderBinSignal()
{
static RenderBinEventSignal theSignal;
return theSignal;
}
void RenderPassManager::initPersistFields()
{
}
RenderPassManager::RenderPassManager()
{
mSceneManager = NULL;
VECTOR_SET_ASSOCIATION( mRenderBins );
mMatrixSet = reinterpret_cast<MatrixSet *>(dMalloc_aligned(sizeof(MatrixSet), 16));
constructInPlace(mMatrixSet);
}
RenderPassManager::~RenderPassManager()
{
dFree_aligned(mMatrixSet);
// Any bins left need to be deleted.
for ( U32 i=0; i<mRenderBins.size(); i++ )
{
RenderBinManager *bin = mRenderBins[i];
// Clear the parent first, so that RenderBinManager::onRemove()
// won't call removeManager() and break this loop.
bin->setRenderPass( NULL );
bin->deleteObject();
}
}
void RenderPassManager::_insertSort(Vector<RenderBinManager*>& list, RenderBinManager* mgr, bool renderOrder)
{
U32 i;
for (i = 0; i < list.size(); i++)
{
bool renderCompare = mgr->getRenderOrder() < list[i]->getRenderOrder();
bool processAddCompare = mgr->getProcessAddOrder() < list[i]->getProcessAddOrder();
if ((renderOrder && renderCompare) || (!renderOrder && processAddCompare))
{
list.insert(i);
list[i] = mgr;
return;
}
}
list.push_back(mgr);
}
void RenderPassManager::addManager(RenderBinManager* mgr)
{
if ( !mgr->isProperlyAdded() )
mgr->registerObject();
AssertFatal( mgr->getRenderPass() == NULL, "RenderPassManager::addManager() - Bin is still part of another pass manager!" );
mgr->setRenderPass( this );
_insertSort(mRenderBins, mgr, true);
}
void RenderPassManager::removeManager(RenderBinManager* mgr)
{
AssertFatal( mgr->getRenderPass() == this, "RenderPassManager::removeManager() - We do not own this bin!" );
mgr->setRenderPass( NULL );
mRenderBins.remove( mgr );
}
RenderBinManager* RenderPassManager::getManager(S32 i) const
{
if (i >= 0 && i < mRenderBins.size())
return mRenderBins[i];
else
return NULL;
}
void RenderPassManager::addInst( RenderInst *inst )
{
PROFILE_SCOPE( RenderPassManager_addInst );
AssertFatal( inst != NULL, "RenderPassManager::addInst - Got null instance!" );
AddInstTable::Iterator iter = mAddInstSignals.find( inst->type );
if ( iter == mAddInstSignals.end() )
return;
iter->value.trigger( inst );
}
void RenderPassManager::sort()
{
PROFILE_SCOPE( RenderPassManager_Sort );
for (Vector<RenderBinManager *>::iterator itr = mRenderBins.begin();
itr != mRenderBins.end(); itr++)
{
AssertFatal(*itr, "Render manager invalid!");
(*itr)->sort();
}
}
void RenderPassManager::clear()
{
PROFILE_SCOPE( RenderPassManager_Clear );
mChunker.clear();
for (Vector<RenderBinManager *>::iterator itr = mRenderBins.begin();
itr != mRenderBins.end(); itr++)
{
AssertFatal(*itr, "Invalid render manager!");
(*itr)->clear();
}
}
void RenderPassManager::render(SceneRenderState * state)
{
PROFILE_SCOPE( RenderPassManager_Render );
GFX->pushWorldMatrix();
MatrixF proj = GFX->getProjectionMatrix();
for (Vector<RenderBinManager *>::iterator itr = mRenderBins.begin();
itr != mRenderBins.end(); itr++)
{
RenderBinManager *curBin = *itr;
AssertFatal(curBin, "Invalid render manager!");
getRenderBinSignal().trigger(curBin, state, true);
curBin->render(state);
getRenderBinSignal().trigger(curBin, state, false);
}
GFX->popWorldMatrix();
GFX->setProjectionMatrix( proj );
// Restore a clean state for subsequent rendering.
GFX->disableShaders();
for(S32 i = 0; i < GFX->getNumSamplers(); ++i)
GFX->setTexture(i, NULL);
}
void RenderPassManager::renderPass(SceneRenderState * state)
{
PROFILE_SCOPE( RenderPassManager_RenderPass );
sort();
render(state);
clear();
}
GFXTextureObject *RenderPassManager::getDepthTargetTexture()
{
// If this is OpenGL, or something else has set the depth buffer, return the pointer
if( mDepthBuff.isValid() )
{
// If this is OpenGL, make sure the depth target matches up
// with the active render target. Otherwise recreate.
if( GFX->getAdapterType() == OpenGL )
{
GFXTarget* activeRT = GFX->getActiveRenderTarget();
AssertFatal( activeRT, "Must be an active render target to call 'getDepthTargetTexture'" );
Point2I activeRTSize = activeRT->getSize();
if( mDepthBuff.getWidth() == activeRTSize.x &&
mDepthBuff.getHeight() == activeRTSize.y )
return mDepthBuff.getPointer();
}
else
return mDepthBuff.getPointer();
}
if(GFX->getAdapterType() == OpenGL)
{
AssertFatal(GFX->getActiveRenderTarget(), "Must be an active render target to call 'getDepthTargetTexture'");
const Point2I rtSize = GFX->getActiveRenderTarget()->getSize();
mDepthBuff.set(rtSize.x, rtSize.y, GFXFormatD24S8,
&GFXDefaultZTargetProfile, avar("%s() - mDepthBuff (line %d)", __FUNCTION__, __LINE__));
return mDepthBuff.getPointer();
}
// Default return value
return GFXTextureTarget::sDefaultDepthStencil;
}
void RenderPassManager::setDepthTargetTexture( GFXTextureObject *zTarget )
{
mDepthBuff = zTarget;
}
const MatrixF* RenderPassManager::allocSharedXform( SharedTransformType stt )
{
AssertFatal(stt == View || stt == Projection, "Bad shared transform type");
// Enable this to simulate non-shared transform performance
//#define SIMULATE_NON_SHARED_TRANSFORMS
#ifdef SIMULATE_NON_SHARED_TRANSFORMS
return allocUniqueXform(stt == View ? mMatrixSet->getWorldToCamera() : mMatrixSet->getCameraToScreen());
#else
return &(stt == View ? mMatrixSet->getWorldToCamera() : mMatrixSet->getCameraToScreen());
#endif
}
void RenderPassManager::assignSharedXform( SharedTransformType stt, const MatrixF &xfm )
{
AssertFatal(stt == View || stt == Projection, "Bad shared transform type");
if(stt == View)
mMatrixSet->setSceneView(xfm);
else
mMatrixSet->setSceneProjection(xfm);
}
// Script interface
DefineEngineMethod(RenderPassManager, getManagerCount, S32, (),,
"Returns the total number of bin managers." )
{
return object->getManagerCount();
}
DefineEngineMethod( RenderPassManager, getManager, RenderBinManager*, ( S32 index ),,
"Returns the render bin manager at the index or null if the index is out of range." )
{
if(index < 0 || index >= object->getManagerCount())
return NULL;
return object->getManager(index);
}
DefineEngineMethod( RenderPassManager, addManager, void, ( RenderBinManager *renderBin ),,
"Add as a render bin manager to the pass." )
{
if ( renderBin )
object->addManager( renderBin );
}
DefineEngineMethod( RenderPassManager, removeManager, void, ( RenderBinManager *renderBin ),,
"Removes a render bin manager." )
{
if ( renderBin )
object->removeManager( renderBin );
}

View file

@ -0,0 +1,446 @@
//-----------------------------------------------------------------------------
// 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 _RENDERPASSMANAGER_H_
#define _RENDERPASSMANAGER_H_
#ifndef _GFXDEVICE_H_
#include "gfx/gfxDevice.h"
#endif
#ifndef _SCENEOBJECT_H_
#include "scene/sceneObject.h"
#endif
#ifndef _SIMOBJECT_H_
#include "console/simObject.h"
#endif
#ifndef _DATACHUNKER_H_
#include "core/dataChunker.h"
#endif
#ifndef _SCENEMANAGER_H_
#include "scene/sceneManager.h"
#endif
class SceneRenderState;
class ISceneObject;
class BaseMatInstance;
struct SceneData;
class ShaderData;
class RenderBinManager;
class LightInfo;
struct RenderInst;
class MatrixSet;
class GFXPrimitiveBufferHandle;
/// A RenderInstType hash value.
typedef U32 RenderInstTypeHash;
/// A a tiny wrapper around String that exposes a U32 operator so
/// that we can assign the RIT to RenderInst::type field.
class RenderInstType
{
/// For direct access to mName.
friend class RenderBinManager;
protected:
String mName;
public:
RenderInstType( const RenderInstType &type = Invalid )
: mName( type.mName )
{
}
RenderInstType( const String &name )
: mName( name )
{
}
~RenderInstType() {}
operator RenderInstTypeHash() const { return (RenderInstTypeHash)mName.getHashCaseInsensitive(); }
const String& getName() const { return mName; }
bool isValid() const { return (RenderInstTypeHash)*this != (RenderInstTypeHash)Invalid; }
static const RenderInstType Invalid;
};
///
class RenderPassManager : public SimObject
{
typedef SimObject Parent;
public:
// Default bin types. Not necessarily the only bin types in the system.
// RIT = "R"ender "I"nstance "T"ype
static const RenderInstType RIT_Interior;
static const RenderInstType RIT_Mesh;
static const RenderInstType RIT_Shadow;
static const RenderInstType RIT_Sky;
static const RenderInstType RIT_Terrain;
static const RenderInstType RIT_Object; // objects that do their own rendering
static const RenderInstType RIT_ObjectTranslucent;// self rendering; but sorted with static const RenderInstType RIT_Translucent
static const RenderInstType RIT_Decal;
static const RenderInstType RIT_Water;
static const RenderInstType RIT_Foliage;
static const RenderInstType RIT_Translucent;
static const RenderInstType RIT_Begin;
static const RenderInstType RIT_Custom;
static const RenderInstType RIT_Particle;
static const RenderInstType RIT_Occluder;
static const RenderInstType RIT_Editor;
public:
RenderPassManager();
virtual ~RenderPassManager();
/// @name Allocation interface
/// @{
/// Allocate a render instance, use like so: MyRenderInstType* t = gRenderInstMgr->allocInst<MyRenderInstType>();
/// Valid until ::clear called.
template <typename T>
T* allocInst()
{
T* inst = mChunker.alloc<T>();
inst->clear();
return inst;
}
/// Allocate a matrix, valid until ::clear called.
MatrixF* allocUniqueXform(const MatrixF& data)
{
MatrixF *r = mChunker.alloc<MatrixF>();
*r = data;
return r;
}
enum SharedTransformType
{
View,
Projection,
};
const MatrixF* allocSharedXform(SharedTransformType stt);
void assignSharedXform(SharedTransformType stt, const MatrixF &xfm);
MatrixSet &getMatrixSet() { return *mMatrixSet; }
/// Allocate a GFXPrimitive object which will remain valid
/// until the pass manager is cleared.
GFXPrimitive* allocPrim() { return mChunker.alloc<GFXPrimitive>(); }
/// @}
/// Add a RenderInstance to the list
virtual void addInst( RenderInst *inst );
/// Sorts the list of RenderInst's per bin. (Normally, one should just call renderPass)
void sort();
/// Renders the list of RenderInsts (Normally, one should just call renderPass)
void render( SceneRenderState *state );
/// Resets our allocated RenderInstances and Matrices. (Normally, one should just call renderPass)
void clear();
// Calls sort, render, and clear
void renderPass( SceneRenderState *state );
/// Returns the active depth buffer for this pass (NOTE: This value may be GFXTextureTarget::sDefaultDepthStencil)
GFXTextureObject *getDepthTargetTexture();
/// Assigns the value for the above method
void setDepthTargetTexture(GFXTextureObject *zTarget);
/// @name RenderBinManager interface
/// @{
/// Add a render bin manager to the list of render bin manager, this SceneRenderPassManager now owns the render bin manager and will free it when needed.
/// @param mgr Render manager to add
/// @param processAddOrder Where to add the manager in the addInst list, set to NO_PROCESSADD to skip processing
/// this is in place for RenderManagers that will bypass the main ::addInst interface and doesn't want to process
/// them.
/// @param renderOrder Where to add the manager in the render list.
void addManager(RenderBinManager* mgr);
/// Removes a manager from render and process add lists
/// @param mgr Render bin manager to remove, the caller is now responsible for freeing the mgr.
void removeManager(RenderBinManager* mgr);
/// How many render bin managers do we have?
U32 getManagerCount() const { return mRenderBins.size(); }
/// Get the render manager at i
RenderBinManager* getManager( S32 i ) const;
/// @}
/// Get scene manager which this render pass belongs to.
SceneManager* getSceneManager()
{
if ( !mSceneManager )
mSceneManager = gClientSceneGraph;
return mSceneManager;
}
/// This signal is triggered when a render bin is about to be rendered.
///
/// @param bin The render bin we're signaling.
/// @param state The current scene state.
/// @params preRender If true it is before the bin is rendered, else its
/// after being rendered.
///
typedef Signal <void ( RenderBinManager *bin,
const SceneRenderState *state,
bool preRender )> RenderBinEventSignal;
/// @see RenderBinEventSignal
static RenderBinEventSignal& getRenderBinSignal();
typedef Signal<void(RenderInst *inst)> AddInstSignal;
AddInstSignal& getAddSignal( RenderInstTypeHash type )
{
return mAddInstSignals.findOrInsert( type )->value;
}
// ConsoleObject interface
static void initPersistFields();
DECLARE_CONOBJECT(RenderPassManager);
protected:
MultiTypedChunker mChunker;
Vector< RenderBinManager* > mRenderBins;
typedef HashTable<RenderInstTypeHash,AddInstSignal> AddInstTable;
AddInstTable mAddInstSignals;
SceneManager * mSceneManager;
GFXTexHandle mDepthBuff;
MatrixSet *mMatrixSet;
/// Do a sorted insert into a vector, renderOrder bool controls which test we run for insertion.
void _insertSort(Vector<RenderBinManager*>& list, RenderBinManager* mgr, bool renderOrder);
};
//**************************************************************************
// Render Instance
//**************************************************************************
struct RenderInst
{
/// The type of render instance this is.
RenderInstTypeHash type;
/// This should be true if the object needs to be sorted
/// back to front with other translucent instances.
/// @see sortDistSq
bool translucentSort;
/// The reference squared distance from the camera used for
/// back to front sorting of the instances.
/// @see translucentSort
F32 sortDistSq;
/// The default key used by render managers for
/// internal sorting.
U32 defaultKey;
/// The secondary key used by render managers for
/// internal sorting.
U32 defaultKey2;
/// Does a memset to clear the render instance.
void clear();
};
struct ObjectRenderInst : public RenderInst
{
/// This is a delegate specific index which is usually
/// used to define a mounted object.
S32 objectIndex;
/// Extra data to be used within the render callback.
/// ObjectRenderInst does not own or cleanup this data.
void *userData;
/// The delegate callback function to call to render
/// this object instance.
///
/// @param ri The ObjectRenderInst that called the delegate.
///
/// @param state The scene state we're rendering.
///
/// @param overrideMat An alternative material to use during rendering... usually
/// used for special renders like shadows. If the object doesn't
/// support override materials it shouldn't render at all.
Delegate<void( ObjectRenderInst *ri,
SceneRenderState *state,
BaseMatInstance *overrideMat )> renderDelegate;
// Clear this instance.
void clear();
};
struct MeshRenderInst : public RenderInst
{
////
GFXVertexBufferHandleBase *vertBuff;
////
GFXPrimitiveBufferHandle *primBuff;
/// If not NULL it is used to draw the primitive, else
/// the primBuffIndex is used.
/// @see primBuffIndex
GFXPrimitive *prim;
/// If prim is NULL then this index is used to draw the
/// indexed primitive from the primitive buffer.
/// @see prim
U32 primBuffIndex;
/// The material to setup when drawing this instance.
BaseMatInstance *matInst;
/// The object to world transform (world transform in most API's).
const MatrixF *objectToWorld;
/// The worldToCamera (view transform in most API's).
const MatrixF* worldToCamera;
/// The projection matrix.
const MatrixF* projection;
// misc render states
U8 transFlags;
bool reflective;
F32 visibility;
/// A generic hint value passed from the game
/// code down to the material for use by shader
/// features.
void *materialHint;
/// The lights we pass to the material for this
/// mesh in order light importance.
LightInfo* lights[8];
// textures
GFXTextureObject *lightmap;
GFXTextureObject *fogTex;
GFXTextureObject *backBuffTex;
GFXTextureObject *reflectTex;
GFXTextureObject *miscTex;
GFXCubemap *cubemap;
void clear();
};
enum ParticleSystemState
{
PSS_AwaitingHighResDraw = 0, // Keep this as first element so that if the offscreen manager rejects a particle system it will get drawn high-res
PSS_AwaitingOffscreenDraw,
PSS_AwaitingCompositeDraw,
PSS_AwaitingMixedResDraw,
PSS_DrawComplete,
};
/// A special render instance for particles.
struct ParticleRenderInst : public RenderInst
{
/// The vertex buffer.
GFXVertexBufferHandleBase *vertBuff;
/// The primitive buffer.
GFXPrimitiveBufferHandle *primBuff;
/// The total particle count to render.
S32 count;
/// The combined model, camera, and projection transform.
const MatrixF *modelViewProj;
/// Blend style for the particle system
enum BlendStyle {
BlendUndefined = 0,
BlendNormal,
BlendAdditive,
BlendSubtractive,
BlendPremultAlpha,
BlendGreyscale,
BlendStyle_COUNT,
};
U8 blendStyle;
/// For the offscreen particle manager
U8 targetIndex;
/// State for the particle system
ParticleSystemState systemState;
/// The soft particle fade distance in meters.
F32 softnessDistance;
/// Bounding box render transform
const MatrixF *bbModelViewProj;
/// The particle texture.
GFXTextureObject *diffuseTex;
void clear();
};
class GFXOcclusionQuery;
class SceneObject;
/// A special render instance for occlusion tests.
struct OccluderRenderInst : public RenderInst
{
Point3F scale;
Point3F position;
const MatrixF *orientation;
GFXOcclusionQuery *query;
// This optional query will have all pixels rendered.
// Its purpose is to return to the user the full pixel count for comparison
// with the other query.
GFXOcclusionQuery *query2;
/// Render a sphere or a box.
bool isSphere;
void clear();
};
#endif // _RENDERPASSMANAGER_H_

View file

@ -0,0 +1,163 @@
//-----------------------------------------------------------------------------
// 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 "renderInstance/renderPassStateToken.h"
#include "console/consoleTypes.h"
#include "console/engineAPI.h"
IMPLEMENT_CONOBJECT(RenderPassStateToken);
ConsoleDocClass( RenderPassStateToken,
"@brief Abstract base class for RenderFormatToken, used to manipulate what goes on in the render manager\n\n"
"You cannot actually instantiate RenderPassToken, only its child: RenderFormatToken. "
"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 "
"a token it is declared with. 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"
"@see RenderFormatToken\n"
"@see RenderPassStateBin\n"
"@see game/core/scripts/client/renderManager.cs\n"
"@ingroup RenderBin\n"
);
void RenderPassStateToken::process(SceneRenderState *state, RenderPassStateBin *callingBin)
{
TORQUE_UNUSED(state);
TORQUE_UNUSED(callingBin);
AssertWarn(false, "RenderPassStateToken is an abstract class, you must re-implement process()");
}
void RenderPassStateToken::reset()
{
AssertWarn(false, "RenderPassStateToken is an abstract class, you must re-implement reset()");
}
void RenderPassStateToken::enable( bool enabled /*= true*/ )
{
TORQUE_UNUSED(enabled);
AssertWarn(false, "RenderPassStateToken is an abstract class, you must re-implement enable()");
}
bool RenderPassStateToken::isEnabled() const
{
AssertWarn(false, "RenderPassStateToken is an abstract class, you must re-implement isEnabled()");
return false;
}
static bool _set_enable( void *object, const char *index, const char *data )
{
reinterpret_cast<RenderPassStateToken *>(object)->enable(dAtob(data));
return false;
}
static const char *_get_enable(void* obj, const char* data)
{
TORQUE_UNUSED(data);
return reinterpret_cast<RenderPassStateToken *>(obj)->isEnabled() ? "true" : "false";
}
void RenderPassStateToken::initPersistFields()
{
addProtectedField("enabled", TypeBool, NULL, &_set_enable, &_get_enable, "Enables or disables this token.");
Parent::initPersistFields();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(RenderPassStateBin);
ConsoleDocClass( RenderPassStateBin,
"@brief A non-rendering render bin used to enable/disable a RenderPassStateToken.\n\n"
"This is a utility RenderBinManager which does not render any render instances. Its only "
"used to define a point in the render bin order at which a RenderPassStateToken is triggered.\n\n"
"@see RenderPassStateToken\n"
"@ingroup RenderBin\n"
);
RenderPassStateBin::RenderPassStateBin()
: Parent()
{
}
RenderPassStateBin::~RenderPassStateBin()
{
}
void RenderPassStateBin::render(SceneRenderState *state)
{
if(mStateToken.isValid())
mStateToken->process(state, this);
}
void RenderPassStateBin::clear()
{
if(mStateToken.isValid())
mStateToken->reset();
}
void RenderPassStateBin::sort()
{
}
void RenderPassStateBin::initPersistFields()
{
addProtectedField( "stateToken", TYPEID< RenderPassStateToken >(), Offset( mStateToken, RenderPassStateBin ),
_setStateToken, _getStateToken );
Parent::initPersistFields();
}
//------------------------------------------------------------------------------
DefineEngineMethod(RenderPassStateToken, enable, void, (),,
"@brief Enables the token." )
{
object->enable(true);
}
DefineEngineMethod(RenderPassStateToken, disable, void, (),,
"@brief Disables the token.")
{
object->enable(false);
}
DefineEngineMethod(RenderPassStateToken, toggle, void, (),,
"@brief Toggles the token from enabled to disabled or vice versa." )
{
object->enable(!object->isEnabled());
}

View file

@ -0,0 +1,87 @@
//-----------------------------------------------------------------------------
// 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 _RENDERPASSSTATETOKEN_H_
#define _RENDERPASSSTATETOKEN_H_
#ifndef _RENDERBINMANAGER_H_
#include "renderInstance/renderBinManager.h"
#endif
class RenderPassStateBin;
class RenderPassStateToken : public SimObject
{
typedef SimObject Parent;
public:
DECLARE_CONOBJECT(RenderPassStateToken);
static void initPersistFields();
// These must be re-implemented, and will assert if called on the base class.
// They just can't be pure-virtual, due to SimObject.
virtual void process(SceneRenderState *state, RenderPassStateBin *callingBin);
virtual void reset();
virtual void enable(bool enabled = true);
virtual bool isEnabled() const;
};
//------------------------------------------------------------------------------
class RenderPassStateBin : public RenderBinManager
{
typedef RenderBinManager Parent;
protected:
SimObjectPtr< RenderPassStateToken > mStateToken;
static bool _setStateToken( void* object, const char* index, const char* data )
{
RenderPassStateToken* stateToken;
Sim::findObject( data, stateToken );
reinterpret_cast< RenderPassStateBin* >( object )->mStateToken = stateToken;
return false;
}
static const char* _getStateToken( void* object, const char* data )
{
RenderPassStateBin* bin = reinterpret_cast< RenderPassStateBin* >( object );
if( bin->mStateToken.isValid() )
return bin->mStateToken->getIdString();
else
return "0";
}
public:
DECLARE_CONOBJECT(RenderPassStateBin);
static void initPersistFields();
RenderPassStateBin();
virtual ~RenderPassStateBin();
void render(SceneRenderState *state);
void clear();
void sort();
};
#endif // _RENDERPASSSTATETOKEN_H_

View file

@ -0,0 +1,855 @@
//-----------------------------------------------------------------------------
// 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/renderPrePassMgr.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 "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"
const MatInstanceHookType PrePassMatInstanceHook::Type( "PrePass" );
const String RenderPrePassMgr::BufferName("prepass");
const RenderInstType RenderPrePassMgr::RIT_PrePass("PrePass");
IMPLEMENT_CONOBJECT(RenderPrePassMgr);
ConsoleDocClass( RenderPrePassMgr,
"@brief The render bin which performs a z+normals prepass 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 #prepass "
"texture target name. See the edge anti-aliasing post effect for an example.\n\n"
"@see game/core/scripts/client/postFx/edgeAA.cs\n"
"@ingroup RenderBin\n" );
RenderPrePassMgr::RenderSignal& RenderPrePassMgr::getRenderSignal()
{
static RenderSignal theSignal;
return theSignal;
}
RenderPrePassMgr::RenderPrePassMgr( bool gatherDepth,
GFXFormat format )
: Parent( RIT_PrePass,
0.01f,
0.01f,
format,
Point2I( Parent::DefaultTargetSize, Parent::DefaultTargetSize),
gatherDepth ? Parent::DefaultTargetChainLength : 0 ),
mPrePassMatInstance( NULL )
{
notifyType( RenderPassManager::RIT_Decal );
notifyType( RenderPassManager::RIT_Mesh );
notifyType( RenderPassManager::RIT_Interior );
notifyType( RenderPassManager::RIT_Terrain );
notifyType( RenderPassManager::RIT_Object );
// We want a full-resolution buffer
mTargetSizeType = RenderTexTargetBinManager::WindowSize;
if(getTargetChainLength() > 0)
GFXShader::addGlobalMacro( "TORQUE_LINEAR_DEPTH" );
mNamedTarget.registerWithName( BufferName );
_registerFeatures();
}
RenderPrePassMgr::~RenderPrePassMgr()
{
GFXShader::removeGlobalMacro( "TORQUE_LINEAR_DEPTH" );
_unregisterFeatures();
SAFE_DELETE( mPrePassMatInstance );
}
void RenderPrePassMgr::_registerFeatures()
{
ConditionerFeature *cond = new LinearEyeDepthConditioner( getTargetFormat() );
FEATUREMGR->registerFeature( MFT_PrePassConditioner, cond );
mNamedTarget.setConditioner( cond );
}
void RenderPrePassMgr::_unregisterFeatures()
{
mNamedTarget.setConditioner( NULL );
FEATUREMGR->unregisterFeature(MFT_PrePassConditioner);
}
bool RenderPrePassMgr::setTargetSize(const Point2I &newTargetSize)
{
bool ret = Parent::setTargetSize( newTargetSize );
mNamedTarget.setViewport( GFX->getViewport() );
return ret;
}
bool RenderPrePassMgr::_updateTargets()
{
PROFILE_SCOPE(RenderPrePassMgr_updateTargets);
bool ret = Parent::_updateTargets();
// check for an output conditioner, and update it's format
ConditionerFeature *outputConditioner = dynamic_cast<ConditionerFeature *>(FEATUREMGR->getByType(MFT_PrePassConditioner));
if( outputConditioner && outputConditioner->setBufferFormat(mTargetFormat) )
{
// reload materials, the conditioner needs to alter the generated shaders
}
// Attach the light info buffer as a second render target, if there is
// lightmapped geometry in the scene.
AdvancedLightBinManager *lightBin;
if ( Sim::findObject( "AL_LightBinMgr", lightBin ) &&
lightBin->MRTLightmapsDuringPrePass() &&
lightBin->isProperlyAdded() )
{
// Update the size of the light bin target here. This will call _updateTargets
// on the light bin
ret &= lightBin->setTargetSize( mTargetSize );
if ( ret )
{
// Sanity check
AssertFatal(lightBin->getTargetChainLength() == mTargetChainLength, "Target chain length mismatch");
// Attach light info buffer to Color1 for each target in the chain
for ( U32 i = 0; i < mTargetChainLength; i++ )
{
GFXTexHandle lightInfoTex = lightBin->getTargetTexture(0, i);
mTargetChain[i]->attachTexture(GFXTextureTarget::Color1, lightInfoTex);
}
}
}
return ret;
}
void RenderPrePassMgr::_createPrePassMaterial()
{
SAFE_DELETE(mPrePassMatInstance);
const GFXVertexFormat *vertexFormat = getGFXVertexFormat<GFXVertexPNTTB>();
MatInstance* prepassMat = static_cast<MatInstance*>(MATMGR->createMatInstance("AL_DefaultPrePassMaterial", vertexFormat));
AssertFatal( prepassMat, "TODO: Handle this better." );
mPrePassMatInstance = new PrePassMatInstance(prepassMat, this);
mPrePassMatInstance->init( MATMGR->getDefaultFeatures(), vertexFormat);
delete prepassMat;
}
void RenderPrePassMgr::setPrePassMaterial( PrePassMatInstance *mat )
{
SAFE_DELETE(mPrePassMatInstance);
mPrePassMatInstance = mat;
}
void RenderPrePassMgr::addElement( RenderInst *inst )
{
PROFILE_SCOPE( RenderPrePassMgr_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;
const bool isMeshInst = inst->type == RenderPassManager::RIT_Mesh ||
inst->type == RenderPassManager::RIT_Interior;
const bool isTerrainInst = inst->type == RenderPassManager::RIT_Terrain;
// Get the material if its a mesh.
BaseMatInstance* matInst = NULL;
if ( isMeshInst || isDecalMeshInst )
matInst = static_cast<MeshRenderInst*>(inst)->matInst;
// Skip decals if they don't have normal maps.
if ( isDecalMeshInst && !matInst->hasNormalMap() )
return;
// If its a custom material and it refracts... skip it.
if ( matInst &&
matInst->isCustomMaterial() &&
static_cast<CustomMaterial*>( matInst->getMaterial() )->mRefract )
return;
// Make sure we got a prepass material.
if ( matInst )
{
matInst = getPrePassMaterial( 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
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 )
elem.key2 = matInst->getStateHint();
else
elem.key2 = originalKey;
}
void RenderPrePassMgr::sort()
{
PROFILE_SCOPE( RenderPrePassMgr_sort );
Parent::sort();
dQsort( mTerrainElementList.address(), mTerrainElementList.size(), sizeof(MainSortElem), cmpKeyFunc);
dQsort( mObjectElementList.address(), mObjectElementList.size(), sizeof(MainSortElem), cmpKeyFunc);
}
void RenderPrePassMgr::clear()
{
Parent::clear();
mTerrainElementList.clear();
mObjectElementList.clear();
}
void RenderPrePassMgr::render( SceneRenderState *state )
{
PROFILE_SCOPE(RenderPrePassMgr_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 prepass to be cleared.
// Automagically save & restore our viewport and transforms.
GFXTransformSaver saver;
GFXDEBUGEVENT_SCOPE( RenderPrePassMgr_Render, ColorI::RED );
// Tell the superclass we're about to render
const bool isRenderingToTarget = _onPreRender(state);
// Clear all the buffers to white so that the
// default depth is to the far plane.
GFX->clear( GFXClearTarget | GFXClearZBuffer | GFXClearStencil, ColorI::WHITE, 1.0f, 0);
// Restore transforms
MatrixSet &matrixSet = getRenderPass()->getMatrixSet();
matrixSet.restoreSceneViewProjection();
const MatrixF worldViewXfm = GFX->getWorldMatrix();
// Setup the default prepass material for object instances.
if ( !mPrePassMatInstance )
_createPrePassMaterial();
if ( mPrePassMatInstance )
{
matrixSet.setWorld(MatrixF::Identity);
mPrePassMatInstance->setTransforms(matrixSet, state);
}
// Signal start of pre-pass
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 prepass... so just clear it.
SceneData sgData;
sgData.init( state, SceneData::PrePassBin );
Vector< MainSortElem >::const_iterator itr = mTerrainElementList.begin();
for ( ; itr != mTerrainElementList.end(); itr++ )
{
TerrainRenderInst *ri = static_cast<TerrainRenderInst*>( itr->inst );
TerrainCellMaterial *mat = ri->cellMat->getPrePassMat();
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 );
}
// Next render all the meshes.
itr = mElementList.begin();
for ( ; itr != mElementList.end(); )
{
MeshRenderInst *ri = static_cast<MeshRenderInst*>( itr->inst );
// Get the prepass material.
BaseMatInstance *mat = getPrePassMaterial( 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-prepass materials
// here so we don't incur the cost of looking up the
// prepass hook on each inst.
//
if ( newPassNeeded( ri, passRI ) )
break;
// Set up SG data for this instance.
setupSGData( passRI, sgData );
matrixSet.setWorld(*passRI->objectToWorld);
matrixSet.setView(*passRI->worldToCamera);
matrixSet.setProjection(*passRI->projection);
mat->setSceneInfo(state, sgData);
mat->setTransforms(matrixSet, state);
// 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;
}
// 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, mPrePassMatInstance );
}
// Signal end of pre-pass
getRenderSignal().trigger( state, this, false );
if(isRenderingToTarget)
_onPostRender();
}
const GFXStateBlockDesc & RenderPrePassMgr::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 = RenderPrePassMgr::OpaqueStaticLitMask;
sOpaqueStaticLitStencilWriteDesc.stencilPassOp = GFXStencilOpReplace;
sOpaqueStaticLitStencilWriteDesc.stencilFailOp = GFXStencilOpKeep;
sOpaqueStaticLitStencilWriteDesc.stencilZFailOp = GFXStencilOpKeep;
sOpaqueStaticLitStencilWriteDesc.stencilFunc = GFXCmpAlways;
// Same only dynamic
sOpaqueDynamicLitStencilWriteDesc = sOpaqueStaticLitStencilWriteDesc;
sOpaqueDynamicLitStencilWriteDesc.stencilRef = RenderPrePassMgr::OpaqueDynamicLitMask;
}
return (lightmappedGeometry ? sOpaqueStaticLitStencilWriteDesc : sOpaqueDynamicLitStencilWriteDesc);
}
const GFXStateBlockDesc & RenderPrePassMgr::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;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
ProcessedPrePassMaterial::ProcessedPrePassMaterial( Material& mat, const RenderPrePassMgr *prePassMgr )
: Parent(mat), mPrePassMgr(prePassMgr)
{
}
void ProcessedPrePassMaterial::_determineFeatures( U32 stageNum,
MaterialFeatureData &fd,
const FeatureSet &features )
{
Parent::_determineFeatures( stageNum, fd, features );
// Find this for use down below...
bool bEnableMRTLightmap = false;
AdvancedLightBinManager *lightBin;
if ( Sim::findObject( "AL_LightBinMgr", lightBin ) )
bEnableMRTLightmap = lightBin->MRTLightmapsDuringPrePass();
// 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( mPrePassMgr->getOpaqueStenciWriteDesc( mIsLightmappedGeometry ) );
FeatureSet newFeatures;
// These are always on for prepass.
newFeatures.addFeature( MFT_EyeSpaceDepthOut );
newFeatures.addFeature( MFT_PrePassConditioner );
#ifndef TORQUE_DEDICATED
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_IsDXTnm ||
type == MFT_TexAnim ||
type == MFT_NormalMap ||
type == MFT_DetailNormalMap ||
type == MFT_AlphaTest ||
type == MFT_Parallax ||
type == MFT_InterlacedPrePass ||
type == MFT_Visibility ||
type == MFT_UseInstancing ||
type == MFT_DiffuseVertColor )
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 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 RenderTarget1
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 this object isn't lightmapped, add a zero-output feature to it
newFeatures.addFeature( MFT_RenderTarget1_Zero );
}
}
#endif
// Set the new features.
fd.features = newFeatures;
}
U32 ProcessedPrePassMaterial::getNumStages()
{
// Return 1 stage so this material gets processed for sure
return 1;
}
void ProcessedPrePassMaterial::addStateBlockDesc(const GFXStateBlockDesc& desc)
{
GFXStateBlockDesc prePassStateBlock = desc;
// Adjust color writes if this is a pure z-fill pass
const bool pixelOutEnabled = mPrePassMgr->getTargetChainLength() > 0;
if ( !pixelOutEnabled )
{
prePassStateBlock.colorWriteDefined = true;
prePassStateBlock.colorWriteRed = pixelOutEnabled;
prePassStateBlock.colorWriteGreen = pixelOutEnabled;
prePassStateBlock.colorWriteBlue = pixelOutEnabled;
prePassStateBlock.colorWriteAlpha = pixelOutEnabled;
}
// Never allow the alpha test state when rendering
// the prepass as we use the alpha channel for the
// depth information... MFT_AlphaTest will handle it.
prePassStateBlock.alphaDefined = true;
prePassStateBlock.alphaTestEnable = false;
// If we're translucent then we're doing prepass blending
// which never writes to the depth channels.
const bool isTranslucent = getMaterial()->isTranslucent();
if ( isTranslucent )
{
prePassStateBlock.setBlend( true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha );
prePassStateBlock.setColorWrites( true, true, false, false );
}
// Enable z reads, but only enable zwrites if we're not translucent.
prePassStateBlock.setZReadWrite( true, isTranslucent ? false : true );
// Pass to parent
Parent::addStateBlockDesc(prePassStateBlock);
}
PrePassMatInstance::PrePassMatInstance(MatInstance* root, const RenderPrePassMgr *prePassMgr)
: Parent(*root->getMaterial()), mPrePassMgr(prePassMgr)
{
mFeatureList = root->getRequestedFeatures();
mVertexFormat = root->getVertexFormat();
mUserObject = root->getUserObject();
}
PrePassMatInstance::~PrePassMatInstance()
{
}
ProcessedMaterial* PrePassMatInstance::getShaderMaterial()
{
return new ProcessedPrePassMaterial(*mMaterial, mPrePassMgr);
}
bool PrePassMatInstance::init( const FeatureSet &features,
const GFXVertexFormat *vertexFormat )
{
return Parent::init( features, vertexFormat );
}
PrePassMatInstanceHook::PrePassMatInstanceHook( MatInstance *baseMatInst,
const RenderPrePassMgr *prePassMgr )
: mHookedPrePassMatInst(NULL), mPrePassManager(prePassMgr)
{
// If the material is a custom material then
// hope that using DefaultPrePassMaterial gives
// them a good prepass.
if ( baseMatInst->isCustomMaterial() )
{
MatInstance* dummyInst = static_cast<MatInstance*>( MATMGR->createMatInstance( "AL_DefaultPrePassMaterial", baseMatInst->getVertexFormat() ) );
mHookedPrePassMatInst = new PrePassMatInstance( dummyInst, prePassMgr );
mHookedPrePassMatInst->init( dummyInst->getRequestedFeatures(), baseMatInst->getVertexFormat());
delete dummyInst;
return;
}
// Create the prepass material instance.
mHookedPrePassMatInst = new PrePassMatInstance(baseMatInst, prePassMgr);
mHookedPrePassMatInst->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.
mHookedPrePassMatInst->init(features, baseMatInst->getVertexFormat());
}
PrePassMatInstanceHook::~PrePassMatInstanceHook()
{
SAFE_DELETE(mHookedPrePassMatInst);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
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 *prepassSampler = new Var;
prepassSampler->setName("prepassSamplerVar");
prepassSampler->setType("sampler2D");
DecOp *prepassSamplerDecl = new DecOp(prepassSampler);
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);
meta->addStatement( new GenOp( "@(@, @)\r\n", methodDecl, prepassSamplerDecl, 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.
meta->addStatement( new GenOp( " #if TORQUE_SM >= 30\r\n" ) );
if (GFX->getAdapterType() == OpenGL)
meta->addStatement( new GenOp( " @ = texture2DLod(@, @, 0); \r\n", bufferSampleDecl, prepassSampler, screenUV) );
else
meta->addStatement( new GenOp( " @ = tex2Dlod(@, float4(@,0,0));\r\n", bufferSampleDecl, prepassSampler, screenUV ) );
meta->addStatement( new GenOp( " #else\r\n" ) );
if (GFX->getAdapterType() == OpenGL)
meta->addStatement( new GenOp( " @ = texture2D(@, @);\r\n", bufferSampleDecl, prepassSampler, screenUV) );
else
meta->addStatement( new GenOp( " @ = tex2D(@, @);\r\n", bufferSampleDecl, prepassSampler, screenUV ) );
meta->addStatement( new GenOp( " #endif\r\n\r\n" ) );
// 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;
}

View file

@ -0,0 +1,204 @@
//-----------------------------------------------------------------------------
// 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 _PREPASS_MGR_H_
#define _PREPASS_MGR_H_
#include "renderInstance/renderTexTargetBinManager.h"
#include "materials/matInstance.h"
#include "materials/processedShaderMaterial.h"
#include "shaderGen/conditionerFeature.h"
#include "core/util/autoPtr.h"
// Forward declare
class PrePassMatInstance;
// This render manager renders opaque objects to the z-buffer as a z-fill pass.
// It can optionally accumulate data from this opaque render pass into a render
// target for later use.
class RenderPrePassMgr : public RenderTexTargetBinManager
{
typedef RenderTexTargetBinManager Parent;
public:
// registered buffer name
static const String BufferName;
// Generic PrePass Render Instance Type
static const RenderInstType RIT_PrePass;
RenderPrePassMgr( bool gatherDepth = true,
GFXFormat format = GFXFormatR16G16B16A16 );
virtual ~RenderPrePassMgr();
virtual void setPrePassMaterial( PrePassMatInstance *mat );
// RenderBinManager interface
virtual void render(SceneRenderState * state);
virtual void sort();
virtual void clear();
virtual void addElement( RenderInst *inst );
// ConsoleObject
DECLARE_CONOBJECT(RenderPrePassMgr);
typedef Signal<void(const SceneRenderState*, RenderPrePassMgr*, bool)> RenderSignal;
static RenderSignal& getRenderSignal();
static const U32 OpaqueStaticLitMask = BIT(1); ///< Stencil mask for opaque, lightmapped pixels
static const U32 OpaqueDynamicLitMask = BIT(0); ///< Stencil mask for opaque, dynamic lit pixels
static const GFXStateBlockDesc &getOpaqueStencilTestDesc();
static const GFXStateBlockDesc &getOpaqueStenciWriteDesc(bool lightmappedGeometry = true);
virtual bool setTargetSize(const Point2I &newTargetSize);
inline BaseMatInstance* getPrePassMaterial( BaseMatInstance *mat );
protected:
/// The terrain render instance elements.
Vector< MainSortElem > mTerrainElementList;
/// The object render instance elements.
Vector< MainSortElem > mObjectElementList;
PrePassMatInstance *mPrePassMatInstance;
virtual void _registerFeatures();
virtual void _unregisterFeatures();
virtual bool _updateTargets();
virtual void _createPrePassMaterial();
bool _lightManagerActivate(bool active);
};
//------------------------------------------------------------------------------
class ProcessedPrePassMaterial : public ProcessedShaderMaterial
{
typedef ProcessedShaderMaterial Parent;
public:
ProcessedPrePassMaterial(Material& mat, const RenderPrePassMgr *prePassMgr);
virtual U32 getNumStages();
virtual void addStateBlockDesc(const GFXStateBlockDesc& desc);
protected:
virtual void _determineFeatures( U32 stageNum, MaterialFeatureData &fd, const FeatureSet &features );
const RenderPrePassMgr *mPrePassMgr;
bool mIsLightmappedGeometry;
};
//------------------------------------------------------------------------------
class PrePassMatInstance : public MatInstance
{
typedef MatInstance Parent;
public:
PrePassMatInstance(MatInstance* root, const RenderPrePassMgr *prePassMgr);
virtual ~PrePassMatInstance();
bool init()
{
return init( mFeatureList, mVertexFormat );
}
// MatInstance
virtual bool init( const FeatureSet &features,
const GFXVertexFormat *vertexFormat );
protected:
virtual ProcessedMaterial* getShaderMaterial();
const RenderPrePassMgr *mPrePassMgr;
};
//------------------------------------------------------------------------------
class PrePassMatInstanceHook : public MatInstanceHook
{
public:
PrePassMatInstanceHook(MatInstance *baseMatInst, const RenderPrePassMgr *prePassMgr);
virtual ~PrePassMatInstanceHook();
virtual PrePassMatInstance *getPrePassMatInstance() { return mHookedPrePassMatInst; }
virtual const MatInstanceHookType& getType() const { return Type; }
/// The type for prepass material hooks.
static const MatInstanceHookType Type;
protected:
PrePassMatInstance *mHookedPrePassMatInst;
const RenderPrePassMgr *mPrePassManager;
};
//------------------------------------------------------------------------------
// A very simple, default depth conditioner feature
class LinearEyeDepthConditioner : public ConditionerFeature
{
typedef ConditionerFeature Parent;
public:
LinearEyeDepthConditioner(const GFXFormat bufferFormat)
: Parent(bufferFormat)
{
}
virtual String getName()
{
return "Linear Eye-Space Depth Conditioner";
}
virtual void processPix( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd );
protected:
virtual Var *_conditionOutput( Var *unconditionedOutput, MultiLine *meta );
virtual Var *_unconditionInput( Var *conditionedInput, MultiLine *meta );
virtual Var *printMethodHeader( MethodType methodType, const String &methodName, Stream &stream, MultiLine *meta );
};
inline BaseMatInstance* RenderPrePassMgr::getPrePassMaterial( BaseMatInstance *mat )
{
PrePassMatInstanceHook *hook = static_cast<PrePassMatInstanceHook*>( mat->getHook( PrePassMatInstanceHook::Type ) );
if ( !hook )
{
hook = new PrePassMatInstanceHook( static_cast<MatInstance*>( mat ), this );
mat->addHook( hook );
}
return hook->getPrePassMatInstance();
}
#endif // _PREPASS_MGR_H_

View file

@ -0,0 +1,200 @@
//-----------------------------------------------------------------------------
// 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/renderTerrainMgr.h"
#include "platform/profiler.h"
#include "scene/sceneManager.h"
#include "gfx/gfxTransformSaver.h"
#include "gfx/gfxDrawUtil.h"
#include "gfx/gfxDebugEvent.h"
#include "materials/shaderData.h"
#include "materials/matInstance.h"
#include "scene/sceneRenderState.h"
#include "console/consoleTypes.h"
#include "terrain/terrCell.h"
#include "terrain/terrCellMaterial.h"
#include "math/util/matrixSet.h"
bool RenderTerrainMgr::smRenderWireframe = false;
S32 RenderTerrainMgr::smCellsRendered = 0;
S32 RenderTerrainMgr::smOverrideCells = 0;
S32 RenderTerrainMgr::smDrawCalls = 0;
IMPLEMENT_CONOBJECT(RenderTerrainMgr);
ConsoleDocClass( RenderTerrainMgr,
"@brief A render bin for terrain mesh rendering.\n\n"
"This bin renders terrain render instances from a TerrainBlock. "
"Normally a mesh would render via the RenderMeshMgr, but terrain uses "
"a TerrainMaterial designed for multi-layered surfaces which this "
"bin can processs.\n\n"
"@ingroup RenderBin\n" );
RenderTerrainMgr::RenderTerrainMgr()
: RenderBinManager( RenderPassManager::RIT_Terrain, 1.0f, 1.0f )
{
}
RenderTerrainMgr::RenderTerrainMgr( F32 renderOrder, F32 processAddOrder )
: RenderBinManager( RenderPassManager::RIT_Terrain, renderOrder, processAddOrder )
{
}
RenderTerrainMgr::~RenderTerrainMgr()
{
}
void RenderTerrainMgr::initPersistFields()
{
Con::addVariable( "RenderTerrainMgr::renderWireframe", TypeBool, &smRenderWireframe,
"Used to enable wireframe rendering on terrain for debugging.\n"
"@ingroup RenderBin\n" );
// For stats.
GFXDevice::getDeviceEventSignal().notify( &RenderTerrainMgr::_clearStats );
Con::addVariable( "$TerrainBlock::cellsRendered", TypeS32, &smCellsRendered, "@internal" );
Con::addVariable( "$TerrainBlock::overrideCells", TypeS32, &smOverrideCells, "@internal" );
Con::addVariable( "$TerrainBlock::drawCalls", TypeS32, &smDrawCalls, "@internal" );
Parent::initPersistFields();
}
bool RenderTerrainMgr::_clearStats( GFXDevice::GFXDeviceEventType type )
{
if ( type == GFXDevice::deStartOfFrame )
{
smCellsRendered = 0;
smOverrideCells = 0;
smDrawCalls = 0;
}
return true;
}
void RenderTerrainMgr::internalAddElement( RenderInst *inst_ )
{
TerrainRenderInst *inst = static_cast<TerrainRenderInst*>( inst_ );
mInstVector.push_back( inst );
}
void RenderTerrainMgr::sort()
{
// TODO: We could probably sort this in some
// manner to improve terrain rendering perf.
}
void RenderTerrainMgr::clear()
{
mInstVector.clear();
}
void RenderTerrainMgr::render( SceneRenderState *state )
{
if ( mInstVector.empty() )
return;
PROFILE_SCOPE( RenderTerrainMgr_Render );
GFXTransformSaver saver;
// Prepare the common scene graph data.
SceneData sgData;
sgData.init( state );
sgData.wireframe |= smRenderWireframe;
// Restore transforms
MatrixSet &matrixSet = getRenderPass()->getMatrixSet();
matrixSet.restoreSceneViewProjection();
GFXDEBUGEVENT_SCOPE( RenderTerrainMgr_Render, ColorI::GREEN );
const MatrixF worldViewXfm = matrixSet.getWorldToCamera();
const MatrixF &projXfm = matrixSet.getCameraToScreen();
// HACKTASTIC!
//
// If this is a shadow pass then render the terrain
// with the first material we get.
//
// In the near future terrains will operate using regular
// MatInstance materials like any other mesh in which case
// this will all be replaced by a normal mesh render bin.
//
if ( state->isShadowPass() )
{
PROFILE_SCOPE( RenderTerrainMgr_Render_Shadow );
Vector<TerrainRenderInst*>::iterator inst = mInstVector.begin();
BaseMatInstance *overideMat = (*inst)->mat;
while ( overideMat && overideMat->setupPass( state, sgData ) )
{
for ( ; inst != mInstVector.end(); inst++ )
{
smOverrideCells++;
GFX->setPrimitiveBuffer( (*inst)->primBuff );
GFX->setVertexBuffer( (*inst)->vertBuff );
matrixSet.setWorld(*(*inst)->objectToWorldXfm);
overideMat->setSceneInfo( state, sgData );
overideMat->setTransforms( matrixSet, state );
GFX->drawPrimitive( (*inst)->prim );
}
}
return;
}
// Do the detail map passes.
Vector<TerrainRenderInst*>::iterator inst = mInstVector.begin();
for ( ; inst != mInstVector.end(); inst++ )
{
TerrainCellMaterial *mat = (*inst)->cellMat;
GFX->setPrimitiveBuffer( (*inst)->primBuff );
GFX->setVertexBuffer( (*inst)->vertBuff );
++smCellsRendered;
mat->setTransformAndEye( *(*inst)->objectToWorldXfm,
worldViewXfm,
projXfm,
state->getFarPlane() );
sgData.objTrans = (*inst)->objectToWorldXfm;
dMemcpy( sgData.lights, (*inst)->lights, sizeof( sgData.lights ) );
while ( mat->setupPass( state, sgData ) )
{
++smDrawCalls;
GFX->drawPrimitive( (*inst)->prim );
}
}
}

View file

@ -0,0 +1,105 @@
//-----------------------------------------------------------------------------
// 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 _RENDERTERRAINMGR_H_
#define _RENDERTERRAINMGR_H_
#ifndef _RENDERBINMANAGER_H_
#include "renderInstance/renderBinManager.h"
#endif
#ifndef _GFXVERTEXBUFFER_H_
#include "gfx/gfxVertexBuffer.h"
#endif
#ifndef _GFXPRIMITIVEBUFFER_H_
#include "gfx/gfxPrimitiveBuffer.h"
#endif
class TerrCell;
class GFXTextureObject;
class TerrainCellMaterial;
/// The render instance for terrain cells.
struct TerrainRenderInst : public RenderInst
{
GFXVertexBuffer *vertBuff;
GFXPrimitiveBuffer *primBuff;
GFXPrimitive prim;
BaseMatInstance *mat;
const MatrixF *objectToWorldXfm;
TerrainCellMaterial *cellMat;
/// The lights we pass to the material for
/// this cell in order light importance.
LightInfo *lights[8];
void clear()
{
dMemset( this, 0, sizeof( TerrainRenderInst ) );
type = RenderPassManager::RIT_Terrain;
}
};
///
class RenderTerrainMgr : public RenderBinManager
{
typedef RenderBinManager Parent;
protected:
Vector<TerrainRenderInst*> mInstVector;
static bool smRenderWireframe;
static S32 smCellsRendered;
static S32 smOverrideCells;
static S32 smDrawCalls;
static bool _clearStats( GFXDevice::GFXDeviceEventType type );
// RenderBinManager
virtual void internalAddElement( RenderInst *inst );
public:
RenderTerrainMgr();
RenderTerrainMgr( F32 renderOrder, F32 processAddOrder );
virtual ~RenderTerrainMgr();
// ConsoleObject
static void initPersistFields();
DECLARE_CONOBJECT(RenderTerrainMgr);
// RenderBinManager
virtual void sort();
virtual void render( SceneRenderState *state );
virtual void clear();
};
#endif // _RENDERTERRAINMGR_H_

View file

@ -0,0 +1,309 @@
//-----------------------------------------------------------------------------
// 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/renderTexTargetBinManager.h"
#include "shaderGen/conditionerFeature.h"
#include "core/util/safeDelete.h"
#include "gfx/gfxTextureManager.h"
#include "gfx/gfxStringEnumTranslate.h"
#include "scene/sceneRenderState.h"
#include "scene/sceneManager.h"
IMPLEMENT_CONOBJECT(RenderTexTargetBinManager);
ConsoleDocClass( RenderTexTargetBinManager,
"@brief An abstract base class for render bin managers that render to a named textue target.\n\n"
"This bin itself doesn't do any rendering work. It offers functionality to manage "
"a texture render target which derived render bin classes can render into.\n\n"
"@see RenderPrePassMgr\n"
"@ingroup RenderBin\n" );
RenderTexTargetBinManager::RenderTexTargetBinManager( const RenderInstType& ritype,
F32 renderOrder,
F32 processAddOrder,
const GFXFormat targetFormat,
const Point2I &targetSize,
const U32 targetChainLength )
: Parent( ritype, renderOrder, processAddOrder ),
mTargetFormat(targetFormat),
mTargetSize(targetSize),
mTargetScale(1.0f, 1.0f),
mTargetSizeType(FixedSize),
mTargetChainLength(targetChainLength),
mTargetChainIdx(0),
mNumRenderTargets(1),
mTargetChain(NULL),
mTargetChainTextures(NULL)
#ifndef TORQUE_SHIPPING
,m_NeedsOnPostRender(false)
#endif
{
GFXDevice::getDeviceEventSignal().notify(this, &RenderTexTargetBinManager::_handleGFXEvent);
GFXTextureManager::addEventDelegate( this, &RenderTexTargetBinManager::_onTextureEvent );
mNamedTarget.setSamplerState( GFXSamplerStateDesc::getClampPoint() );
}
RenderTexTargetBinManager::~RenderTexTargetBinManager()
{
_teardownTargets();
GFXTextureManager::removeEventDelegate( this, &RenderTexTargetBinManager::_onTextureEvent );
GFXDevice::getDeviceEventSignal().remove(this, &RenderTexTargetBinManager::_handleGFXEvent);
}
bool RenderTexTargetBinManager::onAdd()
{
if(!Parent::onAdd())
return false;
_setupTargets();
return true;
}
ImplementEnumType( RenderTexTargetSize,
"What size to render the target texture. Sizes are based on the Window the render is occuring in.\n"
"@ingroup RenderBin\n\n")
{ RenderTexTargetBinManager::WindowSize, "windowsize", "Render to the size of the window.\n" },
{ RenderTexTargetBinManager::WindowSizeScaled, "windowsizescaled", "Render to the size of the window, scaled to the render target's size.\n" },
{ RenderTexTargetBinManager::FixedSize, "fixedsize", "Don't scale the target texture, and render to its default size.\n" },
EndImplementEnumType;
void RenderTexTargetBinManager::initPersistFields()
{
// TOM_TODO:
//addField( "targetScale", mTargetScale );
//addPropertyNOPS( "targetSizeType", mTargetSizeType)->setEnumTable(gSizeTypeEnumTable);
//addPropertyNOPS<S32>( "targetFormat")->setEnumTable(gTextureFormatEnumTable)->addGet(this, &RenderTexTargetBinManager::getTargetFormatConsole)->addSet(this, &RenderTexTargetBinManager::setTargetFormatConsole);
//addProperty<bool>( "blur" )->addSet(this, &RenderTexTargetBinManager::setBlur)->addGet(this, &RenderTexTargetBinManager::getBlur);
Parent::initPersistFields();
}
bool RenderTexTargetBinManager::setTargetSize(const Point2I &newTargetSize)
{
if( GFX->getAdapterType() != OpenGL && // Targets need to match up exactly in size on OpenGL.
mTargetSize.x >= newTargetSize.x &&
mTargetSize.y >= newTargetSize.y )
return true;
mTargetSize = newTargetSize;
mNamedTarget.setViewport( RectI( Point2I::Zero, mTargetSize ) );
return _updateTargets();
}
bool RenderTexTargetBinManager::setTargetFormat(const GFXFormat &newTargetFormat)
{
if(mTargetFormat == newTargetFormat)
return true;
mTargetFormat = newTargetFormat;
ConditionerFeature *conditioner = mNamedTarget.getConditioner();
if(conditioner)
conditioner->setBufferFormat(mTargetFormat);
return _updateTargets();
}
void RenderTexTargetBinManager::setTargetChainLength(const U32 chainLength)
{
if(mTargetChainLength != chainLength)
{
mTargetChainLength = chainLength;
_setupTargets();
}
}
GFXTextureObject* RenderTexTargetBinManager::getTargetTexture( U32 mrtIndex, S32 chainIndex ) const
{
const U32 chainIdx = ( chainIndex > -1 ) ? chainIndex : mTargetChainIdx;
if(chainIdx < mTargetChainLength)
return mTargetChainTextures[chainIdx][mrtIndex];
return NULL;
}
bool RenderTexTargetBinManager::_updateTargets()
{
PROFILE_SCOPE(RenderTexTargetBinManager_updateTargets);
bool ret = true;
mNamedTarget.release();
// Update the target size
for( U32 i = 0; i < mTargetChainLength; i++ )
{
AssertFatal( mTargetChain != NULL, "RenderTexTargetBinManager - target chain not set up" );
if( !mTargetChain[i] )
mTargetChain[i] = GFX->allocRenderToTextureTarget();
for( U32 j = 0; j < mNumRenderTargets; j++ )
{
ret &= mTargetChainTextures[i][j].set( mTargetSize.x, mTargetSize.y, mTargetFormat,
&GFXDefaultRenderTargetProfile, avar( "%s() - (line %d)", __FUNCTION__, __LINE__ ),
1, GFXTextureManager::AA_MATCH_BACKBUFFER );
mTargetChain[i]->attachTexture( GFXTextureTarget::RenderSlot(GFXTextureTarget::Color0 + j), mTargetChainTextures[i][j] );
}
}
return ret;
}
bool RenderTexTargetBinManager::_handleGFXEvent( GFXDevice::GFXDeviceEventType event_ )
{
if ( event_ == GFXDevice::deStartOfFrame )
{
mTargetChainIdx++;
if ( mTargetChainIdx >= mTargetChainLength )
mTargetChainIdx = 0;
}
return true;
}
void RenderTexTargetBinManager::_onTextureEvent( GFXTexCallbackCode code )
{
switch(code)
{
case GFXZombify:
_teardownTargets();
break;
case GFXResurrect:
_setupTargets();
break;
}
}
bool RenderTexTargetBinManager::_setupTargets()
{
_teardownTargets();
mTargetChain = new GFXTextureTargetRef[mTargetChainLength];
mTargetChainTextures = new GFXTexHandle*[mTargetChainLength];
for( U32 i = 0; i < mTargetChainLength; i++ )
mTargetChainTextures[i] = new GFXTexHandle[mNumRenderTargets];
mTargetChainIdx = 0;
mTargetSize = Point2I::Zero;
return true;
}
void RenderTexTargetBinManager::_teardownTargets()
{
mNamedTarget.release();
SAFE_DELETE_ARRAY(mTargetChain);
if(mTargetChainTextures != NULL)
{
for( U32 i = 0; i < mTargetChainLength; i++ )
SAFE_DELETE_ARRAY(mTargetChainTextures[i]);
}
SAFE_DELETE_ARRAY(mTargetChainTextures);
}
GFXTextureTargetRef RenderTexTargetBinManager::_getTextureTarget(const U32 idx /* = 0 */)
{
return mTargetChain[idx];
}
bool RenderTexTargetBinManager::_onPreRender(SceneRenderState * state, bool preserve /* = false */)
{
PROFILE_SCOPE(RenderTexTargetBinManager_onPreRender);
#ifndef TORQUE_SHIPPING
AssertFatal( m_NeedsOnPostRender == false, "_onPostRender not called on RenderTexTargetBinManager, or sub-class." );
m_NeedsOnPostRender = false;
#endif
// Update the render target size
const Point2I &rtSize = GFX->getActiveRenderTarget()->getSize();
switch(mTargetSizeType)
{
case WindowSize:
setTargetSize(rtSize);
break;
case WindowSizeScaled:
{
Point2I scaledTargetSize(mFloor(rtSize.x * mTargetScale.x), mFloor(rtSize.y * mTargetScale.y));
setTargetSize(scaledTargetSize);
break;
}
case FixedSize:
// No adjustment necessary
break;
}
if( mTargetChainLength == 0 )
return false;
GFXTextureTargetRef binTarget = _getTextureTarget(mTargetChainIdx);
if( binTarget.isNull() )
return false;
// Attach active depth target texture
binTarget->attachTexture(GFXTextureTarget::DepthStencil, getRenderPass()->getDepthTargetTexture());
// Preserve contents
if(preserve)
GFX->getActiveRenderTarget()->preserve();
GFX->pushActiveRenderTarget();
GFX->setActiveRenderTarget(binTarget);
GFX->setViewport( mNamedTarget.getViewport() );
#ifndef TORQUE_SHIPPING
m_NeedsOnPostRender = true;
#endif
return true;
}
void RenderTexTargetBinManager::_onPostRender()
{
PROFILE_SCOPE(RenderTexTargetBinManager_onPostRender);
#ifndef TORQUE_SHIPPING
m_NeedsOnPostRender = false;
#endif
GFXTextureTargetRef binTarget = _getTextureTarget(mTargetChainIdx);
binTarget->resolve();
GFX->popActiveRenderTarget();
for ( U32 i=0; i < mNumRenderTargets; i++ )
mNamedTarget.setTexture( i, mTargetChainTextures[mTargetChainIdx][i] );
}

View file

@ -0,0 +1,135 @@
//-----------------------------------------------------------------------------
// 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 _TEXTARGETBIN_MGR_H_
#define _TEXTARGETBIN_MGR_H_
#ifndef _RENDERBINMANAGER_H_
#include "renderInstance/renderBinManager.h"
#endif
#ifndef _MATTEXTURETARGET_H_
#include "materials/matTextureTarget.h"
#endif
class ConditionerFeature;
class RenderTexTargetBinManager : public RenderBinManager
{
typedef RenderBinManager Parent;
public:
static const GFXFormat DefaultTargetFormat = GFXFormatR8G8B8A8;
static const U32 DefaultTargetChainLength = 1;
static const U32 DefaultTargetSize = 256;
enum TargetSizeType
{
WindowSize = 0,
WindowSizeScaled,
FixedSize
};
public:
RenderTexTargetBinManager( const RenderInstType &ritype = RenderPassManager::RIT_Mesh,
F32 renderOrder = 1.0f,
F32 processAddOrder = 1.0f,
const GFXFormat targetFormat = DefaultTargetFormat,
const Point2I &targetSize = Point2I(DefaultTargetSize, DefaultTargetSize),
const U32 targetChainLength = DefaultTargetChainLength);
virtual ~RenderTexTargetBinManager();
virtual bool setTargetSize(const Point2I &newTargetSize);
virtual GFXTextureObject* getTargetTexture( U32 mrtIndex, S32 chainIndex = -1 ) const;
/// Force a target update
virtual bool updateTargets() { return _updateTargets(); }
void setTargetFormatConsole(const S32 &fmt) { setTargetFormat(GFXFormat(fmt)); }
virtual bool setTargetFormat(const GFXFormat &newTargetFormat);
S32 getTargetFormatConsole() { return getTargetFormat(); }
virtual const GFXFormat &getTargetFormat() const { return mTargetFormat; }
virtual void setTargetChainLength(const U32 chainLength);
virtual U32 getTargetChainLength() const { return mTargetChainLength; }
DECLARE_CONOBJECT(RenderTexTargetBinManager);
static void initPersistFields();
virtual bool onAdd();
protected:
NamedTexTarget mNamedTarget;
GFXFormat mTargetFormat;
Point2I mTargetSize;
Point2F mTargetScale;
//RectI mTargetViewport;
TargetSizeType mTargetSizeType;
U32 mTargetChainLength;
U32 mTargetChainIdx;
U32 mNumRenderTargets;
GFXTextureTargetRef *mTargetChain;
GFXTexHandle **mTargetChainTextures;
#ifndef TORQUE_SHIPPING
bool m_NeedsOnPostRender;
#endif
bool mPreserve;
virtual bool _handleGFXEvent(GFXDevice::GFXDeviceEventType event);
virtual GFXTextureTargetRef _getTextureTarget(const U32 idx = 0);
/// Pushes the active render target, and sets itself as a render target. The
/// target is then cleared using 'mTargetClearColor', viewport is set properly,
/// and true is returned, and '_onPostRender' must be called after rendering
/// is complete. If the return value is false, than '_onPostRender'
/// should not be called.
///
/// @param preserve If set to true, the contents of the current render target
// will be the same when _onPostRender is called. Otherwise
// the contents are undefined on console platforms.
virtual bool _onPreRender(SceneRenderState * state, bool preserve = false);
/// Resolves the active render target, pops the render target from _onPreRender, and sets debug info.
virtual void _onPostRender();
virtual bool _updateTargets();
virtual bool _setupTargets();
virtual void _teardownTargets();
/// The callback used to get texture events.
/// @see GFXTextureManager::addEventDelegate
void _onTextureEvent( GFXTexCallbackCode code );
};
typedef RenderTexTargetBinManager::TargetSizeType RenderTexTargetSize;
DefineEnumType( RenderTexTargetSize );
#endif // _TEXTARGETBIN_MGR_H_

View file

@ -0,0 +1,280 @@
//-----------------------------------------------------------------------------
// 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/renderTranslucentMgr.h"
#include "materials/sceneData.h"
#include "scene/sceneManager.h"
#include "scene/sceneObject.h"
#include "scene/sceneRenderState.h"
#include "materials/matInstance.h"
#include "gfx/gfxPrimitiveBuffer.h"
#include "gfx/gfxTransformSaver.h"
#include "gfx/gfxDebugEvent.h"
#include "renderInstance/renderParticleMgr.h"
#include "math/util/matrixSet.h"
#define HIGH_NUM ((U32(-1)/2) - 1)
IMPLEMENT_CONOBJECT(RenderTranslucentMgr);
ConsoleDocClass( RenderTranslucentMgr,
"@brief A render bin for rendering translucent meshes.\n\n"
"This bin is used to render translucent render mesh instances and render object "
"instances. It is generally ordered late in the RenderPassManager after all opaque "
"geometry bins.\n\n"
"@ingroup RenderBin\n" );
RenderTranslucentMgr::RenderTranslucentMgr()
: RenderBinManager( RenderPassManager::RIT_Translucent, 1.0f, 1.0f ), mParticleRenderMgr(NULL)
{
notifyType( RenderPassManager::RIT_ObjectTranslucent );
notifyType( RenderPassManager::RIT_Particle );
}
RenderTranslucentMgr::~RenderTranslucentMgr()
{
}
void RenderTranslucentMgr::setupSGData(MeshRenderInst *ri, SceneData &data )
{
Parent::setupSGData( ri, data );
// We do not support these in the translucent bin.
data.backBuffTex = NULL;
data.cubemap = NULL;
data.lightmap = NULL;
}
void RenderTranslucentMgr::addElement( RenderInst *inst )
{
// Right off the bat if its not translucent skip it.
if ( !inst->translucentSort )
return;
// What type of instance is this.
const bool isMeshInst = inst->type == RenderPassManager::RIT_Translucent;
// Get its material if its a mesh.
BaseMatInstance* matInst = NULL;
if ( isMeshInst )
matInst = static_cast<MeshRenderInst*>( inst )->matInst;
// If the material isn't translucent the skip it.
if ( matInst && !matInst->getMaterial()->isTranslucent() )
return;
// We made it this far, add the instance.
mElementList.increment();
MainSortElem& elem = mElementList.last();
elem.inst = inst;
// Override the instances default key to be the sort distance. All
// the pointer dereferencing is in there to prevent us from losing
// information when converting to a U32.
elem.key = *((U32*)&inst->sortDistSq);
AssertFatal( inst->defaultKey != 0, "RenderTranslucentMgr::addElement() - Got null sort key... did you forget to set it?" );
// Then use the instances primary key as our secondary key
elem.key2 = inst->defaultKey;
}
GFXStateBlockRef RenderTranslucentMgr::_getStateBlock( U8 transFlag )
{
if ( mStateBlocks[transFlag].isValid() )
return mStateBlocks[transFlag];
GFXStateBlockDesc d;
d.cullDefined = true;
d.cullMode = GFXCullNone;
d.blendDefined = true;
d.blendEnable = true;
d.blendSrc = (GFXBlend)((transFlag >> 4) & 0x0f);
d.blendDest = (GFXBlend)(transFlag & 0x0f);
d.alphaDefined = true;
// See http://www.garagegames.com/mg/forums/result.thread.php?qt=81397
d.alphaTestEnable = (d.blendSrc == GFXBlendSrcAlpha && (d.blendDest == GFXBlendInvSrcAlpha || d.blendDest == GFXBlendOne));
d.alphaTestRef = 1;
d.alphaTestFunc = GFXCmpGreaterEqual;
d.zDefined = true;
d.zWriteEnable = false;
d.samplersDefined = true;
d.samplers[0] = GFXSamplerStateDesc::getClampLinear();
d.samplers[0].alphaOp = GFXTOPModulate;
d.samplers[0].alphaArg1 = GFXTATexture;
d.samplers[0].alphaArg2 = GFXTADiffuse;
mStateBlocks[transFlag] = GFX->createStateBlock(d);
return mStateBlocks[transFlag];
}
void RenderTranslucentMgr::render( SceneRenderState *state )
{
PROFILE_SCOPE(RenderTranslucentMgr_render);
// Early out if nothing to draw.
if(!mElementList.size())
return;
GFXDEBUGEVENT_SCOPE(RenderTranslucentMgr_Render, ColorI::BLUE);
// Find the particle render manager (if we don't have it)
if(mParticleRenderMgr == NULL)
{
RenderPassManager *rpm = state->getRenderPass();
for( U32 i = 0; i < rpm->getManagerCount(); i++ )
{
RenderBinManager *bin = rpm->getManager(i);
if( bin->getRenderInstType() == RenderParticleMgr::RIT_Particles )
{
mParticleRenderMgr = reinterpret_cast<RenderParticleMgr *>(bin);
break;
}
}
}
GFXTransformSaver saver;
SceneData sgData;
sgData.init( state );
GFXVertexBuffer * lastVB = NULL;
GFXPrimitiveBuffer * lastPB = NULL;
// Restore transforms
MatrixSet &matrixSet = getRenderPass()->getMatrixSet();
matrixSet.restoreSceneViewProjection();
U32 binSize = mElementList.size();
for( U32 j=0; j<binSize; )
{
RenderInst *baseRI = mElementList[j].inst;
U32 matListEnd = j;
// render these separately...
if ( baseRI->type == RenderPassManager::RIT_ObjectTranslucent )
{
ObjectRenderInst* objRI = static_cast<ObjectRenderInst*>(baseRI);
objRI->renderDelegate( objRI, state, NULL );
lastVB = NULL;
lastPB = NULL;
j++;
continue;
}
else if ( baseRI->type == RenderPassManager::RIT_Particle )
{
ParticleRenderInst *ri = static_cast<ParticleRenderInst*>(baseRI);
// Tell Particle RM to draw the system. (This allows the particle render manager
// to manage drawing offscreen particle systems, and allows the systems
// to be composited back into the scene with proper translucent
// sorting order)
mParticleRenderMgr->renderInstance(ri, state);
lastVB = NULL; // no longer valid, null it
lastPB = NULL; // no longer valid, null it
j++;
continue;
}
else if ( baseRI->type == RenderPassManager::RIT_Translucent )
{
MeshRenderInst* ri = static_cast<MeshRenderInst*>(baseRI);
BaseMatInstance *mat = ri->matInst;
setupSGData( ri, sgData );
while( mat->setupPass( state, sgData ) )
{
U32 a;
for( a=j; a<binSize; a++ )
{
RenderInst* nextRI = mElementList[a].inst;
if ( nextRI->type != RenderPassManager::RIT_Translucent )
break;
MeshRenderInst *passRI = static_cast<MeshRenderInst*>(nextRI);
// Check to see if we need to break this batch.
if ( newPassNeeded( ri, passRI ) )
break;
// Z sorting and stuff is still not working in this mgr...
setupSGData( passRI, sgData );
mat->setSceneInfo(state, sgData);
matrixSet.setWorld(*passRI->objectToWorld);
matrixSet.setView(*passRI->worldToCamera);
matrixSet.setProjection(*passRI->projection);
mat->setTransforms(matrixSet, state);
// 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() )
{
a++;
break;
}
continue;
}
// 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 );
// Render the instanced stream.
if ( ri->prim )
GFX->drawPrimitive( *ri->prim );
else
GFX->drawPrimitive( ri->primBuffIndex );
}
matListEnd = a;
}
// force increment if none happened, otherwise go to end of batch
j = ( j == matListEnd ) ? j+1 : matListEnd;
}
}
}

View file

@ -0,0 +1,67 @@
//-----------------------------------------------------------------------------
// 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 _RENDER_TRANSLUCENT_MGR_H_
#define _RENDER_TRANSLUCENT_MGR_H_
#ifndef _RENDERBINMANAGER_H_
#include "renderInstance/renderBinManager.h"
#endif
#ifndef _MATTEXTURETARGET_H_
#include "materials/matTextureTarget.h"
#endif
class RenderParticleMgr;
class RenderTranslucentMgr : public RenderBinManager
{
typedef RenderBinManager Parent;
public:
RenderTranslucentMgr();
RenderTranslucentMgr( F32 renderOrder, F32 processAddOrder );
virtual ~RenderTranslucentMgr();
// RenderBinManager
void render(SceneRenderState * state);
void addElement( RenderInst *inst );
void setupSGData( MeshRenderInst *ri, SceneData &data );
// ConsoleObject
DECLARE_CONOBJECT(RenderTranslucentMgr);
protected:
// This is a stateblock per potential blend type, we create
// these as needed.
enum
{
MaxBlend = 256
};
GFXStateBlockRef mStateBlocks[MaxBlend];
GFXStateBlockRef _getStateBlock( U8 transFlag );
RenderParticleMgr *mParticleRenderMgr;;
};
#endif // _RENDER_TRANSLUCENT_MGR_H_