1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119 |
- //-----------------------------------------------------------------------------
- // 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 ),
- 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" );
- 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() );
- // 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 );
- }
|