123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728 |
- //-----------------------------------------------------------------------------
- // 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( 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;
- }
- 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();
- 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
- }
- }
- //-------------------------------------------------------------------------
- // 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( ColorF::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 )
- {
- 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 );
- }
- 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." );
- addField( "texture", TypeImageFilename, Offset( mTexFilename, PostEffect ), NumTextures,
- "Input textures to this effect ( samplers ).\n"
- "@see PFXTextureIdentifiers" );
- 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( "isEnabled", 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++ )
- {
- String texFilename = mTexFilename[i];
- // Skip empty stages or ones with variable or target names.
- if ( texFilename.isEmpty() ||
- texFilename[0] == '$' ||
- texFilename[0] == '#' )
- continue;
- // Try to load the texture.
- bool success = mTextures[i].set( texFilename, &PostFxTextureProfile, avar( "%s() - (line %d)", __FUNCTION__, __LINE__ ) );
- if (!success)
- Con::errorf("Invalid Texture for PostEffect (%s), The Texture '%s' does not exist!", this->getName(), texFilename.c_str());
- }
- // 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" );
- mTexSizeSC[0] = mShader->getShaderConstHandle( "$texSize0" );
- mTexSizeSC[1] = mShader->getShaderConstHandle( "$texSize1" );
- mTexSizeSC[2] = mShader->getShaderConstHandle( "$texSize2" );
- mTexSizeSC[3] = mShader->getShaderConstHandle( "$texSize3" );
- mTexSizeSC[4] = mShader->getShaderConstHandle( "$texSize4" );
- mTexSizeSC[5] = mShader->getShaderConstHandle( "$texSize5" );
- mTexSizeSC[6] = mShader->getShaderConstHandle( "$texSize6" );
- mTexSizeSC[7] = mShader->getShaderConstHandle( "$texSize7" );
- mRenderTargetParamsSC[0] = mShader->getShaderConstHandle( "$rtParams0" );
- mRenderTargetParamsSC[1] = mShader->getShaderConstHandle( "$rtParams1" );
- mRenderTargetParamsSC[2] = mShader->getShaderConstHandle( "$rtParams2" );
- mRenderTargetParamsSC[3] = mShader->getShaderConstHandle( "$rtParams3" );
- mRenderTargetParamsSC[4] = mShader->getShaderConstHandle( "$rtParams4" );
- mRenderTargetParamsSC[5] = mShader->getShaderConstHandle( "$rtParams5" );
- mRenderTargetParamsSC[6] = mShader->getShaderConstHandle( "$rtParams6" );
- mRenderTargetParamsSC[7] = mShader->getShaderConstHandle( "$rtParams7" );
- //mViewportSC = shader->getShaderConstHandle( "$viewport" );
- 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" );
- }
- // 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 );
- }
- // 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 );
- const bool hasTexelPixelOffset = GFX->getAdapterType() == Direct3D9;
- const Point2F halfPixel( hasTexelPixelOffset ? (0.5f / targetSize.x) : 0.0f,
- hasTexelPixelOffset ? (0.5f / targetSize.y) : 0.0f );
- Point4F targetParams;
- targetParams.x = offset.x + halfPixel.x;
- targetParams.y = offset.y + halfPixel.y;
- targetParams.z = offset.x + scale.x - halfPixel.x;
- targetParams.w = offset.y + scale.y - halfPixel.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 ColorF &sunlight = state->getAmbientLightColor();
- Point3F ambientColor( sunlight.red, sunlight.green, sunlight.blue );
- mShaderConsts->set( mAmbientColorSC, ambientColor );
- }
- 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() )
- {
- ColorF 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 = mTexFilename[ 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 = mTextures[ 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::_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,
- &GFXDefaultZTargetProfile, "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++ )
- _setupTexture( i, inOutTex, inTexViewport );
- _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.
- mTexFilename[index] = texFilePath;
- mTextures[index].free();
- // Skip empty stages or ones with variable or target names.
- if ( texFilePath.isEmpty() ||
- texFilePath[0] == '$' ||
- texFilePath[0] == '#' )
- return;
- // Try to load the texture.
- mTextures[index].set( texFilePath, &PostFxTextureProfile, avar( "%s() - (line %d)", __FUNCTION__, __LINE__ ) );
- }
- 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 );
- }
- 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++ )
- {
- const String &texFilename = mTexFilename[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, &GFXDefaultPersistentProfile, "" );
- 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 );
- }
|