Torque3D Documentation / _generateds / renderParticleMgr.cpp

renderParticleMgr.cpp

Engine/source/renderInstance/renderParticleMgr.cpp

More...

Public Functions

ConsoleDocClass(RenderParticleMgr , "@brief A <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> bin which renders particle <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">geometry.\n\n</a>" "This <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> bin gathers particle <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> instances, sorts , and renders them. " "It is currently used by <a href="/coding/class/classparticleemitter/">ParticleEmitter</a> and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">LightFlareData.\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">RenderBin\n</a>" )
GFXImplementVertexFormat(CompositeQuadVert )

Detailed Description

Public Variables

const Point4F cubePoints [9]
const bool RenderToParticleTarget 
const bool RenderToSingleTarget 

Public Functions

ConsoleDocClass(RenderParticleMgr , "@brief A <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> bin which renders particle <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">geometry.\n\n</a>" "This <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> bin gathers particle <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> instances, sorts , and renders them. " "It is currently used by <a href="/coding/class/classparticleemitter/">ParticleEmitter</a> and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">LightFlareData.\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">RenderBin\n</a>" )

GFXImplementVertexFormat(CompositeQuadVert )

IMPLEMENT_CONOBJECT(RenderParticleMgr )

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "renderInstance/renderParticleMgr.h"
 26#include "renderInstance/renderDeferredMgr.h"
 27#include "scene/sceneManager.h"
 28#include "scene/sceneObject.h"
 29#include "scene/sceneRenderState.h"
 30#include "gfx/gfxPrimitiveBuffer.h"
 31#include "gfx/gfxTransformSaver.h"
 32#include "gfx/gfxDebugEvent.h"
 33#include "materials/shaderData.h"
 34#include "materials/sceneData.h"
 35#include "materials/matInstance.h"
 36#include "gfx/util/screenspace.h"
 37#include "gfx/gfxDrawUtil.h"
 38#include "collision/clippedPolyList.h"
 39
 40static const Point4F cubePoints[9] = 
 41{
 42   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),
 43   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)
 44};
 45
 46GFXImplementVertexFormat( CompositeQuadVert )
 47{
 48   addElement( "COLOR", GFXDeclType_Color );
 49}
 50
 51IMPLEMENT_CONOBJECT(RenderParticleMgr);
 52
 53
 54ConsoleDocClass( RenderParticleMgr, 
 55   "@brief A render bin which renders particle geometry.\n\n"
 56   "This render bin gathers particle render instances, sorts, and renders them. "
 57   "It is currently used by ParticleEmitter and LightFlareData.\n\n"
 58   "@ingroup RenderBin\n" );
 59
 60
 61const RenderInstType RenderParticleMgr::RIT_Particles("ParticleSystem");
 62
 63// TODO: Replace these once they are supported via options
 64const bool RenderToParticleTarget = true;
 65const bool RenderToSingleTarget = true;
 66
 67RenderParticleMgr::RenderParticleMgr()
 68:  Parent(  RenderParticleMgr::RIT_Particles, 
 69            1.0f, 
 70            1.0f, 
 71            GFXFormatR8G8B8A8, 
 72            Point2I( Parent::DefaultTargetSize, Parent::DefaultTargetSize), 
 73            RenderToParticleTarget ? Parent::DefaultTargetChainLength : 0 ),
 74            mParticleShader( NULL )
 75{
 76   // Render particles at 1/4 resolution
 77   mTargetSizeType = WindowSizeScaled;
 78   mTargetScale.set(0.5f, 0.5f);
 79
 80   // We use the target chain like a texture pool, not like a swap chain
 81   if(!RenderToSingleTarget)
 82      setTargetChainLength(5);
 83   else
 84      mOffscreenSystems.setSize(1);
 85   
 86   notifyType( RenderPassManager::RIT_Particle );
 87   LightManager::smActivateSignal.notify( this, &RenderParticleMgr::_onLMActivate );
 88}
 89
 90RenderParticleMgr::~RenderParticleMgr()
 91{
 92   LightManager::smActivateSignal.remove( this, &RenderParticleMgr::_onLMActivate );
 93}
 94
 95void RenderParticleMgr::setTargetChainLength( const U32 chainLength )
 96{
 97   Parent::setTargetChainLength(chainLength);
 98
 99   if(!RenderToSingleTarget)
100      mOffscreenSystems.setSize(chainLength);
101}
102
103void RenderParticleMgr::addElement( RenderInst *inst )
104{
105   ParticleRenderInst *pri = reinterpret_cast<ParticleRenderInst *>(inst);
106
107   // If this system isn't waiting for an offscreen draw, skip it
108   if( pri->systemState != PSS_AwaitingOffscreenDraw )
109      return;
110
111   // If offscreen rendering isn't enabled, set to high-res, and skip
112   if(!mOffscreenRenderEnabled)
113   {
114      pri->systemState = PSS_AwaitingHighResDraw;
115      return;
116   }
117
118   // Assign a target index
119   RectF screenRect;
120   S32 chainIndex = -1;
121   if(RenderToSingleTarget)
122   {
123      pri->targetIndex = 0;
124      screenRect.point.set(-1.0f, -1.0f);
125      screenRect.extent.set(2.0f, 2.0f);
126
127      mElementList.setSize(1);
128   }
129   else
130   {
131
132      // If we can't fit this into the offscreen systems, skip it, it will render
133      // high resolution
134      //
135      // TODO: Improve this once we are grouping systems
136      if( mTargetChainIdx == OffscreenPoolSize )
137         return;
138
139      // Transform bounding box into screen space
140      const static PlaneF planes[] = {
141         PlaneF(Point3F( 1.0f,  0.0f,  0.0f), Point3F(-1.0f,  0.0f,  0.0f)),
142         PlaneF(Point3F(-1.0f,  0.0f,  0.0f), Point3F( 1.0f,  0.0f,  0.0f)),
143
144         PlaneF(Point3F( 0.0f,  1.0f,  0.0f), Point3F( 0.0f, -1.0f,  0.0f)),
145         PlaneF(Point3F( 0.0f, -1.0f,  0.0f), Point3F( 0.0f,  1.0f,  0.0f)),
146
147         PlaneF(Point3F( 0.0f,  0.0f,  0.0f), Point3F( 0.0f,  0.0f,  1.0f)),
148         PlaneF(Point3F( 0.0f,  0.0f,  1.0f), Point3F( 0.0f,  0.0f, -1.0f)),
149      };
150      const static dsize_t numPlanes = sizeof(planes) / sizeof(PlaneF);
151
152      // Set up a clipper
153      ClippedPolyList screenClipper;
154      screenClipper.setBaseTransform(MatrixF::Identity);
155      screenClipper.setTransform(&MatrixF::Identity, Point3F::One);
156      TORQUE_UNUSED(numPlanes);
157
158      Point4F tempPt(0.0f, 0.0f, 0.0f, 1.0f);
159      pri->bbModelViewProj->mul(tempPt);
160      tempPt = tempPt / tempPt.w;
161
162      for(S32 i = 0; i < 1; i++)
163      {
164         screenClipper.mPlaneList.push_back(planes[i]);
165         screenClipper.mPlaneList.last() += tempPt.asPoint3F();
166      }
167
168      Box3F screenSpaceBoundingBox;
169      screenSpaceBoundingBox.minExtents = Point3F::Zero;
170      screenSpaceBoundingBox.maxExtents = Point3F::Zero;
171
172      for(S32 i = 0; i < 8; i++)
173      {
174         tempPt = cubePoints[i];
175         pri->bbModelViewProj->mul(tempPt);
176         tempPt = tempPt / tempPt.w;
177
178         screenSpaceBoundingBox.maxExtents.setMax(tempPt.asPoint3F());
179         screenSpaceBoundingBox.minExtents.setMin(tempPt.asPoint3F());
180      }
181
182      screenClipper.addBox(screenSpaceBoundingBox);
183
184      screenClipper.cullUnusedVerts();
185      //screenClipper.triangulate();
186
187      // Empty vertex list? Skip!
188      if(screenClipper.mVertexList.empty())
189      {
190         pri->systemState = PSS_AwaitingHighResDraw;
191         return;
192      }
193
194      Point2F minExtents(0.0f, 0.0f), maxExtents(0.0f, 0.0f);
195      for(ClippedPolyList::VertexList::const_iterator itr = screenClipper.mVertexList.begin();
196         itr != screenClipper.mVertexList.end(); itr++)
197      {
198         minExtents.x = getMin(minExtents.x, (*itr).point.x);
199         minExtents.y = getMin(minExtents.y, (*itr).point.y);
200         maxExtents.x = getMax(maxExtents.x, (*itr).point.x);
201         maxExtents.y = getMax(maxExtents.y, (*itr).point.y);
202      }
203      screenRect.set( minExtents, maxExtents - minExtents );
204
205      // Check the size of the system on screen. If it is small, it won't
206      // be eating fillrate anyway, so just draw it high-resolution.
207      // The value it checks against is one I found from experimentation, 
208      // not anything really meaningful.
209      if( screenRect.extent.x < 0.35f || screenRect.extent.y < 0.35f )
210      {
211         pri->systemState = PSS_AwaitingHighResDraw;
212         return;
213      }
214
215      pri->targetIndex = mTargetChainIdx;
216      chainIndex = mTargetChainIdx;
217      mTargetChainIdx++;
218
219      // TODO: Rewrite this...
220      mElementList.increment();
221   }
222
223   // Set up system entry
224   OffscreenSystemEntry &systemEntry = mOffscreenSystems[pri->targetIndex];
225
226   systemEntry.screenRect = screenRect;
227   systemEntry.targetChainIdx = chainIndex;
228   systemEntry.pInstances.push_back(pri);
229
230   // TODO: Rewrite this block
231   // Assign proper values to sort element
232   MainSortElem& elem = mElementList.last();
233   elem.inst = reinterpret_cast<RenderInst *>(&systemEntry);
234   elem.key = *((U32*)&inst->sortDistSq);
235   elem.key2 = inst->defaultKey;
236
237   // TODO: [re]move this block
238   systemEntry.clipMatrix.identity();
239   if(!RenderToSingleTarget)
240   {
241      // Construct crop matrix
242      Point3F scale( getMax(2.0f / systemEntry.screenRect.extent.x, 1.0f), 
243         getMax(2.0f / systemEntry.screenRect.extent.y, 1.0f),
244         1.0f);
245
246      Point3F offset((systemEntry.screenRect.point.x + systemEntry.screenRect.extent.x * 0.5f) * scale.x,
247         (systemEntry.screenRect.point.y + systemEntry.screenRect.extent.y * 0.5f) * scale.y,
248         0.0f);
249
250      //systemEntry.clipMatrix.scale(scale);
251      //systemEntry.clipMatrix.setPosition(-offset);
252   }
253
254   // The translucent mgr will also pick up particles, and will call this class
255   // to composiste the particle systems back into the main scene
256}
257
258void RenderParticleMgr::sort()
259{
260   Parent::sort();
261}
262
263void RenderParticleMgr::clear()
264{
265   Parent::clear();
266
267   // Reset pool index
268   if(!RenderToSingleTarget)
269      mTargetChainIdx = 0;
270
271   for(Vector<OffscreenSystemEntry>::iterator itr = mOffscreenSystems.begin();
272      itr != mOffscreenSystems.end(); itr++)
273   {
274      (*itr).drawnThisFrame = false;
275      (*itr).pInstances.clear();
276   }
277}
278
279void RenderParticleMgr::render( SceneRenderState *state )
280{
281   PROFILE_SCOPE(RenderParticleMgr_render);
282
283   // Early out if nothing to draw
284   if( !mElementList.size() || 
285      (!mParticleShader && !_initShader()) )
286      return;
287
288   GFXDEBUGEVENT_SCOPE(RenderParticleMgr_Render, ColorI::RED);
289
290   GFXTransformSaver saver;
291
292   // Iterate render instances
293   for( Vector<MainSortElem>::const_iterator itr = mElementList.begin();
294      itr != mElementList.end(); itr++ )
295   {
296      OffscreenSystemEntry &systemEntry = *reinterpret_cast<OffscreenSystemEntry *>(itr->inst);
297
298      // Setup target
299      // NOTE: If you are using this on the Xbox360 with Basic Lighting,
300      // you are going to have to mess with either the render order, or 
301      // you are going to have to make this a 'preserve' draw
302      if(!RenderToSingleTarget)
303         mTargetChainIdx = systemEntry.targetChainIdx;
304      _onPreRender(state);
305
306      // Clear offscreen target
307      GFX->clear(GFXClearTarget, ColorI::ZERO, 1.0f, 0);
308
309      // Draw offscreen systems
310      for( Vector<ParticleRenderInst *>::const_iterator itr2 = systemEntry.pInstances.begin();
311         itr2 != systemEntry.pInstances.end(); itr2++ )
312      {
313         ParticleRenderInst *ri = *itr2;
314
315         // Sanity check
316         if(ri->systemState == PSS_AwaitingOffscreenDraw)
317         {
318            // If this is not a diffuse path, flag the system appropriately, and skip
319            // the offscreen processing.
320            if( !state->isDiffusePass() )
321            {
322               if(state->isReflectPass())
323                  ri->systemState = PSS_AwaitingHighResDraw;
324               else
325                  ri->systemState = PSS_DrawComplete;
326               continue;
327            }
328
329            // Draw system offscreen
330            renderInstance(ri, state);
331         }
332      }
333
334      // Cleanup
335      _onPostRender();
336   }
337}
338
339void RenderParticleMgr::_initGFXResources()
340{
341   // Screen quad
342   U16 prims [] = {
343      0, 1, 2, 3,
344   };
345   mScreenQuadPrimBuff.immutable(GFX, 4, 2, prims);
346
347   mScreenQuadVertBuff.set(GFX, 4, GFXBufferTypeStatic);
348   CompositeQuadVert *verts = mScreenQuadVertBuff.lock();
349   (*verts++).uvCoord.set(0, 0, 0, 0);
350   (*verts++).uvCoord.set(0, 255, 0, 0);
351   (*verts++).uvCoord.set(255, 0, 0, 0);
352   (*verts++).uvCoord.set(255, 255, 0, 0);
353   mScreenQuadVertBuff.unlock();
354
355   // Stencil setup state block
356   GFXStateBlockDesc d;
357
358   d.setCullMode(GFXCullNone);
359   d.setColorWrites(false, false, false, false);
360   d.setBlend(false);
361   d.setZReadWrite(false, false);
362
363   d.stencilDefined = true;
364   d.stencilEnable = true;
365   d.stencilMask = RenderParticleMgr::ParticleSystemStencilMask;
366   d.stencilWriteMask = RenderParticleMgr::ParticleSystemStencilMask;
367   d.stencilFunc = GFXCmpAlways;
368   d.stencilPassOp = GFXStencilOpZero;
369
370   mStencilClearSB = GFX->createStateBlock(d);
371}
372
373void RenderParticleMgr::renderInstance(ParticleRenderInst *ri, SceneRenderState *state)
374{
375   // Draw system path, or draw composite path
376   if(ri->systemState == PSS_DrawComplete)
377      return;
378   
379   if(ri->systemState != PSS_AwaitingCompositeDraw)
380   {
381      // Set proper stateblock, and update state
382      if(ri->systemState == PSS_AwaitingOffscreenDraw)
383      {
384         GFX->setStateBlock( _getOffscreenStateBlock(ri) );
385         ri->systemState = PSS_AwaitingCompositeDraw;
386         mParticleShaderConsts.mShaderConsts->setSafe( mParticleShaderConsts.mModelViewProjSC, 
387            *ri->modelViewProj * mOffscreenSystems[ri->targetIndex].clipMatrix );
388      }
389      else
390      {
391         if(ri->systemState == PSS_AwaitingMixedResDraw)
392            GFX->setStateBlock( _getMixedResStateBlock( ri ) );
393         else
394            GFX->setStateBlock( _getHighResStateBlock( ri ) );
395         ri->systemState = PSS_DrawComplete;
396         mParticleShaderConsts.mShaderConsts->setSafe( mParticleShaderConsts.mModelViewProjSC, *ri->modelViewProj );
397      }
398
399      renderParticle(ri, state);
400   }
401   else if(ri->systemState == PSS_AwaitingCompositeDraw)
402   {
403      OffscreenSystemEntry &systemEntry = mOffscreenSystems[ri->targetIndex];
404
405      // If this system has already been composited this frame, skip it
406      if(systemEntry.drawnThisFrame)
407         return;
408
409      // Non-target render, composite the particle system back into the scene
410      GFX->setVertexBuffer(mScreenQuadVertBuff);
411      GFX->setPrimitiveBuffer(mScreenQuadPrimBuff);
412
413
414      // Set up shader constants
415      mParticleCompositeShaderConsts.mShaderConsts->setSafe( mParticleCompositeShaderConsts.mScreenRect, *((Point4F *)&systemEntry.screenRect) );
416
417      // Set offscreen texture
418      Point4F rtParams;
419      GFXTextureObject *particleSource = mNamedTarget.getTexture();
420      GFX->setTexture( mParticleCompositeShaderConsts.mSamplerColorSource->getSamplerRegister(), particleSource );
421      if(particleSource)
422      {
423         ScreenSpace::RenderTargetParameters(particleSource->getSize(), mNamedTarget.getViewport(), rtParams);
424         mParticleCompositeShaderConsts.mShaderConsts->setSafe( mParticleCompositeShaderConsts.mOffscreenTargetParamsSC, rtParams );
425      }
426
427      // And edges
428      GFXTextureObject *texObject = mEdgeTarget ? mEdgeTarget->getTexture() : NULL;
429      GFX->setTexture( mParticleCompositeShaderConsts.mSamplerEdgeSource->getSamplerRegister(), texObject );
430      if(texObject)
431      {
432         ScreenSpace::RenderTargetParameters(texObject->getSize(), mEdgeTarget->getViewport(), rtParams);
433         mParticleCompositeShaderConsts.mShaderConsts->setSafe( mParticleCompositeShaderConsts.mEdgeTargetParamsSC, rtParams );
434      }
435      else
436      {
437         AssertFatal(false, "No edge texture target defined, if you want to use mixed particle"
438            "rendering, then make sure that the EdgeDetectPostEffect is enabled.");
439         ri->systemState = PSS_AwaitingHighResDraw;
440         return;
441      }
442
443      // Set shader and constant buffer
444      GFX->setShader( mParticleCompositeShader );
445      GFX->setShaderConstBuffer( mParticleCompositeShaderConsts.mShaderConsts );
446
447      // Draw to stencil buffer only to clear the stencil values
448      GFX->setStateBlock( mStencilClearSB );
449      GFX->drawIndexedPrimitive( GFXTriangleStrip, 0, 0, 4, 0, 2 );
450
451      // composite particle system back into the scene
452      GFX->setStateBlock( _getCompositeStateBlock(ri) );
453      GFX->drawIndexedPrimitive( GFXTriangleStrip, 0, 0, 4, 0, 2 );
454
455      // Re-draw the particle systems in high-res, but only to the stenciled
456      // areas which were enabled via the edge buffer
457      for( Vector<ParticleRenderInst *>::const_iterator itr = systemEntry.pInstances.begin();
458         itr != systemEntry.pInstances.end(); itr++ )
459      {
460         ParticleRenderInst *pri = *itr;
461         if(pri->systemState == PSS_AwaitingCompositeDraw)
462         {
463            pri->systemState = PSS_AwaitingMixedResDraw;
464            renderInstance(pri, state);
465         }
466      }
467
468      // Mark this system as having been composited this frame
469      systemEntry.drawnThisFrame = true;
470   }
471}
472
473void RenderParticleMgr::renderParticle(ParticleRenderInst* ri, SceneRenderState* state)
474{
475   // We want to turn everything into variation on a pre-multiplied alpha blend
476   F32 alphaFactor = 0.0f, alphaScale = 1.0f;
477   switch(ri->blendStyle)
478   {
479      // SrcAlpha, InvSrcAlpha
480   case ParticleRenderInst::BlendNormal:
481      alphaFactor = 1.0f;
482      break;
483
484      // SrcAlpha, One
485   case ParticleRenderInst::BlendAdditive:
486      alphaFactor = 1.0f;
487      alphaScale = 0.0f;
488      break;
489
490      // SrcColor, One
491   case ParticleRenderInst::BlendGreyscale:
492      alphaFactor = -1.0f;
493      alphaScale = 0.0f;
494      break;
495   }
496
497   mParticleShaderConsts.mShaderConsts->setSafe( mParticleShaderConsts.mAlphaFactorSC, alphaFactor );
498   mParticleShaderConsts.mShaderConsts->setSafe( mParticleShaderConsts.mAlphaScaleSC, alphaScale );
499
500   mParticleShaderConsts.mShaderConsts->setSafe( mParticleShaderConsts.mFSModelViewProjSC, *ri->modelViewProj  );
501   mParticleShaderConsts.mShaderConsts->setSafe( mParticleShaderConsts.mOneOverFarSC, 1.0f / state->getFarPlane() );     
502
503   if ( mParticleShaderConsts.mOneOverSoftnessSC->isValid() )
504   {
505      F32 oneOverSoftness = 1.0f;
506      if ( ri->softnessDistance > 0.0f )
507         oneOverSoftness = 1.0f / ( ri->softnessDistance / state->getFarPlane() );
508      mParticleShaderConsts.mShaderConsts->set( mParticleShaderConsts.mOneOverSoftnessSC, oneOverSoftness );
509   }
510
511   GFX->setShader( mParticleShader );
512   GFX->setShaderConstBuffer( mParticleShaderConsts.mShaderConsts );
513
514      GFX->setTexture( mParticleShaderConsts.mSamplerDiffuse->getSamplerRegister(), ri->diffuseTex );
515
516   // Set up the deferred texture.
517   if ( mParticleShaderConsts.mDeferredTargetParamsSC->isValid() )
518   {
519      GFXTextureObject *texObject = mDeferredTarget ? mDeferredTarget->getTexture(0) : NULL;
520         GFX->setTexture( mParticleShaderConsts.mSamplerDeferredTex->getSamplerRegister(), texObject );
521
522      Point4F rtParams( 0.0f, 0.0f, 1.0f, 1.0f );
523      if ( texObject )
524         ScreenSpace::RenderTargetParameters(texObject->getSize(), mDeferredTarget->getViewport(), rtParams);
525
526      mParticleShaderConsts.mShaderConsts->set( mParticleShaderConsts.mDeferredTargetParamsSC, rtParams );
527   }
528
529   GFX->setPrimitiveBuffer( *ri->primBuff );
530   GFX->setVertexBuffer( *ri->vertBuff );
531
532   GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, ri->count * 4, 0, ri->count * 2 );
533}
534
535bool RenderParticleMgr::_initShader()
536{
537   ShaderData *shaderData = NULL;
538   bool ret = true;
539
540   // Need depth from pre-pass, so get the macros
541   Vector<GFXShaderMacro> macros;
542   if ( mDeferredTarget )
543      mDeferredTarget->getShaderMacros( &macros );
544
545   // Create particle shader
546   if ( !Sim::findObject( "ParticlesShaderData", shaderData ) || !shaderData )
547      Con::warnf( "RenderParticleMgr::_initShader - failed to locate shader ParticlesShaderData!" );
548   if( shaderData )
549      mParticleShader = shaderData->getShader( macros );
550   ret &= (mParticleShader != NULL);
551
552   if ( mParticleShader )
553   {
554      mParticleShaderConsts.mShaderConsts = mParticleShader->allocConstBuffer();
555      mParticleShaderConsts.mModelViewProjSC = mParticleShader->getShaderConstHandle( "$modelViewProj" );
556      mParticleShaderConsts.mOneOverFarSC = mParticleShader->getShaderConstHandle( "$oneOverFar" );
557      mParticleShaderConsts.mOneOverSoftnessSC = mParticleShader->getShaderConstHandle( "$oneOverSoftness" );
558      mParticleShaderConsts.mAlphaFactorSC = mParticleShader->getShaderConstHandle( "$alphaFactor" );
559      mParticleShaderConsts.mAlphaScaleSC = mParticleShader->getShaderConstHandle( "$alphaScale" );
560      mParticleShaderConsts.mFSModelViewProjSC = mParticleShader->getShaderConstHandle( "$fsModelViewProj" );
561      mParticleShaderConsts.mDeferredTargetParamsSC = mParticleShader->getShaderConstHandle( "$deferredTargetParams" );
562
563      //samplers
564      mParticleShaderConsts.mSamplerDiffuse = mParticleShader->getShaderConstHandle("$diffuseMap");
565      mParticleShaderConsts.mSamplerDeferredTex = mParticleShader->getShaderConstHandle("$deferredTex");
566      mParticleShaderConsts.mSamplerParaboloidLightMap = mParticleShader->getShaderConstHandle("$paraboloidLightMap");
567   }
568
569   shaderData = NULL;
570
571   // Create off screen particle composite shader
572   if ( !Sim::findObject( "OffscreenParticleCompositeShaderData", shaderData ) || !shaderData )
573      Con::warnf( "RenderParticleMgr::_initShader - failed to locate shader OffscreenParticleCompositeShaderData!" );
574   if( shaderData )
575      mParticleCompositeShader = shaderData->getShader( macros );
576   ret &= (mParticleCompositeShader != NULL);
577
578   if ( mParticleCompositeShader )
579   {
580      mParticleCompositeShaderConsts.mShaderConsts = mParticleCompositeShader->allocConstBuffer();
581      mParticleCompositeShaderConsts.mScreenRect = mParticleCompositeShader->getShaderConstHandle( "$screenRect" );
582      mParticleCompositeShaderConsts.mSamplerColorSource = mParticleCompositeShader->getShaderConstHandle( "$colorSource" );
583      mParticleCompositeShaderConsts.mSamplerEdgeSource = mParticleCompositeShader->getShaderConstHandle( "$edgeSource" );
584      mParticleCompositeShaderConsts.mEdgeTargetParamsSC = mParticleCompositeShader->getShaderConstHandle( "$edgeTargetParams" );
585      mParticleCompositeShaderConsts.mOffscreenTargetParamsSC = mParticleCompositeShader->getShaderConstHandle( "$offscreenTargetParams" );
586   }
587
588   return ret;
589}
590
591void RenderParticleMgr::_onLMActivate( const char*, bool activate )
592{
593   if ( activate )
594   {
595      RenderPassManager *rpm = getRenderPass();
596      if ( !rpm )
597         return;
598
599      // Hunt for the pre-pass manager/target
600      RenderDeferredMgr *deferredBin = NULL;
601      for( U32 i = 0; i < rpm->getManagerCount(); i++ )
602      {
603         RenderBinManager *bin = rpm->getManager(i);
604         if( bin->getRenderInstType() == RenderDeferredMgr::RIT_Deferred )
605         {
606            deferredBin = (RenderDeferredMgr*)bin;
607            break;
608         }
609      }
610
611      // If we found the deferred bin, set this bin to render very shortly afterwards
612      // and re-add this render-manager. If there is no pre-pass bin, or it doesn't
613      // have a depth-texture, we can't render offscreen.
614      mOffscreenRenderEnabled = deferredBin && (deferredBin->getTargetChainLength() > 0);
615      if(mOffscreenRenderEnabled)
616      {
617         rpm->removeManager(this);
618         setRenderOrder( deferredBin->getRenderOrder() + 0.011f );
619         rpm->addManager(this);
620      }
621
622      // Find the targets we use
623      mDeferredTarget = NamedTexTarget::find( "deferred" );
624      mEdgeTarget = NamedTexTarget::find( "edge" );
625
626      // Setup the shader
627      _initShader();
628
629      if ( mScreenQuadVertBuff.isNull() )
630         _initGFXResources();
631   } 
632   else
633   {
634      mStencilClearSB = NULL;
635      mScreenQuadPrimBuff = NULL;
636      mScreenQuadVertBuff = NULL;
637   }
638}
639
640GFXStateBlockRef RenderParticleMgr::_getOffscreenStateBlock(ParticleRenderInst *ri)
641{
642   const U8 blendStyle = ri->blendStyle;
643   if ( mOffscreenBlocks[blendStyle].isValid() )
644      return mOffscreenBlocks[blendStyle];
645
646   GFXStateBlockDesc d;
647
648   d.setCullMode(GFXCullNone);
649   d.setZReadWrite(false, false); // No zreads or writes, all z-testing is done in the pixel shader
650
651   // Draw everything either subtractive, or using a variation on premultiplied
652   // alpha
653   if(blendStyle == ParticleRenderInst::BlendSubtractive)
654      d.setBlend(true, GFXBlendZero, GFXBlendInvSrcColor);
655   else
656      d.setBlend(true, GFXBlendOne, GFXBlendInvSrcAlpha);
657
658   // Offscreen target, we need to add alpha.
659   d.separateAlphaBlendDefined = true;
660   d.separateAlphaBlendEnable = true;
661   d.separateAlphaBlendSrc = GFXBlendOne;
662   d.separateAlphaBlendDest = GFXBlendInvSrcAlpha;
663
664   d.samplersDefined = true;
665
666   // Diffuse texture sampler
667   d.samplers[0] = GFXSamplerStateDesc::getClampLinear();
668
669   // Deferred sampler
670   d.samplers[1] = GFXSamplerStateDesc::getClampPoint();
671
672   mOffscreenBlocks[blendStyle] = GFX->createStateBlock(d);
673   return mOffscreenBlocks[blendStyle];
674}
675
676GFXStateBlockRef RenderParticleMgr::_getHighResStateBlock(ParticleRenderInst *ri)
677{
678   const U8 blendStyle = ri->blendStyle;
679   if ( mHighResBlocks[blendStyle].isValid() )
680      return mHighResBlocks[blendStyle];
681
682   GFXStateBlockDesc d;
683
684   d.setZReadWrite(true, false);
685   d.setCullMode(GFXCullNone);
686
687   // Draw everything either subtractive, or using a variation on premultiplied
688   // alpha
689   if(blendStyle == ParticleRenderInst::BlendSubtractive)
690      d.setBlend(true, GFXBlendZero, GFXBlendInvSrcColor);
691   else
692      d.setBlend(true, GFXBlendOne, GFXBlendInvSrcAlpha);
693
694   d.samplersDefined = true;
695
696   // Diffuse texture sampler
697   d.samplers[0] = GFXSamplerStateDesc::getClampLinear();
698
699   // Deferred sampler
700   d.samplers[1] = GFXSamplerStateDesc::getClampPoint();
701
702   mHighResBlocks[blendStyle] = GFX->createStateBlock(d);
703   return mHighResBlocks[blendStyle];
704}
705
706GFXStateBlockRef RenderParticleMgr::_getMixedResStateBlock(ParticleRenderInst *ri)
707{
708   const U8 blendStyle = ri->blendStyle;
709   if ( mMixedResBlocks[blendStyle].isValid() )
710      return mMixedResBlocks[blendStyle];
711
712   GFXStateBlockDesc d;
713
714   d.setZReadWrite(true, false);
715   d.setCullMode(GFXCullNone);
716
717   /*
718   // Old blend styles...
719   switch (blendStyle)
720   {
721   case ParticleRenderInst::BlendNormal:
722      d.blendSrc = GFXBlendSrcAlpha;
723      d.blendDest = GFXBlendInvSrcAlpha;
724      break;
725
726   case ParticleRenderInst::BlendSubtractive:
727      d.blendSrc = GFXBlendZero;
728      d.blendDest = GFXBlendInvSrcColor;
729      break;
730
731   case ParticleRenderInst::BlendPremultAlpha:
732      d.blendSrc = GFXBlendOne;
733      d.blendDest = GFXBlendInvSrcAlpha;
734      break;
735
736      // Default to additive blend mode
737   case ParticleRenderInst::BlendAdditive:
738   case ParticleRenderInst::BlendUndefined:
739   default:
740      d.blendSrc = GFXBlendSrcAlpha;
741      d.blendDest = GFXBlendOne;
742      break;
743   }
744   */
745
746   // Draw everything either subtractive, or using a variation on premultiplied
747   // alpha
748   if(blendStyle == ParticleRenderInst::BlendSubtractive)
749      d.setBlend(true, GFXBlendZero, GFXBlendInvSrcColor);
750   else
751      d.setBlend(true, GFXBlendOne, GFXBlendInvSrcAlpha);
752
753   // Draw to anything but the stencil ref value (the edges)
754   d.stencilDefined = true;
755   d.stencilEnable = true;
756   d.stencilRef = RenderParticleMgr::HighResStencilRef;
757   d.stencilMask = RenderParticleMgr::ParticleSystemStencilMask;
758   d.stencilPassOp = GFXStencilOpKeep;
759   d.stencilFailOp = GFXStencilOpKeep;
760   d.stencilZFailOp = GFXStencilOpKeep;
761   d.stencilFunc = GFXCmpNotEqual;
762
763   d.samplersDefined = true;
764
765   // Diffuse texture sampler
766   d.samplers[0] = GFXSamplerStateDesc::getClampLinear();
767
768   // Deferred sampler
769   d.samplers[1] = GFXSamplerStateDesc::getClampPoint();
770
771   mMixedResBlocks[blendStyle] = GFX->createStateBlock(d);
772   return mMixedResBlocks[blendStyle];
773}
774
775GFXStateBlockRef RenderParticleMgr::_getCompositeStateBlock(ParticleRenderInst *ri)
776{
777   const U8 blendStyle = ri->blendStyle;
778   if ( mBackbufferBlocks[blendStyle].isValid() )
779      return mBackbufferBlocks[blendStyle];
780
781   GFXStateBlockDesc d;
782
783   // This is a billboard
784   d.setCullMode(GFXCullNone);
785   d.setZReadWrite(false, false);
786
787   // When we re-composite the particles, it is always either a pre-mult alpha
788   // blend, or a subtractive blend!
789   if(blendStyle == ParticleRenderInst::BlendSubtractive)
790      d.setBlend(true, GFXBlendZero, GFXBlendInvSrcColor);
791   else
792      d.setBlend(true, GFXBlendOne, GFXBlendInvSrcAlpha);
793
794   // All areas which are not along the edges of geometry where the particle system
795   // is being drawn get assigned a stencil ref value as the system is composited
796   // back into the scene. The high-res stateblock uses this value as a mask, and
797   // draws only in areas which are NOT this ref value. This causes high resolution
798   // draws to ONLY the edge areas.
799   d.stencilDefined = true;
800   d.stencilEnable = true;
801   d.stencilRef = RenderParticleMgr::HighResStencilRef; 
802   d.stencilWriteMask = RenderParticleMgr::ParticleSystemStencilMask;
803   d.stencilMask = RenderParticleMgr::ParticleSystemStencilMask;
804   d.stencilPassOp = GFXStencilOpReplace;
805   d.stencilFunc = GFXCmpGreater;
806
807   // Diffuse texture sampler and 
808   d.samplersDefined = true;
809   d.samplers[0] = GFXSamplerStateDesc::getClampLinear();
810   d.samplers[1] = GFXSamplerStateDesc::getClampLinear();
811
812   mBackbufferBlocks[blendStyle] = GFX->createStateBlock(d);
813   return mBackbufferBlocks[blendStyle];
814}
815
816bool RenderParticleMgr::_handleGFXEvent( GFXDevice::GFXDeviceEventType event )
817{
818   if(RenderToSingleTarget)
819      return Parent::_handleGFXEvent( event );
820
821   // Do nothing. This render manager uses its target chain as a pool of targets.
822   return true;
823}
824