mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-02-28 02:53:49 +00:00
Engine directory for ticket #1
This commit is contained in:
parent
352279af7a
commit
7dbfe6994d
3795 changed files with 1363358 additions and 0 deletions
134
Engine/source/renderInstance/forcedMaterialMeshMgr.cpp
Normal file
134
Engine/source/renderInstance/forcedMaterialMeshMgr.cpp
Normal 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;
|
||||
}
|
||||
|
||||
55
Engine/source/renderInstance/forcedMaterialMeshMgr.h
Normal file
55
Engine/source/renderInstance/forcedMaterialMeshMgr.h
Normal 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
|
||||
177
Engine/source/renderInstance/renderBinManager.cpp
Normal file
177
Engine/source/renderInstance/renderBinManager.cpp
Normal 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();
|
||||
}
|
||||
170
Engine/source/renderInstance/renderBinManager.h
Normal file
170
Engine/source/renderInstance/renderBinManager.h
Normal 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_
|
||||
375
Engine/source/renderInstance/renderFormatChanger.cpp
Normal file
375
Engine/source/renderInstance/renderFormatChanger.cpp
Normal 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();
|
||||
}
|
||||
99
Engine/source/renderInstance/renderFormatChanger.h
Normal file
99
Engine/source/renderInstance/renderFormatChanger.h
Normal 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_
|
||||
223
Engine/source/renderInstance/renderGlowMgr.cpp
Normal file
223
Engine/source/renderInstance/renderGlowMgr.cpp
Normal 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 );
|
||||
}
|
||||
89
Engine/source/renderInstance/renderGlowMgr.h
Normal file
89
Engine/source/renderInstance/renderGlowMgr.h
Normal 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_
|
||||
351
Engine/source/renderInstance/renderImposterMgr.cpp
Normal file
351
Engine/source/renderInstance/renderImposterMgr.cpp
Normal 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;
|
||||
}
|
||||
139
Engine/source/renderInstance/renderImposterMgr.h
Normal file
139
Engine/source/renderInstance/renderImposterMgr.h
Normal 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_
|
||||
261
Engine/source/renderInstance/renderMeshMgr.cpp
Normal file
261
Engine/source/renderInstance/renderMeshMgr.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
54
Engine/source/renderInstance/renderMeshMgr.h
Normal file
54
Engine/source/renderInstance/renderMeshMgr.h
Normal 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_
|
||||
75
Engine/source/renderInstance/renderObjectMgr.cpp
Normal file
75
Engine/source/renderInstance/renderObjectMgr.cpp
Normal 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 );
|
||||
}
|
||||
}
|
||||
51
Engine/source/renderInstance/renderObjectMgr.h
Normal file
51
Engine/source/renderInstance/renderObjectMgr.h
Normal 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_
|
||||
254
Engine/source/renderInstance/renderOcclusionMgr.cpp
Normal file
254
Engine/source/renderInstance/renderOcclusionMgr.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
61
Engine/source/renderInstance/renderOcclusionMgr.h
Normal file
61
Engine/source/renderInstance/renderOcclusionMgr.h
Normal 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_
|
||||
806
Engine/source/renderInstance/renderParticleMgr.cpp
Normal file
806
Engine/source/renderInstance/renderParticleMgr.cpp
Normal 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( ¯os );
|
||||
|
||||
// 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;
|
||||
}
|
||||
141
Engine/source/renderInstance/renderParticleMgr.h
Normal file
141
Engine/source/renderInstance/renderParticleMgr.h
Normal 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_
|
||||
365
Engine/source/renderInstance/renderPassManager.cpp
Normal file
365
Engine/source/renderInstance/renderPassManager.cpp
Normal 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 );
|
||||
}
|
||||
|
||||
446
Engine/source/renderInstance/renderPassManager.h
Normal file
446
Engine/source/renderInstance/renderPassManager.h
Normal 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_
|
||||
163
Engine/source/renderInstance/renderPassStateToken.cpp
Normal file
163
Engine/source/renderInstance/renderPassStateToken.cpp
Normal 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());
|
||||
}
|
||||
87
Engine/source/renderInstance/renderPassStateToken.h
Normal file
87
Engine/source/renderInstance/renderPassStateToken.h
Normal 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_
|
||||
855
Engine/source/renderInstance/renderPrePassMgr.cpp
Normal file
855
Engine/source/renderInstance/renderPrePassMgr.cpp
Normal 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;
|
||||
}
|
||||
204
Engine/source/renderInstance/renderPrePassMgr.h
Normal file
204
Engine/source/renderInstance/renderPrePassMgr.h
Normal 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_
|
||||
|
||||
200
Engine/source/renderInstance/renderTerrainMgr.cpp
Normal file
200
Engine/source/renderInstance/renderTerrainMgr.cpp
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
105
Engine/source/renderInstance/renderTerrainMgr.h
Normal file
105
Engine/source/renderInstance/renderTerrainMgr.h
Normal 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_
|
||||
309
Engine/source/renderInstance/renderTexTargetBinManager.cpp
Normal file
309
Engine/source/renderInstance/renderTexTargetBinManager.cpp
Normal 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] );
|
||||
}
|
||||
135
Engine/source/renderInstance/renderTexTargetBinManager.h
Normal file
135
Engine/source/renderInstance/renderTexTargetBinManager.h
Normal 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_
|
||||
280
Engine/source/renderInstance/renderTranslucentMgr.cpp
Normal file
280
Engine/source/renderInstance/renderTranslucentMgr.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
67
Engine/source/renderInstance/renderTranslucentMgr.h
Normal file
67
Engine/source/renderInstance/renderTranslucentMgr.h
Normal 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_
|
||||
Loading…
Add table
Add a link
Reference in a new issue