123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822 |
- //-----------------------------------------------------------------------------
- // 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/renderDeferredMgr.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.5f, 0.5f);
- // We use the target chain like a texture pool, not like a swap chain
- if(!RenderToSingleTarget)
- setTargetChainLength(5);
- else
- mOffscreenSystems.setSize(1);
-
- notifyType( RenderPassManager::RIT_Particle );
- 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(S32 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(S32 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 [] = {
- 0, 1, 2, 3,
- };
- mScreenQuadPrimBuff.immutable(GFX, 4, 2, prims);
- 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 );
- }
- renderParticle(ri, state);
- }
- 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( mParticleCompositeShaderConsts.mSamplerColorSource->getSamplerRegister(), 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( mParticleCompositeShaderConsts.mSamplerEdgeSource->getSamplerRegister(), texObject );
- if(texObject)
- {
- ScreenSpace::RenderTargetParameters(texObject->getSize(), mEdgeTarget->getViewport(), rtParams);
- mParticleCompositeShaderConsts.mShaderConsts->setSafe( mParticleCompositeShaderConsts.mEdgeTargetParamsSC, rtParams );
- }
- else
- {
- AssertFatal(false, "No edge texture target defined, if you want to use mixed particle"
- "rendering, then make sure that the EdgeDetectPostEffect is enabled.");
- ri->systemState = PSS_AwaitingHighResDraw;
- return;
- }
- // 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;
- }
- }
- void RenderParticleMgr::renderParticle(ParticleRenderInst* ri, SceneRenderState* state)
- {
- // 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( mParticleShaderConsts.mSamplerDiffuse->getSamplerRegister(), ri->diffuseTex );
- // Set up the deferred texture.
- if ( mParticleShaderConsts.mDeferredTargetParamsSC->isValid() )
- {
- GFXTextureObject *texObject = mDeferredTarget ? mDeferredTarget->getTexture(0) : NULL;
- GFX->setTexture( mParticleShaderConsts.mSamplerDeferredTex->getSamplerRegister(), texObject );
- Point4F rtParams( 0.0f, 0.0f, 1.0f, 1.0f );
- if ( texObject )
- ScreenSpace::RenderTargetParameters(texObject->getSize(), mDeferredTarget->getViewport(), rtParams);
- mParticleShaderConsts.mShaderConsts->set( mParticleShaderConsts.mDeferredTargetParamsSC, rtParams );
- }
- GFX->setPrimitiveBuffer( *ri->primBuff );
- GFX->setVertexBuffer( *ri->vertBuff );
- GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, ri->count * 4, 0, ri->count * 2 );
- }
- bool RenderParticleMgr::_initShader()
- {
- ShaderData *shaderData = NULL;
- bool ret = true;
- // Need depth from pre-pass, so get the macros
- Vector<GFXShaderMacro> macros;
- if ( mDeferredTarget )
- mDeferredTarget->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.mDeferredTargetParamsSC = mParticleShader->getShaderConstHandle( "$deferredTargetParams" );
- //samplers
- mParticleShaderConsts.mSamplerDiffuse = mParticleShader->getShaderConstHandle("$diffuseMap");
- mParticleShaderConsts.mSamplerDeferredTex = mParticleShader->getShaderConstHandle("$deferredTex");
- mParticleShaderConsts.mSamplerParaboloidLightMap = mParticleShader->getShaderConstHandle("$paraboloidLightMap");
- }
- 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.mSamplerColorSource = mParticleCompositeShader->getShaderConstHandle( "$colorSource" );
- mParticleCompositeShaderConsts.mSamplerEdgeSource = mParticleCompositeShader->getShaderConstHandle( "$edgeSource" );
- mParticleCompositeShaderConsts.mEdgeTargetParamsSC = mParticleCompositeShader->getShaderConstHandle( "$edgeTargetParams" );
- mParticleCompositeShaderConsts.mOffscreenTargetParamsSC = mParticleCompositeShader->getShaderConstHandle( "$offscreenTargetParams" );
- }
- return ret;
- }
- void RenderParticleMgr::_onLMActivate( const char*, bool activate )
- {
- if ( activate )
- {
- RenderPassManager *rpm = getRenderPass();
- if ( !rpm )
- return;
- // Hunt for the pre-pass manager/target
- RenderDeferredMgr *deferredBin = NULL;
- for( U32 i = 0; i < rpm->getManagerCount(); i++ )
- {
- RenderBinManager *bin = rpm->getManager(i);
- if( bin->getRenderInstType() == RenderDeferredMgr::RIT_Deferred )
- {
- deferredBin = (RenderDeferredMgr*)bin;
- break;
- }
- }
- // If we found the deferred 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 = deferredBin && (deferredBin->getTargetChainLength() > 0);
- if(mOffscreenRenderEnabled)
- {
- rpm->removeManager(this);
- setRenderOrder( deferredBin->getRenderOrder() + 0.011f );
- rpm->addManager(this);
- }
- // Find the targets we use
- mDeferredTarget = NamedTexTarget::find( "deferred" );
- mEdgeTarget = NamedTexTarget::find( "edge" );
- // Setup the shader
- _initShader();
- if ( mScreenQuadVertBuff.isNull() )
- _initGFXResources();
- }
- else
- {
- mStencilClearSB = NULL;
- mScreenQuadPrimBuff = NULL;
- mScreenQuadVertBuff = NULL;
- }
- }
- 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();
- // Deferred 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();
- // Deferred 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 ( mMixedResBlocks[blendStyle].isValid() )
- return mMixedResBlocks[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();
- // Deferred sampler
- d.samplers[1] = GFXSamplerStateDesc::getClampPoint();
- mMixedResBlocks[blendStyle] = GFX->createStateBlock(d);
- return mMixedResBlocks[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;
- }
|