12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123 |
- //-----------------------------------------------------------------------------
- // 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 "postFx/postEffect.h"
- #include "console/engineAPI.h"
- #include "core/stream/fileStream.h"
- #include "core/strings/stringUnit.h"
- #include "console/consoleTypes.h"
- #include "console/engineAPI.h"
- #include "math/util/frustum.h"
- #include "math/mathUtils.h"
- #include "gfx/gfxTransformSaver.h"
- #include "gfx/gfxStringEnumTranslate.h"
- #include "gfx/gfxTextureManager.h"
- #include "gfx/gfxDebugEvent.h"
- #include "gfx/util/screenspace.h"
- #include "gfx/sim/gfxStateBlockData.h"
- #include "scene/sceneRenderState.h"
- #include "shaderGen/shaderGenVars.h"
- #include "lighting/lightInfo.h"
- #include "lighting/lightManager.h"
- #include "materials/materialManager.h"
- #include "materials/shaderData.h"
- #include "postFx/postEffectManager.h"
- #include "postFx/postEffectVis.h"
- using namespace Torque;
- ConsoleDocClass( PostEffect,
- "@brief A fullscreen shader effect.\n\n"
- "@section PFXTextureIdentifiers\n\n"
- "@ingroup Rendering\n"
- );
- IMPLEMENT_CALLBACK( PostEffect, onAdd, void, (), (),
- "Called when this object is first created and registered."
- );
- IMPLEMENT_CALLBACK( PostEffect, preProcess, void, (), (),
- "Called when an effect is processed but before textures are bound. This "
- "allows the user to change texture related paramaters or macros at runtime.\n"
- "@tsexample\n"
- "function SSAOPostFx::preProcess( %this )\n"
- "{\n"
- " if ( $SSAOPostFx::quality !$= %this.quality )\n"
- " {\n"
- " %this.quality = mClamp( mRound( $SSAOPostFx::quality ), 0, 2 );\n"
- " \n"
- " %this.setShaderMacro( \"QUALITY\", %this.quality );\n"
- " }\n"
- " %this.targetScale = $SSAOPostFx::targetScale;\n"
- "}\n"
- "@endtsexample\n"
- "@see setShaderConst\n"
- "@see setShaderMacro"
- );
- IMPLEMENT_CALLBACK( PostEffect, setShaderConsts, void, (), (),
- "Called immediate before processing this effect. This is the user's chance "
- "to set the value of shader uniforms (constants).\n"
- "@see setShaderConst"
- );
- IMPLEMENT_CALLBACK( PostEffect, onEnabled, bool, (), (),
- "Called when this effect becomes enabled. If the user returns false from "
- "this callback the effect will not be enabled.\n"
- "@return True to allow this effect to be enabled."
- );
- IMPLEMENT_CALLBACK( PostEffect, onDisabled, void, (), (),
- "Called when this effect becomes disabled."
- );
- ImplementEnumType( PFXRenderTime,
- "When to process this effect during the frame.\n"
- "@ingroup Rendering\n\n")
- { PFXBeforeBin, "PFXBeforeBin", "Before a RenderInstManager bin.\n" },
- { PFXAfterBin, "PFXAfterBin", "After a RenderInstManager bin.\n" },
- { PFXAfterDiffuse, "PFXAfterDiffuse", "After the diffuse rendering pass.\n" },
- { PFXEndOfFrame, "PFXEndOfFrame", "When the end of the frame is reached.\n" },
- { PFXTexGenOnDemand, "PFXTexGenOnDemand", "This PostEffect is not processed by the manager. It will generate its texture when it is requested.\n" }
- EndImplementEnumType;
- ImplementEnumType( PFXTargetClear,
- "Describes when the target texture should be cleared\n"
- "@ingroup Rendering\n\n")
- { PFXTargetClear_None, "PFXTargetClear_None", "Never clear the PostEffect target.\n" },
- { PFXTargetClear_OnCreate, "PFXTargetClear_OnCreate", "Clear once on create.\n" },
- { PFXTargetClear_OnDraw, "PFXTargetClear_OnDraw", "Clear before every draw.\n" },
- EndImplementEnumType;
- ImplementEnumType( PFXTargetViewport,
- "Specifies how the viewport should be set up for a PostEffect's target.\n"
- "@note Applies to both the diffuse target and the depth target (if defined).\n"
- "@ingroup Rendering\n\n")
- { PFXTargetViewport_TargetSize, "PFXTargetViewport_TargetSize", "Set viewport to match target size (default).\n" },
- { PFXTargetViewport_GFXViewport, "PFXTargetViewport_GFXViewport", "Use the current GFX viewport (scaled to match target size).\n" },
- { PFXTargetViewport_NamedInTexture0, "PFXTargetViewport_NamedInTexture0", "Use the input texture 0 if it is named (scaled to match target size), otherwise revert to PFXTargetViewport_TargetSize if there is none.\n" },
- EndImplementEnumType;
- GFXImplementVertexFormat( PFXVertex )
- {
- addElement( "POSITION", GFXDeclType_Float3 );
- addElement( "TEXCOORD", GFXDeclType_Float2, 0 );
- addElement( "TEXCOORD", GFXDeclType_Float3, 1 );
- };
- GFX_ImplementTextureProfile( PostFxTargetProfile,
- GFXTextureProfile::DiffuseMap,
- GFXTextureProfile::PreserveSize |
- GFXTextureProfile::RenderTarget |
- GFXTextureProfile::Pooled,
- GFXTextureProfile::NONE );
- IMPLEMENT_CONOBJECT(PostEffect);
- GFX_ImplementTextureProfile( PostFxTextureProfile,
- GFXTextureProfile::DiffuseMap,
- GFXTextureProfile::Static | GFXTextureProfile::PreserveSize | GFXTextureProfile::NoMipmap,
- GFXTextureProfile::NONE );
- GFX_ImplementTextureProfile( PostFxTextureSRGBProfile,
- GFXTextureProfile::DiffuseMap,
- GFXTextureProfile::Static | GFXTextureProfile::PreserveSize | GFXTextureProfile::NoMipmap | GFXTextureProfile::SRGB,
- GFXTextureProfile::NONE);
- GFX_ImplementTextureProfile( VRTextureProfile,
- GFXTextureProfile::DiffuseMap,
- GFXTextureProfile::PreserveSize |
- GFXTextureProfile::RenderTarget |
- GFXTextureProfile::NoMipmap,
- GFXTextureProfile::NONE );
- GFX_ImplementTextureProfile( VRDepthProfile,
- GFXTextureProfile::DiffuseMap,
- GFXTextureProfile::PreserveSize |
- GFXTextureProfile::NoMipmap |
- GFXTextureProfile::ZTarget,
- GFXTextureProfile::NONE );
- void PostEffect::EffectConst::set( const String &newVal )
- {
- if ( mStringVal == newVal )
- return;
- mStringVal = newVal;
- mDirty = true;
- mValueType = StringType;
- }
- void PostEffect::EffectConst::set(const F32 &newVal)
- {
- if (mFloatVal == newVal)
- return;
- mFloatVal = newVal;
- mDirty = true;
- mValueType = FloatType;
- }
- void PostEffect::EffectConst::set(const int& newVal)
- {
- if (mIntVal == newVal)
- return;
- mIntVal = newVal;
- mDirty = true;
- mValueType = IntType;
- }
- void PostEffect::EffectConst::set(const Point4F &newVal)
- {
- if (mPointVal == newVal)
- return;
- mPointVal = newVal;
- mDirty = true;
- mValueType = PointType;
- }
- void PostEffect::EffectConst::set(const MatrixF &newVal)
- {
- if (mMatrixVal == newVal)
- return;
- mMatrixVal = newVal;
- mDirty = true;
- mValueType = MatrixType;
- }
- void PostEffect::EffectConst::set(const Vector<Point4F> &newVal)
- {
- //if (mPointArrayVal == newVal)
- // return;
- mPointArrayVal = newVal;
- mDirty = true;
- mValueType = PointArrayType;
- }
- void PostEffect::EffectConst::set(const Vector<MatrixF> &newVal)
- {
- //if (mMatrixArrayVal == newVal)
- // return;
- mMatrixArrayVal = newVal;
- mDirty = true;
- mValueType = MatrixArrayType;
- }
- void PostEffect::EffectConst::setToBuffer( GFXShaderConstBufferRef buff )
- {
- // Nothing to do if the value hasn't changed.
- if ( !mDirty )
- return;
- mDirty = false;
- // If we don't have a handle... get it now.
- if ( !mHandle )
- mHandle = buff->getShader()->getShaderConstHandle( mName );
- // If the handle isn't valid then we're done.
- if ( !mHandle->isValid() )
- return;
- const GFXShaderConstType type = mHandle->getType();
- // For now, we're only going
- // to support float4 arrays.
- // Expand to other types as necessary.
- U32 arraySize = mHandle->getArraySize();
- if (mValueType == StringType)
- {
- const char *strVal = mStringVal.c_str();
- if (type == GFXSCT_Int)
- {
- S32 val;
- Con::setData(TypeS32, &val, 0, 1, &strVal);
- buff->set(mHandle, val);
- }
- else if (type == GFXSCT_Float)
- {
- F32 val;
- Con::setData(TypeF32, &val, 0, 1, &strVal);
- buff->set(mHandle, val);
- }
- else if (type == GFXSCT_Float2)
- {
- Point2F val;
- Con::setData(TypePoint2F, &val, 0, 1, &strVal);
- buff->set(mHandle, val);
- }
- else if (type == GFXSCT_Float3)
- {
- Point3F val;
- Con::setData(TypePoint3F, &val, 0, 1, &strVal);
- buff->set(mHandle, val);
- }
- else if (type == GFXSCT_Float4)
- {
- Point4F val;
- if (arraySize > 1)
- {
- // Do array setup!
- //U32 unitCount = StringUnit::getUnitCount( strVal, "\t" );
- //AssertFatal( unitCount == arraySize, "" );
- String tmpString;
- Vector<Point4F> valArray;
- for (U32 i = 0; i < arraySize; i++)
- {
- tmpString = StringUnit::getUnit(strVal, i, "\t");
- valArray.increment();
- const char *tmpCStr = tmpString.c_str();
- Con::setData(TypePoint4F, &valArray.last(), 0, 1, &tmpCStr);
- }
- AlignedArray<Point4F> rectData(valArray.size(), sizeof(Point4F), (U8*)valArray.address(), false);
- buff->set(mHandle, rectData);
- }
- else
- {
- // Do regular setup.
- Con::setData(TypePoint4F, &val, 0, 1, &strVal);
- buff->set(mHandle, val);
- }
- }
- else
- {
- #if TORQUE_DEBUG
- const char* err = avar("PostEffect::EffectConst::setToBuffer $s type is not implemented", mName.c_str());
- Con::errorf(err);
- GFXAssertFatal(0, err);
- #endif
- }
- }
- else if (mValueType == FloatType)
- {
- if (type == GFXSCT_Float)
- {
- buff->set(mHandle, mFloatVal);
- }
- else
- {
- #if TORQUE_DEBUG
- const char* err = avar("PostEffect::EffectConst::setToBuffer $s type is not implemented", mName.c_str());
- Con::errorf(err);
- GFXAssertFatal(0, err);
- #endif
- }
- }
- else if (mValueType == IntType)
- {
- if (type == GFXSCT_Int)
- {
- buff->set(mHandle, mIntVal);
- }
- else
- {
- #if TORQUE_DEBUG
- const char* err = avar("PostEffect::EffectConst::setToBuffer $s type is not implemented", mName.c_str());
- Con::errorf(err);
- GFXAssertFatal(0, err);
- #endif
- }
- }
- else if (mValueType == PointType)
- {
- if (type == GFXSCT_Float2)
- {
- buff->set(mHandle, Point2F(mPointVal.x, mPointVal.y));
- }
- else if (type == GFXSCT_Float3)
- {
- buff->set(mHandle, Point3F(mPointVal.x, mPointVal.y, mPointVal.z));
- }
- else if (type == GFXSCT_Float4)
- {
- buff->set(mHandle, mPointVal);
- }
- else
- {
- #if TORQUE_DEBUG
- const char* err = avar("PostEffect::EffectConst::setToBuffer $s type is not implemented", mName.c_str());
- Con::errorf(err);
- GFXAssertFatal(0, err);
- #endif
- }
- }
- else if (mValueType == MatrixType)
- {
- if (type == GFXSCT_Float4x4)
- {
- buff->set(mHandle, mMatrixVal);
- }
- else
- {
- #if TORQUE_DEBUG
- const char* err = avar("PostEffect::EffectConst::setToBuffer $s type is not implemented", mName.c_str());
- Con::errorf(err);
- GFXAssertFatal(0, err);
- #endif
- }
- }
- else if (mValueType == PointArrayType)
- {
- if (type == GFXSCT_Float4)
- {
- if (arraySize != mPointArrayVal.size())
- {
- #if TORQUE_DEBUG
- const char* err = avar("PostEffect::EffectConst::setToBuffer PointArrayType, attempted to feed an array that does not match the uniform array's size!");
- Con::errorf(err);
- GFXAssertFatal(0, err);
- #endif
- return;
- }
- AlignedArray<Point4F> alignedVal = AlignedArray<Point4F>(arraySize, sizeof(Point4F), (U8*)mPointArrayVal.address(), false);
- buff->set(mHandle, alignedVal);
- }
- else
- {
- #if TORQUE_DEBUG
- const char* err = avar("PostEffect::EffectConst::setToBuffer $s type is not implemented", mName.c_str());
- Con::errorf(err);
- GFXAssertFatal(0, err);
- #endif
- }
- }
- else if (mValueType == MatrixArrayType)
- {
- if (type == GFXSCT_Float4x4)
- {
- if (arraySize != mMatrixArrayVal.size())
- {
- #if TORQUE_DEBUG
- const char* err = avar("PostEffect::EffectConst::setToBuffer MatrixArrayType, attempted to feed an array that does not match the uniform array's size!");
- Con::errorf(err);
- GFXAssertFatal(0, err);
- #endif
- return;
- }
- buff->set(mHandle, mMatrixArrayVal.address(), arraySize);
- }
- else
- {
- #if TORQUE_DEBUG
- const char* err = avar("PostEffect::EffectConst::setToBuffer $s type is not implemented", mName.c_str());
- Con::errorf(err);
- GFXAssertFatal(0, err);
- #endif
- }
- }
- }
- //-------------------------------------------------------------------------
- // PostEffect
- //-------------------------------------------------------------------------
- PostEffect::PostEffect()
- : mRenderTime( PFXAfterDiffuse ),
- mRenderPriority( 1.0 ),
- mEnabled( false ),
- mStateBlockData( NULL ),
- mUpdateShader( true ),
- mSkip( false ),
- mAllowReflectPass( false ),
- mTargetClear( PFXTargetClear_None ),
- mTargetScale( Point2F::One ),
- mTargetViewport( PFXTargetViewport_TargetSize ),
- mTargetSize( Point2I::Zero ),
- mTargetFormat( GFXFormatR8G8B8A8 ),
- mTargetClearColor( LinearColorF::BLACK ),
- mOneFrameOnly( false ),
- mOnThisFrame( true ),
- mRTSizeSC( NULL ),
- mIsValid( false ),
- mShaderReloadKey( 0 ),
- mOneOverRTSizeSC( NULL ),
- mViewportOffsetSC( NULL ),
- mTargetViewportSC( NULL ),
- mFogDataSC( NULL ),
- mFogColorSC( NULL ),
- mEyePosSC( NULL ),
- mMatWorldToScreenSC( NULL ),
- mMatScreenToWorldSC( NULL ),
- mMatPrevScreenToWorldSC( NULL ),
- mNearFarSC( NULL ),
- mInvNearFarSC( NULL ),
- mWorldToScreenScaleSC( NULL ),
- mProjectionOffsetSC( NULL ),
- mWaterColorSC( NULL ),
- mWaterFogDataSC( NULL ),
- mAmbientColorSC( NULL ),
- mWaterFogPlaneSC( NULL ),
- mWaterDepthGradMaxSC( NULL ),
- mScreenSunPosSC( NULL ),
- mLightDirectionSC( NULL ),
- mCameraForwardSC( NULL ),
- mAccumTimeSC( NULL ),
- mDampnessSC(NULL),
- mDeltaTimeSC( NULL ),
- mInvCameraMatSC( NULL ),
- mMatCameraToWorldSC( NULL),
- mInvCameraTransSC(NULL),
- mMatCameraToScreenSC(NULL),
- mMatScreenToCameraSC(NULL)
- {
- dMemset( mTexSRGB, 0, sizeof(bool) * NumTextures);
- dMemset( mActiveTextures, 0, sizeof( GFXTextureObject* ) * NumTextures );
- dMemset( mActiveNamedTarget, 0, sizeof( NamedTexTarget* ) * NumTextures );
- dMemset( mActiveTextureViewport, 0, sizeof( RectI ) * NumTextures );
- dMemset( mTexSizeSC, 0, sizeof( GFXShaderConstHandle* ) * NumTextures );
- dMemset( mRenderTargetParamsSC, 0, sizeof( GFXShaderConstHandle* ) * NumTextures );
- for (U32 i = 0; i < NumTextures; i++)
- {
- INIT_IMAGEASSET_ARRAY(Texture, PostFxTextureProfile, i);
- }
- }
- PostEffect::~PostEffect()
- {
- EffectConstTable::Iterator iter = mEffectConsts.begin();
- for ( ; iter != mEffectConsts.end(); iter++ )
- delete iter->value;
- }
- void PostEffect::initPersistFields()
- {
- addField( "shader", TypeRealString, Offset( mShaderName, PostEffect ),
- "Name of a GFXShaderData for this effect." );
- addField( "stateBlock", TYPEID<GFXStateBlockData>(), Offset( mStateBlockData, PostEffect ),
- "Name of a GFXStateBlockData for this effect." );
- addField( "target", TypeRealString, Offset( mTargetName, PostEffect ),
- "String identifier of this effect's target texture.\n"
- "@see PFXTextureIdentifiers" );
-
- addField( "targetDepthStencil", TypeRealString, Offset( mTargetDepthStencilName, PostEffect ),
- "Optional string identifier for this effect's target depth/stencil texture.\n"
- "@see PFXTextureIdentifiers" );
- addField( "targetScale", TypePoint2F, Offset( mTargetScale, PostEffect ),
- "If targetSize is zero this is used to set a relative size from the current target." );
-
- addField( "targetSize", TypePoint2I, Offset( mTargetSize, PostEffect ),
- "If non-zero this is used as the absolute target size." );
-
- addField( "targetFormat", TypeGFXFormat, Offset( mTargetFormat, PostEffect ),
- "Format of the target texture, not applicable if writing to the backbuffer." );
- addField( "targetClearColor", TypeColorF, Offset( mTargetClearColor, PostEffect ),
- "Color to which the target texture is cleared before rendering." );
- addField( "targetClear", TYPEID< PFXTargetClear >(), Offset( mTargetClear, PostEffect ),
- "Describes when the target texture should be cleared." );
- addField( "targetViewport", TYPEID< PFXTargetViewport >(), Offset( mTargetViewport, PostEffect ),
- "Specifies how the viewport should be set up for a target texture." );
- INITPERSISTFIELD_IMAGEASSET_ARRAY(Texture, NumTextures, PostEffect, "Input textures to this effect ( samplers ).\n"
- "@see PFXTextureIdentifiers");
- addField("textureSRGB", TypeBool, Offset(mTexSRGB, PostEffect), NumTextures,
- "Set input texture to be sRGB");
- addField( "renderTime", TYPEID< PFXRenderTime >(), Offset( mRenderTime, PostEffect ),
- "When to process this effect during the frame." );
- addField( "renderBin", TypeRealString, Offset( mRenderBin, PostEffect ),
- "Name of a renderBin, used if renderTime is PFXBeforeBin or PFXAfterBin." );
- addField( "renderPriority", TypeF32, Offset( mRenderPriority, PostEffect ),
- "PostEffects are processed in DESCENDING order of renderPriority if more than one has the same renderBin/Time." );
- addField( "allowReflectPass", TypeBool, Offset( mAllowReflectPass, PostEffect ),
- "Is this effect processed during reflection render passes." );
- addProtectedField( "enabled", TypeBool, Offset( mEnabled, PostEffect),
- &PostEffect::_setIsEnabled, &defaultProtectedGetFn,
- "Is the effect on." );
- addField( "onThisFrame", TypeBool, Offset( mOnThisFrame, PostEffect ),
- "Allows you to turn on a PostEffect for only a single frame." );
- addField( "oneFrameOnly", TypeBool, Offset( mOneFrameOnly, PostEffect ),
- "Allows you to turn on a PostEffect for only a single frame." );
- addField( "skip", TypeBool, Offset( mSkip, PostEffect ),
- "Skip processing of this PostEffect and its children even if its parent "
- "is enabled. Parent and sibling PostEffects in the chain are still processed." );
- Parent::initPersistFields();
- }
- bool PostEffect::onAdd()
- {
- if( !Parent::onAdd() )
- return false;
- LightManager::smActivateSignal.notify( this, &PostEffect::_onLMActivate );
- mUpdateShader = true;
- // Grab the script path.
- Torque::Path scriptPath( Con::getVariable( "$Con::File" ) );
- scriptPath.setFileName( String::EmptyString );
- scriptPath.setExtension( String::EmptyString );
- // Find additional textures
- for (S32 i = 0; i < NumTextures; i++)
- {
- mTextureType[i] = NormalTextureType;
- String texFilename = getTexture(i);
- // Skip empty stages or ones with variable or target names.
- if (texFilename.isEmpty() ||
- texFilename[0] == '$' ||
- texFilename[0] == '#')
- continue;
- mTextureProfile[i] = (mTexSRGB[i]) ? &PostFxTextureSRGBProfile : &PostFxTextureProfile;
- _setTexture(texFilename, i);
- }
- // Is the target a named target?
- if ( mTargetName.isNotEmpty() && mTargetName[0] == '#' )
- {
- mNamedTarget.registerWithName( mTargetName.substr( 1 ) );
- mNamedTarget.getTextureDelegate().bind( this, &PostEffect::_getTargetTexture );
- }
- if ( mTargetDepthStencilName.isNotEmpty() && mTargetDepthStencilName[0] == '#' )
- mNamedTargetDepthStencil.registerWithName( mTargetDepthStencilName.substr( 1 ) );
- if (mNamedTarget.isRegistered() || mNamedTargetDepthStencil.isRegistered())
- GFXTextureManager::addEventDelegate( this, &PostEffect::_onTextureEvent );
- // Call onAdd in script
- onAdd_callback();
- // Should we start enabled?
- if ( mEnabled )
- {
- mEnabled = false;
- enable();
- }
- getSet()->addObject( this );
- return true;
- }
- void PostEffect::onRemove()
- {
- Parent::onRemove();
- PFXMGR->_removeEffect( this );
- LightManager::smActivateSignal.remove( this, &PostEffect::_onLMActivate );
- mShader = NULL;
- _cleanTargets();
- if ( mNamedTarget.isRegistered() || mNamedTargetDepthStencil.isRegistered() )
- GFXTextureManager::removeEventDelegate( this, &PostEffect::_onTextureEvent );
- if ( mNamedTarget.isRegistered() )
- {
- mNamedTarget.unregister();
- mNamedTarget.getTextureDelegate().clear();
- }
- if ( mNamedTargetDepthStencil.isRegistered() )
- mNamedTargetDepthStencil.unregister();
- }
- void PostEffect::_updateScreenGeometry( const Frustum &frustum,
- GFXVertexBufferHandle<PFXVertex> *outVB )
- {
- outVB->set( GFX, 4, GFXBufferTypeVolatile );
- const Point3F *frustumPoints = frustum.getPoints();
- const Point3F& cameraPos = frustum.getPosition();
- // Perform a camera offset. We need to manually perform this offset on the postFx's
- // polygon, which is at the far plane.
- const Point2F& projOffset = frustum.getProjectionOffset();
- Point3F cameraOffsetPos = cameraPos;
- if(!projOffset.isZero())
- {
- // First we need to calculate the offset at the near plane. The projOffset
- // given above can be thought of a percent as it ranges from 0..1 (or 0..-1).
- F32 nearOffset = frustum.getNearRight() * projOffset.x;
- // Now given the near plane distance from the camera we can solve the right
- // triangle and calcuate the SIN theta for the offset at the near plane.
- // SIN theta = x/y
- F32 sinTheta = nearOffset / frustum.getNearDist();
- // Finally, we can calcuate the offset at the far plane, which is where our sun (or vector)
- // light's polygon is drawn.
- F32 farOffset = frustum.getFarDist() * sinTheta;
- // We can now apply this far plane offset to the far plane itself, which then compensates
- // for the project offset.
- MatrixF camTrans = frustum.getTransform();
- VectorF offset = camTrans.getRightVector();
- offset *= farOffset;
- cameraOffsetPos += offset;
- }
- PFXVertex *vert = outVB->lock();
- vert->point.set(-1.0, 1.0, 0.0);
- vert->texCoord.set(0.0f, 0.0f);
- vert->wsEyeRay = frustumPoints[Frustum::FarTopLeft] - cameraOffsetPos;
- vert++;
- vert->point.set(1.0, 1.0, 0.0);
- vert->texCoord.set(1.0f, 0.0f);
- vert->wsEyeRay = frustumPoints[Frustum::FarTopRight] - cameraOffsetPos;
- vert++;
- vert->point.set(-1.0, -1.0, 0.0);
- vert->texCoord.set(0.0f, 1.0f);
- vert->wsEyeRay = frustumPoints[Frustum::FarBottomLeft] - cameraOffsetPos;
- vert++;
- vert->point.set(1.0, -1.0, 0.0);
- vert->texCoord.set(1.0f, 1.0f);
- vert->wsEyeRay = frustumPoints[Frustum::FarBottomRight] - cameraOffsetPos;
- vert++;
- outVB->unlock();
- }
- void PostEffect::_setupStateBlock( const SceneRenderState *state )
- {
- if ( mStateBlock.isNull() )
- {
- GFXStateBlockDesc desc;
- if ( mStateBlockData )
- desc = mStateBlockData->getState();
- mStateBlock = GFX->createStateBlock( desc );
- }
- GFX->setStateBlock( mStateBlock );
- }
- void PostEffect::_setupConstants( const SceneRenderState *state )
- {
- // Alloc the const buffer.
- if ( mShaderConsts.isNull() )
- {
- mShaderConsts = mShader->allocConstBuffer();
- mRTSizeSC = mShader->getShaderConstHandle( "$targetSize" );
- mOneOverRTSizeSC = mShader->getShaderConstHandle( "$oneOverTargetSize" );
- mRTRatioSC = mShader->getShaderConstHandle("$targetRatio");
- for (U32 i = 0; i < NumTextures; i++)
- {
- mTexSizeSC[i] = mShader->getShaderConstHandle(String::ToString("$texSize%d", i));
- mRenderTargetParamsSC[i] = mShader->getShaderConstHandle(String::ToString("$rtParams%d",i));
- }
- mTargetViewportSC = mShader->getShaderConstHandle( "$targetViewport" );
- mFogDataSC = mShader->getShaderConstHandle( ShaderGenVars::fogData );
- mFogColorSC = mShader->getShaderConstHandle( ShaderGenVars::fogColor );
- mEyePosSC = mShader->getShaderConstHandle( ShaderGenVars::eyePosWorld );
- mNearFarSC = mShader->getShaderConstHandle( "$nearFar" );
- mInvNearFarSC = mShader->getShaderConstHandle( "$invNearFar" );
- mWorldToScreenScaleSC = mShader->getShaderConstHandle( "$worldToScreenScale" );
- mMatWorldToScreenSC = mShader->getShaderConstHandle( "$matWorldToScreen" );
- mMatScreenToWorldSC = mShader->getShaderConstHandle( "$matScreenToWorld" );
- mMatPrevScreenToWorldSC = mShader->getShaderConstHandle( "$matPrevScreenToWorld" );
- mProjectionOffsetSC = mShader->getShaderConstHandle( "$projectionOffset" );
- mWaterColorSC = mShader->getShaderConstHandle( "$waterColor" );
- mAmbientColorSC = mShader->getShaderConstHandle( "$ambientColor" );
- mWaterFogDataSC = mShader->getShaderConstHandle( "$waterFogData" );
- mWaterFogPlaneSC = mShader->getShaderConstHandle( "$waterFogPlane" );
- mWaterDepthGradMaxSC = mShader->getShaderConstHandle( "$waterDepthGradMax" );
- mScreenSunPosSC = mShader->getShaderConstHandle( "$screenSunPos" );
- mLightDirectionSC = mShader->getShaderConstHandle( "$lightDirection" );
- mCameraForwardSC = mShader->getShaderConstHandle( "$camForward" );
- mAccumTimeSC = mShader->getShaderConstHandle( "$accumTime" );
- mDampnessSC = mShader->getShaderConstHandle("$dampness");
-
- mDeltaTimeSC = mShader->getShaderConstHandle( "$deltaTime" );
- mInvCameraMatSC = mShader->getShaderConstHandle( "$invCameraMat" );
- mMatCameraToWorldSC = mShader->getShaderConstHandle("$cameraToWorld");
- mInvCameraTransSC = mShader->getShaderConstHandle("$invCameraTrans");
- mMatCameraToScreenSC = mShader->getShaderConstHandle("$cameraToScreen");
- mMatScreenToCameraSC = mShader->getShaderConstHandle("$screenToCamera");
- }
- // Set up shader constants for source image size
- if ( mRTSizeSC->isValid() )
- {
- const Point2I &resolution = GFX->getActiveRenderTarget()->getSize();
- Point2F pixelShaderConstantData;
- pixelShaderConstantData.x = resolution.x;
- pixelShaderConstantData.y = resolution.y;
- mShaderConsts->set( mRTSizeSC, pixelShaderConstantData );
- }
- if ( mOneOverRTSizeSC->isValid() )
- {
- const Point2I &resolution = GFX->getActiveRenderTarget()->getSize();
- Point2F oneOverTargetSize( 1.0f / (F32)resolution.x, 1.0f / (F32)resolution.y );
- mShaderConsts->set( mOneOverRTSizeSC, oneOverTargetSize );
- }
- if (mRTRatioSC->isValid())
- {
- const Point2I& resolution = GFX->getActiveRenderTarget()->getSize();
- mShaderConsts->set(mRTRatioSC, (F32)resolution.x/ (F32)resolution.y);
- }
- // Set up additional textures
- Point2F texSizeConst;
- for( U32 i = 0; i < NumTextures; i++ )
- {
- if( !mActiveTextures[i] )
- continue;
- if ( mTexSizeSC[i]->isValid() )
- {
- texSizeConst.x = (F32)mActiveTextures[i]->getWidth();
- texSizeConst.y = (F32)mActiveTextures[i]->getHeight();
- mShaderConsts->set( mTexSizeSC[i], texSizeConst );
- }
- }
- for ( U32 i = 0; i < NumTextures; i++ )
- {
- if ( !mRenderTargetParamsSC[i]->isValid() )
- continue;
- Point4F rtParams( Point4F::One );
- if ( mActiveTextures[i] )
- {
- const Point3I &targetSz = mActiveTextures[i]->getSize();
- RectI targetVp = mActiveTextureViewport[i];
- ScreenSpace::RenderTargetParameters(targetSz, targetVp, rtParams);
- }
- mShaderConsts->set( mRenderTargetParamsSC[i], rtParams );
- }
- // Target viewport (in target space)
- if ( mTargetViewportSC->isValid() )
- {
- const Point2I& targetSize = GFX->getActiveRenderTarget()->getSize();
- Point3I size(targetSize.x, targetSize.y, 0);
- const RectI& viewport = GFX->getViewport();
- Point2F offset((F32)viewport.point.x / (F32)targetSize.x, (F32)viewport.point.y / (F32)targetSize.y );
- Point2F scale((F32)viewport.extent.x / (F32)targetSize.x, (F32)viewport.extent.y / (F32)targetSize.y );
- Point4F targetParams;
- targetParams.x = offset.x;
- targetParams.y = offset.y;
- targetParams.z = offset.x + scale.x;
- targetParams.w = offset.y + scale.y;
- mShaderConsts->set( mTargetViewportSC, targetParams );
- }
- // Set the fog data.
- if ( mFogDataSC->isValid() )
- {
- const FogData &data = state->getSceneManager()->getFogData();
- Point3F params;
- params.x = data.density;
- params.y = data.densityOffset;
- if ( !mIsZero( data.atmosphereHeight ) )
- params.z = 1.0f / data.atmosphereHeight;
- else
- params.z = 0.0f;
- mShaderConsts->set( mFogDataSC, params );
- }
- const PFXFrameState &thisFrame = PFXMGR->getFrameState();
- if ( mMatWorldToScreenSC->isValid() )
- {
- // Screen space->world space
- MatrixF tempMat = thisFrame.cameraToScreen;
- tempMat.mul( thisFrame.worldToCamera );
- tempMat.fullInverse();
- tempMat.transpose();
- // Support using these matrices as float3x3 or float4x4...
- mShaderConsts->set( mMatWorldToScreenSC, tempMat, mMatWorldToScreenSC->getType() );
- }
- if ( mMatScreenToWorldSC->isValid() )
- {
- // World space->screen space
- MatrixF tempMat = thisFrame.cameraToScreen;
- tempMat.mul( thisFrame.worldToCamera );
- tempMat.transpose();
- // Support using these matrices as float3x3 or float4x4...
- mShaderConsts->set( mMatScreenToWorldSC, tempMat, mMatScreenToWorldSC->getType() );
- }
- if ( mMatPrevScreenToWorldSC->isValid() )
- {
- const PFXFrameState &lastFrame = PFXMGR->getLastFrameState();
- // Previous frame world space->screen space
- MatrixF tempMat = lastFrame.cameraToScreen;
- tempMat.mul( lastFrame.worldToCamera );
- tempMat.transpose();
- mShaderConsts->set( mMatPrevScreenToWorldSC, tempMat );
- }
- if (mAmbientColorSC->isValid() && state)
- {
- const LinearColorF &sunlight = state->getAmbientLightColor();
- Point3F ambientColor( sunlight.red, sunlight.green, sunlight.blue );
- mShaderConsts->set( mAmbientColorSC, ambientColor );
- }
- if (mMatCameraToWorldSC->isValid())
- {
- MatrixF tempMat = thisFrame.worldToCamera;
- tempMat.inverse();
- mShaderConsts->set(mMatCameraToWorldSC, tempMat);
- }
- if (mInvCameraTransSC->isValid())
- {
- MatrixF mat = state->getCameraTransform();
- mat.fullInverse();
- mShaderConsts->set(mInvCameraTransSC, mat, mInvCameraTransSC->getType());
- }
- //Projection Matrix
- if (mMatCameraToScreenSC->isValid())
- {
- MatrixF tempMat = thisFrame.cameraToScreen;
- mShaderConsts->set(mMatCameraToScreenSC, tempMat, mMatCameraToScreenSC->getType());
- }
- //Inverse Projection Matrix
- if (mMatScreenToCameraSC->isValid())
- {
- MatrixF tempMat = thisFrame.cameraToScreen;
- tempMat.fullInverse();
- mShaderConsts->set(mMatScreenToCameraSC, tempMat, mMatScreenToCameraSC->getType());
- }
- mShaderConsts->setSafe( mAccumTimeSC, MATMGR->getTotalTime() );
- mShaderConsts->setSafe( mDeltaTimeSC, MATMGR->getDeltaTime() );
- mShaderConsts->setSafe(mDampnessSC, MATMGR->getDampnessClamped());
-
- // Now set all the constants that are dependent on the scene state.
- if ( state )
- {
- mShaderConsts->setSafe( mEyePosSC, state->getDiffuseCameraPosition() );
- mShaderConsts->setSafe( mNearFarSC, Point2F( state->getNearPlane(), state->getFarPlane() ) );
- mShaderConsts->setSafe( mInvNearFarSC, Point2F( 1.0f / state->getNearPlane(), 1.0f / state->getFarPlane() ) );
- mShaderConsts->setSafe( mWorldToScreenScaleSC, state->getWorldToScreenScale() );
- mShaderConsts->setSafe( mProjectionOffsetSC, state->getCameraFrustum().getProjectionOffset() );
- mShaderConsts->setSafe( mFogColorSC, state->getSceneManager()->getFogData().color );
- if ( mWaterColorSC->isValid() )
- {
- LinearColorF color( state->getSceneManager()->getWaterFogData().color );
- mShaderConsts->set( mWaterColorSC, color );
- }
- if ( mWaterFogDataSC->isValid() )
- {
- const WaterFogData &data = state->getSceneManager()->getWaterFogData();
- Point4F params( data.density, data.densityOffset, data.wetDepth, data.wetDarkening );
- mShaderConsts->set( mWaterFogDataSC, params );
- }
- if ( mWaterFogPlaneSC->isValid() )
- {
- const PlaneF &plane = state->getSceneManager()->getWaterFogData().plane;
- mShaderConsts->set( mWaterFogPlaneSC, plane );
- }
- if ( mWaterDepthGradMaxSC->isValid() )
- {
- mShaderConsts->set( mWaterDepthGradMaxSC, state->getSceneManager()->getWaterFogData().depthGradMax );
- }
- if ( mScreenSunPosSC->isValid() )
- {
- // Grab our projection matrix
- // from the frustum.
- Frustum frust = state->getCameraFrustum();
- MatrixF proj( true );
- frust.getProjectionMatrix( &proj );
- // Grab the ScatterSky world matrix.
- MatrixF camMat = state->getCameraTransform();
- camMat.inverse();
- MatrixF tmp( true );
- tmp = camMat;
- tmp.setPosition( Point3F( 0, 0, 0 ) );
- Point3F sunPos( 0, 0, 0 );
- // Get the light manager and sun light object.
- LightInfo *sunLight = LIGHTMGR->getSpecialLight( LightManager::slSunLightType );
- // Grab the light direction and scale
- // by the ScatterSky radius to get the world
- // space sun position.
- const VectorF &lightDir = sunLight->getDirection();
- Point3F lightPos( lightDir.x * (6378.0f * 1000.0f),
- lightDir.y * (6378.0f * 1000.0f),
- lightDir.z * (6378.0f * 1000.0f) );
- RectI viewPort = GFX->getViewport();
- // Get the screen space sun position.
- MathUtils::mProjectWorldToScreen(lightPos, &sunPos, viewPort, tmp, proj);
- // And normalize it to the 0 to 1 range.
- sunPos.x -= (F32)viewPort.point.x;
- sunPos.y -= (F32)viewPort.point.y;
- sunPos.x /= (F32)viewPort.extent.x;
- sunPos.y /= (F32)viewPort.extent.y;
- mShaderConsts->set( mScreenSunPosSC, Point2F( sunPos.x, sunPos.y ) );
- }
- if ( mLightDirectionSC->isValid() )
- {
- LightInfo *sunLight = LIGHTMGR->getSpecialLight( LightManager::slSunLightType );
- const VectorF &lightDir = sunLight->getDirection();
- mShaderConsts->set( mLightDirectionSC, lightDir );
- }
- if ( mCameraForwardSC->isValid() )
- {
- const MatrixF &camMat = state->getCameraTransform();
- VectorF camFwd( 0, 0, 0 );
- camMat.getColumn( 1, &camFwd );
- mShaderConsts->set( mCameraForwardSC, camFwd );
- }
- if ( mInvCameraMatSC->isValid() )
- {
- MatrixF mat = state->getCameraTransform();
- mat.inverse();
- mShaderConsts->set( mInvCameraMatSC, mat, mInvCameraMatSC->getType() );
- }
- } // if ( state )
- // Set EffectConsts - specified from script
- // If our shader has reloaded since last frame we must mark all
- // EffectConsts dirty so they will be reset.
- if ( mShader->getReloadKey() != mShaderReloadKey )
- {
- mShaderReloadKey = mShader->getReloadKey();
- EffectConstTable::Iterator iter = mEffectConsts.begin();
- for ( ; iter != mEffectConsts.end(); iter++ )
- {
- iter->value->mDirty = true;
- iter->value->mHandle = NULL;
- }
- }
- // Doesn't look like anyone is using this anymore.
- // But if we do want to pass this info to script,
- // we should do so in the same way as I am doing below.
- /*
- Point2F texSizeScriptConst( 0, 0 );
- String buffer;
- if ( mActiveTextures[0] )
- {
- texSizeScriptConst.x = (F32)mActiveTextures[0]->getWidth();
- texSizeScriptConst.y = (F32)mActiveTextures[0]->getHeight();
- dSscanf( buffer.c_str(), "%g %g", texSizeScriptConst.x, texSizeScriptConst.y );
- }
- */
-
- {
- PROFILE_SCOPE( PostEffect_SetShaderConsts );
- // Pass some data about the current render state to script.
- //
- // TODO: This is pretty messy... it should go away. This info
- // should be available from some other script accessible method
- // or field which isn't PostEffect specific.
- //
- if ( state )
- {
- Con::setFloatVariable( "$Param::NearDist", state->getNearPlane() );
- Con::setFloatVariable( "$Param::FarDist", state->getFarPlane() );
- }
- setShaderConsts_callback();
- }
- EffectConstTable::Iterator iter = mEffectConsts.begin();
- for ( ; iter != mEffectConsts.end(); iter++ )
- iter->value->setToBuffer( mShaderConsts );
- }
- void PostEffect::_setupTexture( U32 stage, GFXTexHandle &inputTex, const RectI *inTexViewport )
- {
- const String &texFilename = getTexture( stage );
- GFXTexHandle theTex;
- NamedTexTarget *namedTarget = NULL;
- RectI viewport = GFX->getViewport();
- if ( texFilename.compare( "$inTex", 0, String::NoCase ) == 0 )
- {
- theTex = inputTex;
- if ( inTexViewport )
- {
- viewport = *inTexViewport;
- }
- else if ( theTex )
- {
- viewport.set( 0, 0, theTex->getWidth(), theTex->getHeight() );
- }
- }
- else if ( texFilename.compare( "$backBuffer", 0, String::NoCase ) == 0 )
- {
- theTex = PFXMGR->getBackBufferTex();
- // Always use the GFX viewport when reading from the backbuffer
- }
- else if ( texFilename.isNotEmpty() && texFilename[0] == '#' )
- {
- namedTarget = NamedTexTarget::find( texFilename.c_str() + 1 );
- if ( namedTarget )
- {
- theTex = namedTarget->getTexture( 0 );
- viewport = namedTarget->getViewport();
- }
- }
- else
- {
- theTex = mTexture[ stage ];
- if ( theTex )
- viewport.set( 0, 0, theTex->getWidth(), theTex->getHeight() );
- }
- mActiveTextures[ stage ] = theTex;
- mActiveNamedTarget[ stage ] = namedTarget;
- mActiveTextureViewport[ stage ] = viewport;
- if ( theTex.isValid() )
- GFX->setTexture( stage, theTex );
- }
- void PostEffect::_setupCubemapTexture(U32 stage, GFXCubemapHandle &inputTex)
- {
- RectI viewport = GFX->getViewport();
- mActiveTextures[stage] = nullptr;
- mActiveNamedTarget[stage] = nullptr;
- mActiveTextureViewport[stage] = viewport;
- if (inputTex.isValid())
- GFX->setCubeTexture(stage, inputTex);
- }
- void PostEffect::_setupCubemapArrayTexture(U32 stage, GFXCubemapArrayHandle &inputTex)
- {
- RectI viewport = GFX->getViewport();
- mActiveTextures[stage] = nullptr;
- mActiveNamedTarget[stage] = nullptr;
- mActiveTextureViewport[stage] = viewport;
- if (inputTex.isValid())
- GFX->setCubeArrayTexture(stage, inputTex);
- }
- void PostEffect::_setupTransforms()
- {
- // Set everything to identity.
- GFX->setWorldMatrix( MatrixF::Identity );
- GFX->setProjectionMatrix( MatrixF::Identity );
- }
- void PostEffect::_setupTarget( const SceneRenderState *state, bool *outClearTarget )
- {
- if ( mNamedTarget.isRegistered() ||
- mTargetName.compare( "$outTex", 0, String::NoCase ) == 0 )
- {
- // Size it relative to the texture of the first stage or
- // if NULL then use the current target.
- Point2I targetSize;
- // If we have an absolute target size then use that.
- if ( !mTargetSize.isZero() )
- targetSize = mTargetSize;
- // Else generate a relative size using the target scale.
- else if ( mActiveTextures[ 0 ] )
- {
- const Point3I &texSize = mActiveTextures[ 0 ]->getSize();
- targetSize.set( texSize.x * mTargetScale.x,
- texSize.y * mTargetScale.y );
- }
- else
- {
- GFXTarget *oldTarget = GFX->getActiveRenderTarget();
- const Point2I &oldTargetSize = oldTarget->getSize();
- targetSize.set( oldTargetSize.x * mTargetScale.x,
- oldTargetSize.y * mTargetScale.y );
- }
- // Make sure its at least 1x1.
- targetSize.setMax( Point2I::One );
- if ( mNamedTarget.isRegistered() ||
- !mTargetTex ||
- mTargetTex.getWidthHeight() != targetSize )
- {
- mTargetTex.set( targetSize.x, targetSize.y, mTargetFormat,
- &PostFxTargetProfile, "PostEffect::_setupTarget" );
- if ( mTargetClear == PFXTargetClear_OnCreate )
- *outClearTarget = true;
- if(mTargetViewport == PFXTargetViewport_GFXViewport)
- {
- // We may need to scale the GFX viewport to fit within
- // our target texture size
- GFXTarget *oldTarget = GFX->getActiveRenderTarget();
- const Point2I &oldTargetSize = oldTarget->getSize();
- Point2F scale(targetSize.x / F32(oldTargetSize.x), targetSize.y / F32(oldTargetSize.y));
- const RectI &viewport = GFX->getViewport();
- mNamedTarget.setViewport( RectI( viewport.point.x*scale.x, viewport.point.y*scale.y, viewport.extent.x*scale.x, viewport.extent.y*scale.y ) );
- }
- else if(mTargetViewport == PFXTargetViewport_NamedInTexture0 && mActiveNamedTarget[0] && mActiveNamedTarget[0]->getTexture())
- {
- // Scale the named input texture's viewport to match our target
- const Point3I &namedTargetSize = mActiveNamedTarget[0]->getTexture()->getSize();
- Point2F scale(targetSize.x / F32(namedTargetSize.x), targetSize.y / F32(namedTargetSize.y));
- const RectI &viewport = mActiveNamedTarget[0]->getViewport();
- mNamedTarget.setViewport( RectI( viewport.point.x*scale.x, viewport.point.y*scale.y, viewport.extent.x*scale.x, viewport.extent.y*scale.y ) );
- }
- else
- {
- // PFXTargetViewport_TargetSize
- mNamedTarget.setViewport( RectI( 0, 0, targetSize.x, targetSize.y ) );
- }
- }
- }
- else
- mTargetTex = NULL;
- // Do we have a named depthStencil target?
- if ( mNamedTargetDepthStencil.isRegistered() )
- {
- // Size it relative to the texture of the first stage or
- // if NULL then use the current target.
- Point2I targetSize;
- // If we have an absolute target size then use that.
- if ( !mTargetSize.isZero() )
- targetSize = mTargetSize;
- // Else generate a relative size using the target scale.
- else if ( mActiveTextures[ 0 ] )
- {
- const Point3I &texSize = mActiveTextures[ 0 ]->getSize();
- targetSize.set( texSize.x * mTargetScale.x,
- texSize.y * mTargetScale.y );
- }
- else
- {
- GFXTarget *oldTarget = GFX->getActiveRenderTarget();
- const Point2I &oldTargetSize = oldTarget->getSize();
- targetSize.set( oldTargetSize.x * mTargetScale.x,
- oldTargetSize.y * mTargetScale.y );
- }
- // Make sure its at least 1x1.
- targetSize.setMax( Point2I::One );
-
- if ( mNamedTargetDepthStencil.isRegistered() &&
- mTargetDepthStencil.getWidthHeight() != targetSize )
- {
- mTargetDepthStencil.set( targetSize.x, targetSize.y, GFXFormatD24S8,
- &GFXZTargetProfile, "PostEffect::_setupTarget" );
- if ( mTargetClear == PFXTargetClear_OnCreate )
- *outClearTarget = true;
- if(mTargetViewport == PFXTargetViewport_GFXViewport)
- {
- // We may need to scale the GFX viewport to fit within
- // our target texture size
- GFXTarget *oldTarget = GFX->getActiveRenderTarget();
- const Point2I &oldTargetSize = oldTarget->getSize();
- Point2F scale(targetSize.x / F32(oldTargetSize.x), targetSize.y / F32(oldTargetSize.y));
- const RectI &viewport = GFX->getViewport();
- mNamedTargetDepthStencil.setViewport( RectI( viewport.point.x*scale.x, viewport.point.y*scale.y, viewport.extent.x*scale.x, viewport.extent.y*scale.y ) );
- }
- else if(mTargetViewport == PFXTargetViewport_NamedInTexture0 && mActiveNamedTarget[0] && mActiveNamedTarget[0]->getTexture())
- {
- // Scale the named input texture's viewport to match our target
- const Point3I &namedTargetSize = mActiveNamedTarget[0]->getTexture()->getSize();
- Point2F scale(targetSize.x / F32(namedTargetSize.x), targetSize.y / F32(namedTargetSize.y));
- const RectI &viewport = mActiveNamedTarget[0]->getViewport();
- mNamedTargetDepthStencil.setViewport( RectI( viewport.point.x*scale.x, viewport.point.y*scale.y, viewport.extent.x*scale.x, viewport.extent.y*scale.y ) );
- }
- else
- {
- // PFXTargetViewport_TargetSize
- mNamedTargetDepthStencil.setViewport( RectI( 0, 0, targetSize.x, targetSize.y ) );
- }
- }
- }
- else
- mTargetDepthStencil = NULL;
- if ( mTargetClear == PFXTargetClear_OnDraw )
- *outClearTarget = true;
- if ( !mTarget && (mTargetTex || mTargetDepthStencil) )
- mTarget = GFX->allocRenderToTextureTarget();
- }
- void PostEffect::_cleanTargets( bool recurse )
- {
- mTargetTex = NULL;
- mTargetDepthStencil = NULL;
- mTarget = NULL;
- if ( !recurse )
- return;
- // Clear the children too!
- for ( U32 i = 0; i < size(); i++ )
- {
- PostEffect *effect = (PostEffect*)(*this)[i];
- effect->_cleanTargets( true );
- }
- }
- void PostEffect::process( const SceneRenderState *state,
- GFXTexHandle &inOutTex,
- const RectI *inTexViewport )
- {
- // If the shader is forced to be skipped... then skip.
- if ( mSkip )
- return;
- // Skip out if we don't support reflection passes.
- if ( state && state->isReflectPass() && !mAllowReflectPass )
- return;
- if ( mOneFrameOnly && !mOnThisFrame )
- return;
- // Check requirements if the shader needs updating.
- if ( mUpdateShader )
- {
- _checkRequirements();
- // Clear the targets if we failed passing
- // the requirements at this time.
- if ( !mIsValid )
- _cleanTargets( true );
- }
- // If we're not valid then we cannot render.
- if ( !mIsValid )
- return;
- GFXDEBUGEVENT_SCOPE_EX( PostEffect_Process, ColorI::GREEN, avar("PostEffect: %s", getName()) );
- preProcess_callback();
- GFXTransformSaver saver;
- // Set the textures.
- for (U32 i = 0; i < NumTextures; i++)
- {
- if (mTextureType[i] == NormalTextureType)
- _setupTexture(i, inOutTex, inTexViewport);
- else if (mTextureType[i] == CubemapType)
- _setupCubemapTexture(i, mCubemapTextures[i]);
- else if (mTextureType[i] == CubemapArrayType)
- _setupCubemapArrayTexture(i, mCubemapArrayTextures[i]);
- }
- _setupStateBlock( state ) ;
- _setupTransforms();
- bool clearTarget = false;
- _setupTarget( state, &clearTarget );
- if ( mTargetTex || mTargetDepthStencil )
- {
- const RectI &oldViewport = GFX->getViewport();
- GFXTarget *oldTarget = GFX->getActiveRenderTarget();
- GFX->pushActiveRenderTarget();
- mTarget->attachTexture( GFXTextureTarget::Color0, mTargetTex );
- // Set the right depth stencil target.
- if ( !mTargetDepthStencil && mTargetTex.getWidthHeight() == GFX->getActiveRenderTarget()->getSize() )
- mTarget->attachTexture( GFXTextureTarget::DepthStencil, GFXTextureTarget::sDefaultDepthStencil );
- else
- mTarget->attachTexture( GFXTextureTarget::DepthStencil, mTargetDepthStencil );
- // Set the render target but not its viewport. We'll do that below.
- GFX->setActiveRenderTarget( mTarget, false );
- if(mNamedTarget.isRegistered())
- {
- // Always use the name target's viewport, if available. It was set up in _setupTarget().
- GFX->setViewport(mNamedTarget.getViewport());
- }
- else if(mTargetViewport == PFXTargetViewport_GFXViewport)
- {
- // Go with the current viewport as scaled against our render target.
- const Point2I &oldTargetSize = oldTarget->getSize();
- const Point2I &targetSize = mTarget->getSize();
- Point2F scale(targetSize.x / F32(oldTargetSize.x), targetSize.y / F32(oldTargetSize.y));
- GFX->setViewport( RectI( oldViewport.point.x*scale.x, oldViewport.point.y*scale.y, oldViewport.extent.x*scale.x, oldViewport.extent.y*scale.y ) );
- }
- else if(mTargetViewport == PFXTargetViewport_NamedInTexture0 && mActiveNamedTarget[0] && mActiveNamedTarget[0]->getTexture())
- {
- // Go with the first input texture, if it is named. Scale the named input texture's viewport to match our target
- const Point3I &namedTargetSize = mActiveNamedTarget[0]->getTexture()->getSize();
- const Point2I &targetSize = mTarget->getSize();
- Point2F scale(targetSize.x / F32(namedTargetSize.x), targetSize.y / F32(namedTargetSize.y));
- const RectI &viewport = mActiveNamedTarget[0]->getViewport();
- GFX->setViewport( RectI( viewport.point.x*scale.x, viewport.point.y*scale.y, viewport.extent.x*scale.x, viewport.extent.y*scale.y ) );
- }
- else
- {
- // Default to using the whole target as the viewport
- GFX->setViewport( RectI( Point2I::Zero, mTarget->getSize() ) );
- }
- }
- if ( clearTarget )
- GFX->clear( GFXClearTarget, mTargetClearColor, 1.f, 0 );
- // Setup the shader and constants.
- if ( mShader )
- {
- GFX->setShader( mShader );
- _setupConstants( state );
- GFX->setShaderConstBuffer( mShaderConsts );
- }
- else
- GFX->setupGenericShaders();
- Frustum frustum;
- if ( state )
- frustum = state->getCameraFrustum();
- else
- {
- // If we don't have a scene state then setup
- // a dummy frustum... you better not be depending
- // on this being related to the camera in any way.
-
- frustum = Frustum();
- }
- GFXVertexBufferHandle<PFXVertex> vb;
- _updateScreenGeometry( frustum, &vb );
- // Draw it.
- GFX->setVertexBuffer( vb );
- GFX->drawPrimitive( GFXTriangleStrip, 0, 2 );
- // Allow PostEffecVis to hook in.
- PFXVIS->onPFXProcessed( this );
- if ( mTargetTex || mTargetDepthStencil )
- {
- mTarget->resolve();
- GFX->popActiveRenderTarget();
- }
- else
- {
- // We wrote to the active back buffer, so release
- // the current texture copy held by the manager.
- //
- // This ensures a new copy is made.
- PFXMGR->releaseBackBufferTex();
- }
- // Return and release our target texture.
- inOutTex = mTargetTex;
- if ( !mNamedTarget.isRegistered() )
- mTargetTex = NULL;
- // Restore the transforms before the children
- // are processed as it screws up the viewport.
- saver.restore();
- // Now process my children.
- iterator i = begin();
- for ( ; i != end(); i++ )
- {
- PostEffect *effect = static_cast<PostEffect*>(*i);
- effect->process( state, inOutTex );
- }
- if ( mOneFrameOnly )
- mOnThisFrame = false;
- }
- bool PostEffect::_setIsEnabled( void *object, const char *index, const char *data )
- {
- bool enabled = dAtob( data );
- if ( enabled )
- static_cast<PostEffect*>( object )->enable();
- else
- static_cast<PostEffect*>( object )->disable();
- // Always return false from a protected field.
- return false;
- }
- void PostEffect::enable()
- {
- // Don't add TexGen PostEffects to the PostEffectManager!
- if ( mRenderTime == PFXTexGenOnDemand )
- return;
- // Ignore it if its already enabled.
- if ( mEnabled )
- return;
- mEnabled = true;
- // We cannot really enable the effect
- // until its been registed.
- if ( !isProperlyAdded() )
- return;
- // If the enable callback returns 'false' then
- // leave the effect disabled.
- if ( !onEnabled_callback() )
- {
- mEnabled = false;
- return;
- }
- PFXMGR->_addEffect( this );
- }
- void PostEffect::disable()
- {
- if ( !mEnabled )
- return;
- mEnabled = false;
- _cleanTargets( true );
- if ( isProperlyAdded() )
- {
- PFXMGR->_removeEffect( this );
- onDisabled_callback();
- }
- }
- void PostEffect::reload()
- {
- // Reload the shader if we have one or mark it
- // for updating when its processed next.
- if ( mShader )
- mShader->reload();
- else
- mUpdateShader = true;
- // Null stateblock so it is reloaded.
- mStateBlock = NULL;
- // Call reload on any children
- // this PostEffect may have.
- for ( U32 i = 0; i < size(); i++ )
- {
- PostEffect *effect = (PostEffect*)(*this)[i];
- effect->reload();
- }
- }
- void PostEffect::setTexture( U32 index, const String &texFilePath )
- {
- // Set the new texture name.
- mTextureName[index] = texFilePath;
- mTexture[index].free();
- // Skip empty stages or ones with variable or target names.
- if ( texFilePath.isEmpty() ||
- texFilePath[0] == '$' ||
- texFilePath[0] == '#' )
- return;
- mTextureProfile[index] = (mTexSRGB[index])? &PostFxTextureSRGBProfile : &PostFxTextureProfile;
- _setTexture(texFilePath, index);
- mTextureType[index] = NormalTextureType;
- }
- void PostEffect::setTexture(U32 index, const GFXTexHandle& texHandle)
- {
- // Set the new texture name.
- mTextureName[index] = StringTable->EmptyString();
- mTexture[index].free();
- // Skip empty stages or ones with variable or target names.
- if (!texHandle.isValid())
- return;
- // Try to load the texture.
- mTexture[index] = texHandle;
- mTextureType[index] = NormalTextureType;
- }
- void PostEffect::setCubemapTexture(U32 index, const GFXCubemapHandle &cubemapHandle)
- {
- // Set the new texture name.
- mCubemapTextures[index].free();
- // Skip empty stages or ones with variable or target names.
- if (cubemapHandle.isNull())
- return;
- // Try to load the texture.
- mCubemapTextures[index] = cubemapHandle;
- mTextureType[index] = CubemapType;
- }
- void PostEffect::setCubemapArrayTexture(U32 index, const GFXCubemapArrayHandle &cubemapArrayHandle)
- {
- // Set the new texture name.
- mCubemapArrayTextures[index].free();
- // Skip empty stages or ones with variable or target names.
- if (cubemapArrayHandle.isNull())
- return;
- // Try to load the texture.
- mCubemapArrayTextures[index] = cubemapArrayHandle;
- mTextureType[index] = CubemapArrayType;
- }
- void PostEffect::setShaderConst( const String &name, const String &val )
- {
- PROFILE_SCOPE( PostEffect_SetShaderConst );
- EffectConstTable::Iterator iter = mEffectConsts.find( name );
- if ( iter == mEffectConsts.end() )
- {
- EffectConst *newConst = new EffectConst( name, val );
- iter = mEffectConsts.insertUnique( name, newConst );
- }
- iter->value->set( val );
- }
- void PostEffect::setShaderConst(const String &name, const F32 &val)
- {
- PROFILE_SCOPE(PostEffect_SetShaderConst_Float);
- EffectConstTable::Iterator iter = mEffectConsts.find(name);
- if (iter == mEffectConsts.end())
- {
- EffectConst *newConst = new EffectConst(name, val);
- iter = mEffectConsts.insertUnique(name, newConst);
- }
- iter->value->set(val);
- }
- void PostEffect::setShaderConst(const String& name, const int& val)
- {
- PROFILE_SCOPE(PostEffect_SetShaderConst_Int);
- EffectConstTable::Iterator iter = mEffectConsts.find(name);
- if (iter == mEffectConsts.end())
- {
- EffectConst* newConst = new EffectConst(name, val);
- iter = mEffectConsts.insertUnique(name, newConst);
- }
- iter->value->set(val);
- }
- void PostEffect::setShaderConst(const String &name, const Point4F &val)
- {
- PROFILE_SCOPE(PostEffect_SetShaderConst_Point);
- EffectConstTable::Iterator iter = mEffectConsts.find(name);
- if (iter == mEffectConsts.end())
- {
- EffectConst *newConst = new EffectConst(name, val);
- iter = mEffectConsts.insertUnique(name, newConst);
- }
- iter->value->set(val);
- }
- void PostEffect::setShaderConst(const String &name, const MatrixF &val)
- {
- PROFILE_SCOPE(PostEffect_SetShaderConst_Matrix);
- EffectConstTable::Iterator iter = mEffectConsts.find(name);
- if (iter == mEffectConsts.end())
- {
- EffectConst *newConst = new EffectConst(name, val);
- iter = mEffectConsts.insertUnique(name, newConst);
- }
- iter->value->set(val);
- }
- void PostEffect::setShaderConst(const String &name, const Vector<Point4F> &val)
- {
- PROFILE_SCOPE(PostEffect_SetShaderConst_PointArray);
- EffectConstTable::Iterator iter = mEffectConsts.find(name);
- if (iter == mEffectConsts.end())
- {
- EffectConst *newConst = new EffectConst(name, val);
- iter = mEffectConsts.insertUnique(name, newConst);
- }
- iter->value->set(val);
- }
- void PostEffect::setShaderConst(const String &name, const Vector<MatrixF> &val)
- {
- PROFILE_SCOPE(PostEffect_SetShaderConst_MatrixArray);
- EffectConstTable::Iterator iter = mEffectConsts.find(name);
- if (iter == mEffectConsts.end())
- {
- EffectConst *newConst = new EffectConst(name, val);
- iter = mEffectConsts.insertUnique(name, newConst);
- }
- iter->value->set(val);
- }
- F32 PostEffect::getAspectRatio() const
- {
- const Point2I &rtSize = GFX->getActiveRenderTarget()->getSize();
- return (F32)rtSize.x / (F32)rtSize.y;
- }
- void PostEffect::_checkRequirements()
- {
- // This meets requirements if its shader loads
- // properly, we can find all the input textures,
- // and its formats are supported.
- mIsValid = false;
- mUpdateShader = false;
- mShader = NULL;
- mShaderConsts = NULL;
- EffectConstTable::Iterator iter = mEffectConsts.begin();
- for ( ; iter != mEffectConsts.end(); iter++ )
- {
- iter->value->mDirty = true;
- iter->value->mHandle = NULL;
- }
- // First make sure the target format is supported.
- if ( mNamedTarget.isRegistered() )
- {
- Vector<GFXFormat> formats;
- formats.push_back( mTargetFormat );
- GFXFormat format = GFX->selectSupportedFormat( &PostFxTargetProfile,
- formats,
- true,
- false,
- false );
-
- // If we didn't get our format out then its unsupported!
- if ( format != mTargetFormat )
- return;
- }
- // Gather macros specified on this PostEffect.
- Vector<GFXShaderMacro> macros( mShaderMacros );
- // Now check the input named targets and make sure
- // they exist... else we're invalid.
- for ( U32 i=0; i < NumTextures; i++ )
- {
- if (mTextureType[i] == NormalTextureType)
- {
- const String &texFilename = mTextureName[i];
- if (texFilename.isNotEmpty() && texFilename[0] == '#')
- {
- NamedTexTarget *namedTarget = NamedTexTarget::find(texFilename.c_str() + 1);
- if (!namedTarget)
- {
- return;
- }
- // Grab the macros for shader initialization.
- namedTarget->getShaderMacros(¯os);
- }
- }
- }
- // Finally find and load the shader.
- ShaderData *shaderData;
- if ( Sim::findObject( mShaderName, shaderData ) )
- if ( shaderData->getPixVersion() <= GFX->getPixelShaderVersion() )
- mShader = shaderData->getShader( macros );
- // If we didn't get a shader... we're done.
- if ( !mShader )
- return;
- // If we got here then we're valid.
- mIsValid = true;
- }
- bool PostEffect::dumpShaderDisassembly( String &outFilename ) const
- {
- String data;
- if ( !mShader || !mShader->getDisassembly( data ) )
- return false;
-
- outFilename = FS::MakeUniquePath( "", "ShaderDisassembly", "txt" );
- FileStream *fstream = FileStream::createAndOpen( outFilename, Torque::FS::File::Write );
- if ( !fstream )
- return false;
- fstream->write( data );
- fstream->close();
- delete fstream;
- return true;
- }
- SimSet* PostEffect::getSet() const
- {
- SimSet *set;
- if ( !Sim::findObject( "PFXSet", set ) )
- {
- set = new SimSet();
- set->registerObject( "PFXSet" );
- Sim::getRootGroup()->addObject( set );
- }
- return set;
- }
- void PostEffect::setShaderMacro( const String &name, const String &value )
- {
- // Check to see if we already have this macro.
- Vector<GFXShaderMacro>::iterator iter = mShaderMacros.begin();
- for ( ; iter != mShaderMacros.end(); iter++ )
- {
- if ( iter->name == name )
- {
- if ( iter->value != value )
- {
- iter->value = value;
- mUpdateShader = true;
- }
- return;
- }
- }
- // Add a new macro.
- mShaderMacros.increment();
- mShaderMacros.last().name = name;
- mShaderMacros.last().value = value;
- mUpdateShader = true;
- }
- bool PostEffect::removeShaderMacro( const String &name )
- {
- Vector<GFXShaderMacro>::iterator iter = mShaderMacros.begin();
- for ( ; iter != mShaderMacros.end(); iter++ )
- {
- if ( iter->name == name )
- {
- mShaderMacros.erase( iter );
- mUpdateShader = true;
- return true;
- }
- }
- return false;
- }
- void PostEffect::clearShaderMacros()
- {
- if ( mShaderMacros.empty() )
- return;
- mShaderMacros.clear();
- mUpdateShader = true;
- }
- GFXTextureObject* PostEffect::_getTargetTexture( U32 )
- {
- // A TexGen PostEffect will generate its texture now if it
- // has not already.
- if ( mRenderTime == PFXTexGenOnDemand &&
- ( !mTargetTex || mUpdateShader ) )
- {
- GFXTexHandle chainTex;
- process( NULL, chainTex );
-
- // TODO: We should add a conditional copy
- // to a non-RT texture here to reduce the
- // amount of non-swappable RTs in use.
- }
- return mTargetTex.getPointer();
- }
- DefineEngineMethod( PostEffect, reload, void, (),,
- "Reloads the effect shader and textures." )
- {
- return object->reload();
- }
- DefineEngineMethod( PostEffect, enable, void, (),,
- "Enables the effect." )
- {
- object->enable();
- }
- DefineEngineMethod( PostEffect, disable, void, (),,
- "Disables the effect." )
- {
- object->disable();
- }
- DefineEngineMethod( PostEffect, toggle, bool, (),,
- "Toggles the effect between enabled / disabled.\n"
- "@return True if effect is enabled." )
- {
- if ( object->isEnabled() )
- object->disable();
- else
- object->enable();
- return object->isEnabled();
- }
- DefineEngineMethod( PostEffect, isEnabled, bool, (),,
- "@return True if the effect is enabled." )
- {
- return object->isEnabled();
- }
- DefineEngineMethod( PostEffect, setTexture, void, ( S32 index, const char *filePath ),,
- "This is used to set the texture file and load the texture on a running effect. "
- "If the texture file is not different from the current file nothing is changed. If "
- "the texture cannot be found a null texture is assigned.\n"
- "@param index The texture stage index.\n"
- "@param filePath The file name of the texture to set.\n" )
- {
- if ( index > -1 && index < PostEffect::NumTextures )
- object->setTexture( index, filePath );
- }
- DefineEngineMethod( PostEffect, setShaderConst, void, ( const char* name, const char* value ),,
- "Sets the value of a uniform defined in the shader. This will usually "
- "be called within the setShaderConsts callback. Array type constants are "
- "not supported.\n"
- "@param name Name of the constanst, prefixed with '$'.\n"
- "@param value Value to set, space seperate values with more than one element.\n"
- "@tsexample\n"
- "function MyPfx::setShaderConsts( %this )\n"
- "{\n"
- " // example float4 uniform\n"
- " %this.setShaderConst( \"$colorMod\", \"1.0 0.9 1.0 1.0\" );\n"
- " // example float1 uniform\n"
- " %this.setShaderConst( \"$strength\", \"3.0\" );\n"
- " // example integer uniform\n"
- " %this.setShaderConst( \"$loops\", \"5\" );"
- "}\n"
- "@endtsexample" )
- {
- object->setShaderConst( name, value );
- }
- DefineEngineMethod( PostEffect, getAspectRatio, F32, (),,
- "@return Width over height of the backbuffer." )
- {
- return object->getAspectRatio();
- }
- DefineEngineMethod( PostEffect, dumpShaderDisassembly, String, (),,
- "Dumps this PostEffect shader's disassembly to a temporary text file.\n"
- "@return Full path to the dumped file or an empty string if failed." )
- {
- String fileName;
- object->dumpShaderDisassembly( fileName );
- return fileName;
- }
- DefineEngineMethod( PostEffect, setShaderMacro, void, ( const char* key, const char* value ), ( "" ),
- "Adds a macro to the effect's shader or sets an existing one's value. "
- "This will usually be called within the onAdd or preProcess callback.\n"
- "@param key lval of the macro."
- "@param value rval of the macro, or may be empty."
- "@tsexample\n"
- "function MyPfx::onAdd( %this )\n"
- "{\n"
- " %this.setShaderMacro( \"NUM_SAMPLES\", \"10\" );\n"
- " %this.setShaderMacro( \"HIGH_QUALITY_MODE\" );\n"
- " \n"
- " // In the shader looks like... \n"
- " // #define NUM_SAMPLES 10\n"
- " // #define HIGH_QUALITY_MODE\n"
- "}\n"
- "@endtsexample" )
- {
- object->setShaderMacro( key, value );
- }
- DefineEngineMethod( PostEffect, removeShaderMacro, void, ( const char* key ),,
- "Remove a shader macro. This will usually be called within the preProcess callback.\n"
- "@param key Macro to remove." )
- {
- object->removeShaderMacro( key );
- }
- DefineEngineMethod( PostEffect, clearShaderMacros, void, (),,
- "Remove all shader macros." )
- {
- object->clearShaderMacros();
- }
- DefineEngineFunction( dumpRandomNormalMap, void, (),,
- "Creates a 64x64 normal map texture filled with noise. The texture is saved "
- "to randNormTex.png in the location of the game executable.\n\n"
- "@ingroup GFX")
- {
- GFXTexHandle tex;
- tex.set( 64, 64, GFXFormatR8G8B8A8, &GFXTexturePersistentProfile, "" );
- GFXLockedRect *rect = tex.lock();
- U8 *f = rect->bits;
- for ( U32 i = 0; i < 64*64; i++, f += 4 )
- {
- VectorF vec;
- vec.x = mRandF( -1.0f, 1.0f );
- vec.y = mRandF( -1.0f, 1.0f );
- vec.z = mRandF( -1.0f, 1.0f );
- vec.normalizeSafe();
- f[0] = U8_MAX * ( ( 1.0f + vec.x ) * 0.5f );
- f[1] = U8_MAX * ( ( 1.0f + vec.y ) * 0.5f );
- f[2] = U8_MAX * ( ( 1.0f + vec.z ) * 0.5f );
- f[3] = U8_MAX;
- }
- tex.unlock();
- String path = Torque::FS::MakeUniquePath( "", "randNormTex", "png" );
- tex->dumpToDisk( "png", path );
- }
|