diff --git a/Engine/source/T3D/fx/particleEmitter.cpp b/Engine/source/T3D/fx/particleEmitter.cpp index b40148cea..99e19294a 100644 --- a/Engine/source/T3D/fx/particleEmitter.cpp +++ b/Engine/source/T3D/fx/particleEmitter.cpp @@ -145,6 +145,7 @@ ParticleEmitterData::ParticleEmitterData() blendStyle = ParticleRenderInst::BlendUndefined; sortParticles = false; renderReflection = true; + glow = false; reverseOrder = false; textureName = 0; textureHandle = 0; @@ -289,6 +290,9 @@ void ParticleEmitterData::initPersistFields() addField( "renderReflection", TYPEID< bool >(), Offset(renderReflection, ParticleEmitterData), "Controls whether particles are rendered onto reflective surfaces like water." ); + addField("glow", TYPEID< bool >(), Offset(glow, ParticleEmitterData), + "If true, the particles are rendered to the glow buffer as well."); + //@} endGroup( "ParticleEmitterData" ); @@ -356,6 +360,7 @@ void ParticleEmitterData::packData(BitStream* stream) } stream->writeFlag(highResOnly); stream->writeFlag(renderReflection); + stream->writeFlag(glow); stream->writeInt( blendStyle, 4 ); } @@ -418,6 +423,7 @@ void ParticleEmitterData::unpackData(BitStream* stream) } highResOnly = stream->readFlag(); renderReflection = stream->readFlag(); + glow = stream->readFlag(); blendStyle = stream->readInt( 4 ); } @@ -909,6 +915,8 @@ void ParticleEmitter::prepRenderImage(SceneRenderState* state) ri->blendStyle = mDataBlock->blendStyle; + ri->glow = mDataBlock->glow; + // use first particle's texture unless there is an emitter texture to override it if (mDataBlock->textureHandle) ri->diffuseTex = &*(mDataBlock->textureHandle); diff --git a/Engine/source/T3D/fx/particleEmitter.h b/Engine/source/T3D/fx/particleEmitter.h index 36d486f47..7e369ad26 100644 --- a/Engine/source/T3D/fx/particleEmitter.h +++ b/Engine/source/T3D/fx/particleEmitter.h @@ -114,6 +114,7 @@ class ParticleEmitterData : public GameBaseData GFXTexHandle textureHandle; ///< Emitter texture handle from txrName bool highResOnly; ///< This particle system should not use the mixed-resolution particle rendering bool renderReflection; ///< Enables this emitter to render into reflection passes. + bool glow; ///< Renders this emitter into the glow buffer. bool reload(); }; diff --git a/Engine/source/renderInstance/renderGlowMgr.cpp b/Engine/source/renderInstance/renderGlowMgr.cpp index e3801e85e..3ad9587ce 100644 --- a/Engine/source/renderInstance/renderGlowMgr.cpp +++ b/Engine/source/renderInstance/renderGlowMgr.cpp @@ -22,6 +22,7 @@ #include "platform/platform.h" #include "renderInstance/renderGlowMgr.h" +#include "renderInstance/renderParticleMgr.h" #include "scene/sceneManager.h" #include "scene/sceneRenderState.h" @@ -89,6 +90,9 @@ RenderGlowMgr::RenderGlowMgr() { notifyType( RenderPassManager::RIT_Decal ); notifyType( RenderPassManager::RIT_Translucent ); + notifyType( RenderPassManager::RIT_Particle ); + + mParticleRenderMgr = NULL; mNamedTarget.registerWithName( "glowbuffer" ); mTargetSizeType = WindowSize; @@ -122,6 +126,14 @@ void RenderGlowMgr::addElement( RenderInst *inst ) // manner so we can skip glow in a non-diffuse render pass. //if ( !mParentManager->getSceneManager()->getSceneState()->isDiffusePass() ) //return RenderBinManager::arSkipped; + ParticleRenderInst *particleInst = NULL; + if(inst->type == RenderPassManager::RIT_Particle) + particleInst = static_cast(inst); + if(particleInst && particleInst->glow) + { + internalAddElement(inst); + return; + } // Skip it if we don't have a glowing material. BaseMatInstance *matInst = getMaterial( inst ); @@ -171,7 +183,31 @@ void RenderGlowMgr::render( SceneRenderState *state ) for( U32 j=0; j(mElementList[j].inst); + RenderInst *_ri = mElementList[j].inst; + if(_ri->type == RenderPassManager::RIT_Particle) + { + // 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(bin); + break; + } + } + } + + ParticleRenderInst *ri = static_cast(_ri); + mParticleRenderMgr->renderParticle(ri, state); + j++; + continue; + } + + MeshRenderInst *ri = static_cast(_ri); setupSGData( ri, sgData ); @@ -191,6 +227,9 @@ void RenderGlowMgr::render( SceneRenderState *state ) U32 a; for( a=j; atype == RenderPassManager::RIT_Particle) + break; + MeshRenderInst *passRI = static_cast(mElementList[a].inst); if ( newPassNeeded( ri, passRI ) ) diff --git a/Engine/source/renderInstance/renderGlowMgr.h b/Engine/source/renderInstance/renderGlowMgr.h index 7b92218c1..6b7d2289f 100644 --- a/Engine/source/renderInstance/renderGlowMgr.h +++ b/Engine/source/renderInstance/renderGlowMgr.h @@ -26,6 +26,7 @@ #ifndef _TEXTARGETBIN_MGR_H_ #include "renderInstance/renderTexTargetBinManager.h" #endif +#include class PostEffect; @@ -82,7 +83,7 @@ protected: }; SimObjectPtr mGlowEffect; - + RenderParticleMgr *mParticleRenderMgr; }; diff --git a/Engine/source/renderInstance/renderParticleMgr.cpp b/Engine/source/renderInstance/renderParticleMgr.cpp index 5355cbaf6..ade79420d 100644 --- a/Engine/source/renderInstance/renderParticleMgr.cpp +++ b/Engine/source/renderInstance/renderParticleMgr.cpp @@ -399,64 +399,7 @@ void RenderParticleMgr::renderInstance(ParticleRenderInst *ri, SceneRenderState 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( mParticleShaderConsts.mSamplerDiffuse->getSamplerRegister(), ri->diffuseTex ); - - // Set up the prepass texture. - if ( mParticleShaderConsts.mPrePassTargetParamsSC->isValid() ) - { - GFXTextureObject *texObject = mPrepassTarget ? mPrepassTarget->getTexture(0) : NULL; - GFX->setTexture( mParticleShaderConsts.mSamplerPrePassTex->getSamplerRegister(), 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 ); + renderParticle(ri, state); } else if(ri->systemState == PSS_AwaitingCompositeDraw) { @@ -530,6 +473,68 @@ void RenderParticleMgr::renderInstance(ParticleRenderInst *ri, SceneRenderState } } +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 prepass texture. + if ( mParticleShaderConsts.mPrePassTargetParamsSC->isValid() ) + { + GFXTextureObject *texObject = mPrepassTarget ? mPrepassTarget->getTexture(0) : NULL; + GFX->setTexture( mParticleShaderConsts.mSamplerPrePassTex->getSamplerRegister(), 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 ); +} + bool RenderParticleMgr::_initShader() { ShaderData *shaderData = NULL; diff --git a/Engine/source/renderInstance/renderParticleMgr.h b/Engine/source/renderInstance/renderParticleMgr.h index b292ea673..f7a1e2861 100644 --- a/Engine/source/renderInstance/renderParticleMgr.h +++ b/Engine/source/renderInstance/renderParticleMgr.h @@ -77,7 +77,9 @@ protected: // Not only a helper method, but a method for the RenderTranslucentMgr to // request a particle system draw void renderInstance(ParticleRenderInst *ri, SceneRenderState *state); - +public: + void renderParticle(ParticleRenderInst *ri, SceneRenderState *state); +protected: bool mOffscreenRenderEnabled; /// The prepass render target used for the diff --git a/Engine/source/renderInstance/renderPassManager.h b/Engine/source/renderInstance/renderPassManager.h index 1f07a8ac7..b13a7adba 100644 --- a/Engine/source/renderInstance/renderPassManager.h +++ b/Engine/source/renderInstance/renderPassManager.h @@ -392,6 +392,8 @@ struct ParticleRenderInst : public RenderInst /// The total particle count to render. S32 count; + bool glow; + /// The combined model, camera, and projection transform. const MatrixF *modelViewProj; diff --git a/Templates/Empty/game/tools/particleEditor/ParticleEditor.ed.gui b/Templates/Empty/game/tools/particleEditor/ParticleEditor.ed.gui index 865334dbd..3ec447504 100644 --- a/Templates/Empty/game/tools/particleEditor/ParticleEditor.ed.gui +++ b/Templates/Empty/game/tools/particleEditor/ParticleEditor.ed.gui @@ -442,7 +442,7 @@ $PE_guielement_ext_colorpicker = "18 18"; text = ""; }; }; - + new GuiControl(){ // Spacer ---------------------------- isContainer = "1"; HorizSizing = "width"; Position = "0 0"; Extent = "194 8"; new GuiBitmapCtrl(){ @@ -543,6 +543,33 @@ $PE_guielement_ext_colorpicker = "18 18"; altCommand = "$ThisControl.getParent().updateFromChild($ThisControl); PE_EmitterEditor.updateAmountFields( true, $ThisControl.getValue() );"; }; }; + + new GuiControl(){ // Particle glow + isContainer = "1"; + HorizSizing = "width"; + VertSizing = "bottom"; + Position = $PE_guielement_pos_single_container ; + Extent = $PE_guielement_ext_single_container ; + + new GuiTextCtrl() { + Profile = "ToolsGuiTextProfile"; + HorizSizing = "width"; + VertSizing = "bottom"; + position = $PE_guielement_pos_name; + Extent = $PE_guielement_ext_checkbox_name; + text = "Glow"; + }; + new GuiCheckBoxCtrl() { + internalName = "PEE_glow"; + Profile = "ToolsGuiCheckBoxProfile"; + HorizSizing = "left"; + VertSizing = "bottom"; + position = $PE_guielement_pos_checkbox; + Extent = $PE_guielement_ext_checkbox; + Command = "PE_EmitterEditor.updateEmitter( \"glow\", $ThisControl.getValue());"; + text = ""; + }; + }; };// end stack }; // end "basic" rollout new GuiRolloutCtrl() { diff --git a/Templates/Empty/game/tools/particleEditor/particleEmitterEditor.ed.cs b/Templates/Empty/game/tools/particleEditor/particleEmitterEditor.ed.cs index 8d290f0a3..4e3a571e7 100644 --- a/Templates/Empty/game/tools/particleEditor/particleEmitterEditor.ed.cs +++ b/Templates/Empty/game/tools/particleEditor/particleEmitterEditor.ed.cs @@ -100,6 +100,8 @@ function PE_EmitterEditor::guiSync( %this ) PE_EmitterEditor-->PEE_reverseOrder.setValue( %data.reverseOrder ); PE_EmitterEditor-->PEE_useEmitterSizes.setValue( %data.useEmitterSizes ); PE_EmitterEditor-->PEE_useEmitterColors.setValue( %data.useEmitterColors ); + + PE_EmitterEditor-->PEE_glow.setValue( %data.glow ); // Sync up particle selectors. diff --git a/Templates/Full/game/tools/particleEditor/ParticleEditor.ed.gui b/Templates/Full/game/tools/particleEditor/ParticleEditor.ed.gui index 865334dbd..3ec447504 100644 --- a/Templates/Full/game/tools/particleEditor/ParticleEditor.ed.gui +++ b/Templates/Full/game/tools/particleEditor/ParticleEditor.ed.gui @@ -442,7 +442,7 @@ $PE_guielement_ext_colorpicker = "18 18"; text = ""; }; }; - + new GuiControl(){ // Spacer ---------------------------- isContainer = "1"; HorizSizing = "width"; Position = "0 0"; Extent = "194 8"; new GuiBitmapCtrl(){ @@ -543,6 +543,33 @@ $PE_guielement_ext_colorpicker = "18 18"; altCommand = "$ThisControl.getParent().updateFromChild($ThisControl); PE_EmitterEditor.updateAmountFields( true, $ThisControl.getValue() );"; }; }; + + new GuiControl(){ // Particle glow + isContainer = "1"; + HorizSizing = "width"; + VertSizing = "bottom"; + Position = $PE_guielement_pos_single_container ; + Extent = $PE_guielement_ext_single_container ; + + new GuiTextCtrl() { + Profile = "ToolsGuiTextProfile"; + HorizSizing = "width"; + VertSizing = "bottom"; + position = $PE_guielement_pos_name; + Extent = $PE_guielement_ext_checkbox_name; + text = "Glow"; + }; + new GuiCheckBoxCtrl() { + internalName = "PEE_glow"; + Profile = "ToolsGuiCheckBoxProfile"; + HorizSizing = "left"; + VertSizing = "bottom"; + position = $PE_guielement_pos_checkbox; + Extent = $PE_guielement_ext_checkbox; + Command = "PE_EmitterEditor.updateEmitter( \"glow\", $ThisControl.getValue());"; + text = ""; + }; + }; };// end stack }; // end "basic" rollout new GuiRolloutCtrl() { diff --git a/Templates/Full/game/tools/particleEditor/particleEmitterEditor.ed.cs b/Templates/Full/game/tools/particleEditor/particleEmitterEditor.ed.cs index 8d290f0a3..4e3a571e7 100644 --- a/Templates/Full/game/tools/particleEditor/particleEmitterEditor.ed.cs +++ b/Templates/Full/game/tools/particleEditor/particleEmitterEditor.ed.cs @@ -100,6 +100,8 @@ function PE_EmitterEditor::guiSync( %this ) PE_EmitterEditor-->PEE_reverseOrder.setValue( %data.reverseOrder ); PE_EmitterEditor-->PEE_useEmitterSizes.setValue( %data.useEmitterSizes ); PE_EmitterEditor-->PEE_useEmitterColors.setValue( %data.useEmitterColors ); + + PE_EmitterEditor-->PEE_glow.setValue( %data.glow ); // Sync up particle selectors.