postEffect.cpp

Engine/source/postFx/postEffect.cpp

More...

Public Variables

Public Functions

ConsoleDocClass(PostEffect , "@brief A fullscreen shader <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">effect.\n\n</a>" "@section <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PFXTextureIdentifiers\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Rendering\n</a>" )
DefineEngineFunction(dumpRandomNormalMap , void , () , "Creates <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> 64x64 normal map texture filled with noise. The texture is saved " "<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> randNormTex.png in the location of the game <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">executable.\n\n</a>" "@ingroup <a href="/coding/file/gfxdevice_8h/#gfxdevice_8h_1afd23debb5edac4f53e564f02e6964c62">GFX</a>" )
DefineEngineMethod(PostEffect , clearShaderMacros , void , () , "Remove all shader macros." )
DefineEngineMethod(PostEffect , disable , void , () , "Disables the effect." )
DefineEngineMethod(PostEffect , dumpShaderDisassembly , String , () , "Dumps this <a href="/coding/class/classposteffect/">PostEffect</a> shader's disassembly <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> temporary text <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">file.\n</a>" "@return Full path <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the dumped <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> or an empty string <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> failed." )
DefineEngineMethod(PostEffect , enable , void , () , "Enables the effect." )
DefineEngineMethod(PostEffect , getAspectRatio , F32 , () , "@return Width over height of the backbuffer." )
DefineEngineMethod(PostEffect , isEnabled , bool , () , "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the effect is enabled." )
DefineEngineMethod(PostEffect , reload , void , () , "Reloads the effect shader and textures." )
DefineEngineMethod(PostEffect , removeShaderMacro , void , (const char *key) , "Remove <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> shader macro. This will usually be called within the preProcess <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">callback.\n</a>" "@param key Macro <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> remove." )
DefineEngineMethod(PostEffect , setShaderConst , void , (const char *name, const char *value) , "Sets the <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> uniform defined in the shader. This will usually " "be called within the setShaderConsts callback. <a href="/coding/file/platformmemory_8cpp/#platformmemory_8cpp_1a3ffd6d180bfa999dfbafef07fab77f2caf8303e03242532eebd970f40ee509689">Array</a> type constants are " "not <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">supported.\n</a>" "@param name Name of the constanst, prefixed with '$'.\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @param <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> <a href="/coding/file/document_8h/#document_8h_1a071cf97155ba72ac9a1fc4ad7e63d481">Value</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> set, space seperate values with more than one <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">element.\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "function MyPfx::setShaderConsts(%this)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "//example float4 <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">uniform\n</a>" " %this.setShaderConst(\"$colorMod\", \"1.0 0.9 1.0 1.0\" );\n" "   // example float1 <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">uniform\n</a>" "   %this.setShaderConst( \"$strength\", \"3.0\" );\n" "   // example integer <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">uniform\n</a>" "   %this.setShaderConst( \"$loops\", \"5\" );" "}\n" "@endtsexample" )
DefineEngineMethod(PostEffect , setShaderMacro , void , (const char *key, const char *value) , ("") , "Adds <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> macro <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the effect's shader or sets an existing one's value. " "This will usually be called within the onAdd or preProcess <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">callback.\n</a>" "@param key lval of the macro." "@param <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> rval of the macro, or may be empty." " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "function MyPfx::onAdd(%this)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " %this.setShaderMacro(\"NUM_SAMPLES\", \"10\" );\n" "   %this.setShaderMacro( \"HIGH_QUALITY_MODE\" );\n" "   \<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   // In the shader looks like... \<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   // #define NUM_SAMPLES 10\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   // #define <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">HIGH_QUALITY_MODE\n</a>" "}\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@endtsexample" )
DefineEngineMethod(PostEffect , setTexture , void , (S32 index, const char *filePath) , "This is used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> set the texture <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> and load the texture on <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> running effect. " "If the texture <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> is not different from the current <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> nothing is changed. If " "the texture cannot be found <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> null texture is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">assigned.\n</a>" "@param index The texture stage <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">index.\n</a>" "@param filePath The <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> name of the texture <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">set.\n</a>" )
DefineEngineMethod(PostEffect , toggle , bool , () , "Toggles the effect between enabled / <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">disabled.\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> effect is enabled." )
IMPLEMENT_CALLBACK(PostEffect , onAdd , void , () , () , "Called when this object is first created and registered." )
IMPLEMENT_CALLBACK(PostEffect , onDisabled , void , () , () , "Called when this effect becomes disabled." )
IMPLEMENT_CALLBACK(PostEffect , onEnabled , bool , () , () , "Called when this effect becomes enabled. If the user returns false from " "this callback the effect will not be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">enabled.\n</a>" "@return True <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> allow this effect <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be enabled." )
IMPLEMENT_CALLBACK(PostEffect , preProcess , void , () , () , "Called when an effect is processed but before textures are bound. This " "allows the user <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> change texture related paramaters or macros at <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">runtime.\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "function SSAOPostFx::preProcess( %this )\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> ( $SSAOPostFx::quality !$= %this.quality )\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "      %this.quality = <a href="/coding/file/mmathfn_8h/#mmathfn_8h_1a65728120acb10c58cf049e176e3b0011">mClamp</a>( <a href="/coding/file/mmathfn_8h/#mmathfn_8h_1abef53d0a7c27cf32f96fba1d65e25fed">mRound</a>( $SSAOPostFx::quality ), 0, 2 );\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "      \<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "      %this.setShaderMacro( \"QUALITY\", %this.quality );\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   }\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   %this.targetScale = $SSAOPostFx::targetScale;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "}\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">setShaderConst\n</a>" "@see setShaderMacro" )
IMPLEMENT_CALLBACK(PostEffect , setShaderConsts , void , () , () , "Called immediate before processing this effect. This is the user's chance " "<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> set the <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> of shader uniforms (constants).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@see setShaderConst" )
ImplementEnumType(PFXRenderTime , "When <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> process this effect during the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">frame.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Rendering\n\n</a>" )
ImplementEnumType(PFXTargetClear , "Describes when the target texture should be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">cleared\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Rendering\n\n</a>" )
ImplementEnumType(PFXTargetViewport , "Specifies how the viewport should be set up <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classposteffect/">PostEffect</a>'s <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">target.\n</a>" "@note Applies <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> both the diffuse target and the depth target (<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> defined).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Rendering\n\n</a>" )

Detailed Description

Public Variables

 EndImplementEnumType 

Public Functions

ConsoleDocClass(PostEffect , "@brief A fullscreen shader <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">effect.\n\n</a>" "@section <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PFXTextureIdentifiers\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Rendering\n</a>" )

DefineEngineFunction(dumpRandomNormalMap , void , () , "Creates <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> 64x64 normal map texture filled with noise. The texture is saved " "<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> randNormTex.png in the location of the game <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">executable.\n\n</a>" "@ingroup <a href="/coding/file/gfxdevice_8h/#gfxdevice_8h_1afd23debb5edac4f53e564f02e6964c62">GFX</a>" )

DefineEngineMethod(PostEffect , clearShaderMacros , void , () , "Remove all shader macros." )

DefineEngineMethod(PostEffect , disable , void , () , "Disables the effect." )

DefineEngineMethod(PostEffect , dumpShaderDisassembly , String , () , "Dumps this <a href="/coding/class/classposteffect/">PostEffect</a> shader's disassembly <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> temporary text <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">file.\n</a>" "@return Full path <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the dumped <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> or an empty string <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> failed." )

DefineEngineMethod(PostEffect , enable , void , () , "Enables the effect." )

DefineEngineMethod(PostEffect , getAspectRatio , F32 , () , "@return Width over height of the backbuffer." )

DefineEngineMethod(PostEffect , isEnabled , bool , () , "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the effect is enabled." )

DefineEngineMethod(PostEffect , reload , void , () , "Reloads the effect shader and textures." )

DefineEngineMethod(PostEffect , removeShaderMacro , void , (const char *key) , "Remove <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> shader macro. This will usually be called within the preProcess <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">callback.\n</a>" "@param key Macro <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> remove." )

DefineEngineMethod(PostEffect , setShaderConst , void , (const char *name, const char *value) , "Sets the <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> uniform defined in the shader. This will usually " "be called within the setShaderConsts callback. <a href="/coding/file/platformmemory_8cpp/#platformmemory_8cpp_1a3ffd6d180bfa999dfbafef07fab77f2caf8303e03242532eebd970f40ee509689">Array</a> type constants are " "not <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">supported.\n</a>" "@param name Name of the constanst, prefixed with '$'.\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @param <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> <a href="/coding/file/document_8h/#document_8h_1a071cf97155ba72ac9a1fc4ad7e63d481">Value</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> set, space seperate values with more than one <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">element.\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "function MyPfx::setShaderConsts(%this)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "//example float4 <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">uniform\n</a>" " %this.setShaderConst(\"$colorMod\", \"1.0 0.9 1.0 1.0\" );\n" "   // example float1 <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">uniform\n</a>" "   %this.setShaderConst( \"$strength\", \"3.0\" );\n" "   // example integer <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">uniform\n</a>" "   %this.setShaderConst( \"$loops\", \"5\" );" "}\n" "@endtsexample" )

DefineEngineMethod(PostEffect , setShaderMacro , void , (const char *key, const char *value) , ("") , "Adds <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> macro <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the effect's shader or sets an existing one's value. " "This will usually be called within the onAdd or preProcess <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">callback.\n</a>" "@param key lval of the macro." "@param <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> rval of the macro, or may be empty." " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "function MyPfx::onAdd(%this)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " %this.setShaderMacro(\"NUM_SAMPLES\", \"10\" );\n" "   %this.setShaderMacro( \"HIGH_QUALITY_MODE\" );\n" "   \<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   // In the shader looks like... \<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   // #define NUM_SAMPLES 10\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   // #define <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">HIGH_QUALITY_MODE\n</a>" "}\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@endtsexample" )

DefineEngineMethod(PostEffect , setTexture , void , (S32 index, const char *filePath) , "This is used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> set the texture <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> and load the texture on <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> running effect. " "If the texture <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> is not different from the current <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> nothing is changed. If " "the texture cannot be found <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> null texture is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">assigned.\n</a>" "@param index The texture stage <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">index.\n</a>" "@param filePath The <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> name of the texture <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">set.\n</a>" )

DefineEngineMethod(PostEffect , toggle , bool , () , "Toggles the effect between enabled / <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">disabled.\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> effect is enabled." )

GFX_ImplementTextureProfile(PostFxTargetProfile , GFXTextureProfile::DiffuseMap , GFXTextureProfile::PreserveSize</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82da75302d480adb239daa0dd3fec9fd7a0b">GFXTextureProfile::RenderTarget</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82da8e64fa44eaa9b6444614dac7bdb1dcf8">GFXTextureProfile::Pooled , GFXTextureProfile::NONE )

GFX_ImplementTextureProfile(PostFxTextureProfile , GFXTextureProfile::DiffuseMap , GFXTextureProfile::Static</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82dac429cfe8dbe343378e106bc721fc96c8">GFXTextureProfile::PreserveSize</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82daf55b13e32bd1a1746406b68ead73ba05">GFXTextureProfile::NoMipmap , GFXTextureProfile::NONE )

GFX_ImplementTextureProfile(PostFxTextureSRGBProfile , GFXTextureProfile::DiffuseMap , GFXTextureProfile::Static</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82dac429cfe8dbe343378e106bc721fc96c8">GFXTextureProfile::PreserveSize</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82daf55b13e32bd1a1746406b68ead73ba05">GFXTextureProfile::NoMipmap</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82daf6773a6da8ddf28520016603401b8f23">GFXTextureProfile::SRGB , GFXTextureProfile::NONE )

GFX_ImplementTextureProfile(VRDepthProfile , GFXTextureProfile::DiffuseMap , GFXTextureProfile::PreserveSize</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82daf55b13e32bd1a1746406b68ead73ba05">GFXTextureProfile::NoMipmap</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82daa3a2027753aec009ced4f0818a231296">GFXTextureProfile::ZTarget , GFXTextureProfile::NONE )

GFX_ImplementTextureProfile(VRTextureProfile , GFXTextureProfile::DiffuseMap , GFXTextureProfile::PreserveSize</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82da75302d480adb239daa0dd3fec9fd7a0b">GFXTextureProfile::RenderTarget</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82daf55b13e32bd1a1746406b68ead73ba05">GFXTextureProfile::NoMipmap , GFXTextureProfile::NONE )

GFXImplementVertexFormat(PFXVertex )

IMPLEMENT_CALLBACK(PostEffect , onAdd , void , () , () , "Called when this object is first created and registered." )

IMPLEMENT_CALLBACK(PostEffect , onDisabled , void , () , () , "Called when this effect becomes disabled." )

IMPLEMENT_CALLBACK(PostEffect , onEnabled , bool , () , () , "Called when this effect becomes enabled. If the user returns false from " "this callback the effect will not be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">enabled.\n</a>" "@return True <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> allow this effect <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be enabled." )

IMPLEMENT_CALLBACK(PostEffect , preProcess , void , () , () , "Called when an effect is processed but before textures are bound. This " "allows the user <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> change texture related paramaters or macros at <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">runtime.\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "function SSAOPostFx::preProcess( %this )\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> ( $SSAOPostFx::quality !$= %this.quality )\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "      %this.quality = <a href="/coding/file/mmathfn_8h/#mmathfn_8h_1a65728120acb10c58cf049e176e3b0011">mClamp</a>( <a href="/coding/file/mmathfn_8h/#mmathfn_8h_1abef53d0a7c27cf32f96fba1d65e25fed">mRound</a>( $SSAOPostFx::quality ), 0, 2 );\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "      \<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "      %this.setShaderMacro( \"QUALITY\", %this.quality );\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   }\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   %this.targetScale = $SSAOPostFx::targetScale;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "}\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">setShaderConst\n</a>" "@see setShaderMacro" )

IMPLEMENT_CALLBACK(PostEffect , setShaderConsts , void , () , () , "Called immediate before processing this effect. This is the user's chance " "<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> set the <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> of shader uniforms (constants).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@see setShaderConst" )

IMPLEMENT_CONOBJECT(PostEffect )

ImplementEnumType(PFXRenderTime , "When <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> process this effect during the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">frame.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Rendering\n\n</a>" )

ImplementEnumType(PFXTargetClear , "Describes when the target texture should be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">cleared\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Rendering\n\n</a>" )

ImplementEnumType(PFXTargetViewport , "Specifies how the viewport should be set up <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classposteffect/">PostEffect</a>'s <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">target.\n</a>" "@note Applies <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> both the diffuse target and the depth target (<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> defined).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Rendering\n\n</a>" )

   1
   2//-----------------------------------------------------------------------------
   3// Copyright (c) 2012 GarageGames, LLC
   4//
   5// Permission is hereby granted, free of charge, to any person obtaining a copy
   6// of this software and associated documentation files (the "Software"), to
   7// deal in the Software without restriction, including without limitation the
   8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
   9// sell copies of the Software, and to permit persons to whom the Software is
  10// furnished to do so, subject to the following conditions:
  11//
  12// The above copyright notice and this permission notice shall be included in
  13// all copies or substantial portions of the Software.
  14//
  15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21// IN THE SOFTWARE.
  22//-----------------------------------------------------------------------------
  23
  24#include "platform/platform.h"
  25#include "postFx/postEffect.h"
  26
  27#include "console/engineAPI.h"
  28#include "core/stream/fileStream.h"
  29#include "core/strings/stringUnit.h"
  30#include "console/consoleTypes.h"
  31#include "console/engineAPI.h"
  32#include "math/util/frustum.h"
  33#include "math/mathUtils.h"
  34#include "gfx/gfxTransformSaver.h"
  35#include "gfx/gfxStringEnumTranslate.h"
  36#include "gfx/gfxTextureManager.h"
  37#include "gfx/gfxDebugEvent.h"
  38#include "gfx/util/screenspace.h"
  39#include "gfx/sim/gfxStateBlockData.h"
  40#include "scene/sceneRenderState.h"
  41#include "shaderGen/shaderGenVars.h"
  42#include "lighting/lightInfo.h"
  43#include "lighting/lightManager.h"
  44#include "materials/materialManager.h"
  45#include "materials/shaderData.h"
  46#include "postFx/postEffectManager.h"
  47#include "postFx/postEffectVis.h"
  48
  49using namespace Torque;
  50
  51ConsoleDocClass( PostEffect, 
  52   "@brief A fullscreen shader effect.\n\n"
  53
  54   "@section PFXTextureIdentifiers\n\n"   
  55
  56   "@ingroup Rendering\n"
  57);
  58
  59IMPLEMENT_CALLBACK( PostEffect, onAdd, void, (), (),
  60   "Called when this object is first created and registered."
  61);
  62
  63IMPLEMENT_CALLBACK( PostEffect, preProcess, void, (), (),
  64   "Called when an effect is processed but before textures are bound. This "
  65   "allows the user to change texture related paramaters or macros at runtime.\n"
  66   "@tsexample\n"   
  67   "function SSAOPostFx::preProcess( %this )\n"
  68   "{\n"   
  69   "   if ( $SSAOPostFx::quality !$= %this.quality )\n"
  70   "   {\n"
  71   "      %this.quality = mClamp( mRound( $SSAOPostFx::quality ), 0, 2 );\n"
  72   "      \n"         
  73   "      %this.setShaderMacro( \"QUALITY\", %this.quality );\n"
  74   "   }\n"     
  75   "   %this.targetScale = $SSAOPostFx::targetScale;\n"
  76   "}\n"
  77   "@endtsexample\n"
  78   "@see setShaderConst\n"
  79   "@see setShaderMacro"
  80);
  81
  82IMPLEMENT_CALLBACK( PostEffect, setShaderConsts, void, (), (),
  83   "Called immediate before processing this effect. This is the user's chance "
  84   "to set the value of shader uniforms (constants).\n"
  85   "@see setShaderConst"
  86);
  87
  88IMPLEMENT_CALLBACK( PostEffect, onEnabled, bool, (), (),
  89   "Called when this effect becomes enabled. If the user returns false from "
  90   "this callback the effect will not be enabled.\n"
  91   "@return True to allow this effect to be enabled."
  92);
  93
  94IMPLEMENT_CALLBACK( PostEffect, onDisabled, void, (), (),
  95   "Called when this effect becomes disabled."
  96);
  97
  98ImplementEnumType( PFXRenderTime,
  99   "When to process this effect during the frame.\n"
 100   "@ingroup Rendering\n\n")
 101   { PFXBeforeBin, "PFXBeforeBin", "Before a RenderInstManager bin.\n" },
 102   { PFXAfterBin, "PFXAfterBin", "After a RenderInstManager bin.\n" },
 103   { PFXAfterDiffuse, "PFXAfterDiffuse", "After the diffuse rendering pass.\n" },
 104   { PFXEndOfFrame, "PFXEndOfFrame", "When the end of the frame is reached.\n" },
 105   { PFXTexGenOnDemand, "PFXTexGenOnDemand", "This PostEffect is not processed by the manager. It will generate its texture when it is requested.\n" }
 106EndImplementEnumType;
 107
 108ImplementEnumType( PFXTargetClear,
 109   "Describes when the target texture should be cleared\n"
 110   "@ingroup Rendering\n\n")
 111   { PFXTargetClear_None, "PFXTargetClear_None", "Never clear the PostEffect target.\n" },
 112   { PFXTargetClear_OnCreate, "PFXTargetClear_OnCreate", "Clear once on create.\n" },
 113   { PFXTargetClear_OnDraw, "PFXTargetClear_OnDraw", "Clear before every draw.\n" },
 114EndImplementEnumType;
 115
 116ImplementEnumType( PFXTargetViewport,
 117   "Specifies how the viewport should be set up for a PostEffect's target.\n"
 118   "@note Applies to both the diffuse target and the depth target (if defined).\n"
 119   "@ingroup Rendering\n\n")
 120   { PFXTargetViewport_TargetSize, "PFXTargetViewport_TargetSize", "Set viewport to match target size (default).\n" },
 121   { PFXTargetViewport_GFXViewport, "PFXTargetViewport_GFXViewport", "Use the current GFX viewport (scaled to match target size).\n" },
 122   { 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" },
 123EndImplementEnumType;
 124
 125
 126GFXImplementVertexFormat( PFXVertex )
 127{
 128   addElement( "POSITION", GFXDeclType_Float3 );
 129   addElement( "TEXCOORD", GFXDeclType_Float2, 0 );
 130   addElement( "TEXCOORD", GFXDeclType_Float3, 1 );
 131};
 132
 133GFX_ImplementTextureProfile(  PostFxTargetProfile,
 134                              GFXTextureProfile::DiffuseMap,
 135                              GFXTextureProfile::PreserveSize |
 136                              GFXTextureProfile::RenderTarget |
 137                              GFXTextureProfile::Pooled,
 138                              GFXTextureProfile::NONE );
 139
 140IMPLEMENT_CONOBJECT(PostEffect);
 141
 142
 143GFX_ImplementTextureProfile( PostFxTextureProfile,
 144                            GFXTextureProfile::DiffuseMap,
 145                            GFXTextureProfile::Static | GFXTextureProfile::PreserveSize | GFXTextureProfile::NoMipmap,
 146                            GFXTextureProfile::NONE );
 147
 148GFX_ImplementTextureProfile( PostFxTextureSRGBProfile,
 149                             GFXTextureProfile::DiffuseMap,
 150                             GFXTextureProfile::Static | GFXTextureProfile::PreserveSize | GFXTextureProfile::NoMipmap | GFXTextureProfile::SRGB,
 151                             GFXTextureProfile::NONE);
 152
 153GFX_ImplementTextureProfile( VRTextureProfile,
 154                            GFXTextureProfile::DiffuseMap,
 155                            GFXTextureProfile::PreserveSize |
 156                            GFXTextureProfile::RenderTarget |
 157                            GFXTextureProfile::NoMipmap,
 158                            GFXTextureProfile::NONE );
 159
 160GFX_ImplementTextureProfile( VRDepthProfile,
 161                            GFXTextureProfile::DiffuseMap,
 162                            GFXTextureProfile::PreserveSize |
 163                            GFXTextureProfile::NoMipmap |
 164                            GFXTextureProfile::ZTarget,
 165                            GFXTextureProfile::NONE );
 166
 167void PostEffect::EffectConst::set( const String &newVal )
 168{
 169   if ( mStringVal == newVal )
 170      return;
 171
 172   mStringVal = newVal;
 173   mDirty = true;
 174   mValueType = StringType;
 175}
 176
 177void PostEffect::EffectConst::set(const F32 &newVal)
 178{
 179   if (mFloatVal == newVal)
 180      return;
 181
 182   mFloatVal = newVal;
 183   mDirty = true;
 184   mValueType = FloatType;
 185}
 186
 187void PostEffect::EffectConst::set(const int& newVal)
 188{
 189   if (mIntVal == newVal)
 190      return;
 191
 192   mIntVal = newVal;
 193   mDirty = true;
 194   mValueType = IntType;
 195}
 196
 197void PostEffect::EffectConst::set(const Point4F &newVal)
 198{
 199   if (mPointVal == newVal)
 200      return;
 201
 202   mPointVal = newVal;
 203   mDirty = true;
 204   mValueType = PointType;
 205}
 206
 207void PostEffect::EffectConst::set(const MatrixF &newVal)
 208{
 209   if (mMatrixVal == newVal)
 210      return;
 211
 212   mMatrixVal = newVal;
 213   mDirty = true;
 214   mValueType = MatrixType;
 215}
 216
 217void PostEffect::EffectConst::set(const Vector<Point4F> &newVal)
 218{
 219   //if (mPointArrayVal == newVal)
 220   //   return;
 221
 222   mPointArrayVal = newVal;
 223   mDirty = true;
 224   mValueType = PointArrayType;
 225}
 226
 227void PostEffect::EffectConst::set(const Vector<MatrixF> &newVal)
 228{
 229   //if (mMatrixArrayVal == newVal)
 230   //   return;
 231
 232   mMatrixArrayVal = newVal;
 233   mDirty = true;
 234   mValueType = MatrixArrayType;
 235}
 236
 237void PostEffect::EffectConst::setToBuffer( GFXShaderConstBufferRef buff )
 238{
 239   // Nothing to do if the value hasn't changed.
 240   if ( !mDirty )
 241      return;
 242   mDirty = false;
 243
 244   // If we don't have a handle... get it now.
 245   if ( !mHandle )
 246      mHandle = buff->getShader()->getShaderConstHandle( mName );
 247
 248   // If the handle isn't valid then we're done.
 249   if ( !mHandle->isValid() )
 250      return;
 251
 252   const GFXShaderConstType type = mHandle->getType();
 253
 254   // For now, we're only going
 255   // to support float4 arrays.
 256   // Expand to other types as necessary.
 257   U32 arraySize = mHandle->getArraySize();
 258
 259   if (mValueType == StringType)
 260   {
 261      const char *strVal = mStringVal.c_str();
 262
 263      if (type == GFXSCT_Int)
 264      {
 265         S32 val;
 266         Con::setData(TypeS32, &val, 0, 1, &strVal);
 267         buff->set(mHandle, val);
 268      }
 269      else if (type == GFXSCT_Float)
 270      {
 271         F32 val;
 272         Con::setData(TypeF32, &val, 0, 1, &strVal);
 273         buff->set(mHandle, val);
 274      }
 275      else if (type == GFXSCT_Float2)
 276      {
 277         Point2F val;
 278         Con::setData(TypePoint2F, &val, 0, 1, &strVal);
 279         buff->set(mHandle, val);
 280      }
 281      else if (type == GFXSCT_Float3)
 282      {
 283         Point3F val;
 284         Con::setData(TypePoint3F, &val, 0, 1, &strVal);
 285         buff->set(mHandle, val);
 286      }
 287      else if (type == GFXSCT_Float4)
 288      {
 289         Point4F val;
 290
 291         if (arraySize > 1)
 292         {
 293            // Do array setup!
 294            //U32 unitCount = StringUnit::getUnitCount( strVal, "\t" );
 295            //AssertFatal( unitCount == arraySize, "" );
 296
 297            String tmpString;
 298            Vector<Point4F> valArray;
 299
 300            for (U32 i = 0; i < arraySize; i++)
 301            {
 302               tmpString = StringUnit::getUnit(strVal, i, "\t");
 303               valArray.increment();
 304               const char *tmpCStr = tmpString.c_str();
 305
 306               Con::setData(TypePoint4F, &valArray.last(), 0, 1, &tmpCStr);
 307            }
 308
 309            AlignedArray<Point4F> rectData(valArray.size(), sizeof(Point4F), (U8*)valArray.address(), false);
 310            buff->set(mHandle, rectData);
 311         }
 312         else
 313         {
 314            // Do regular setup.
 315            Con::setData(TypePoint4F, &val, 0, 1, &strVal);
 316            buff->set(mHandle, val);
 317         }
 318      }
 319      else
 320      {
 321#if TORQUE_DEBUG
 322         const char* err = avar("PostEffect::EffectConst::setToBuffer $s type is not implemented", mName.c_str());
 323         Con::errorf(err);
 324         GFXAssertFatal(0, err);
 325#endif
 326      }
 327   }
 328   else if (mValueType == FloatType)
 329   {
 330      if (type == GFXSCT_Float)
 331      {
 332         buff->set(mHandle, mFloatVal);
 333      }
 334      else
 335      {
 336#if TORQUE_DEBUG
 337         const char* err = avar("PostEffect::EffectConst::setToBuffer $s type is not implemented", mName.c_str());
 338         Con::errorf(err);
 339         GFXAssertFatal(0, err);
 340#endif
 341      }
 342   }
 343   else if (mValueType == IntType)
 344   {
 345      if (type == GFXSCT_Int)
 346      {
 347         buff->set(mHandle, mIntVal);
 348      }
 349      else
 350      {
 351#if TORQUE_DEBUG
 352         const char* err = avar("PostEffect::EffectConst::setToBuffer $s type is not implemented", mName.c_str());
 353         Con::errorf(err);
 354         GFXAssertFatal(0, err);
 355#endif
 356      }
 357   }
 358   else if (mValueType == PointType)
 359   {
 360      if (type == GFXSCT_Float2)
 361      {
 362         buff->set(mHandle, Point2F(mPointVal.x, mPointVal.y));
 363      }
 364      else if (type == GFXSCT_Float3)
 365      {
 366         buff->set(mHandle, Point3F(mPointVal.x, mPointVal.y, mPointVal.z));
 367      }
 368      else if (type == GFXSCT_Float4)
 369      {
 370         buff->set(mHandle, mPointVal);
 371      }
 372      else
 373      {
 374#if TORQUE_DEBUG
 375         const char* err = avar("PostEffect::EffectConst::setToBuffer $s type is not implemented", mName.c_str());
 376         Con::errorf(err);
 377         GFXAssertFatal(0, err);
 378#endif
 379      }
 380   }
 381   else if (mValueType == MatrixType)
 382   {
 383      if (type == GFXSCT_Float4x4)
 384      {
 385         buff->set(mHandle, mMatrixVal);
 386      }
 387      else
 388      {
 389   #if TORQUE_DEBUG
 390         const char* err = avar("PostEffect::EffectConst::setToBuffer $s type is not implemented", mName.c_str());
 391         Con::errorf(err);
 392         GFXAssertFatal(0, err);
 393   #endif
 394      }
 395   }
 396   else if (mValueType == PointArrayType)
 397   {
 398      if (type == GFXSCT_Float4)
 399      {
 400         if (arraySize != mPointArrayVal.size())
 401         {
 402         #if TORQUE_DEBUG
 403            const char* err = avar("PostEffect::EffectConst::setToBuffer PointArrayType, attempted to feed an array that does not match the uniform array's size!");
 404            Con::errorf(err);
 405            GFXAssertFatal(0, err);
 406         #endif
 407            return;
 408         }
 409
 410         AlignedArray<Point4F> alignedVal = AlignedArray<Point4F>(arraySize, sizeof(Point4F), (U8*)mPointArrayVal.address(), false);
 411
 412         buff->set(mHandle, alignedVal);
 413      }
 414      else
 415      {
 416   #if TORQUE_DEBUG
 417         const char* err = avar("PostEffect::EffectConst::setToBuffer $s type is not implemented", mName.c_str());
 418         Con::errorf(err);
 419         GFXAssertFatal(0, err);
 420   #endif
 421      }
 422   }
 423   else if (mValueType == MatrixArrayType)
 424   {
 425      if (type == GFXSCT_Float4x4)
 426      {
 427         if (arraySize != mMatrixArrayVal.size())
 428         {
 429   #if TORQUE_DEBUG
 430            const char* err = avar("PostEffect::EffectConst::setToBuffer MatrixArrayType, attempted to feed an array that does not match the uniform array's size!");
 431            Con::errorf(err);
 432            GFXAssertFatal(0, err);
 433   #endif
 434            return;
 435         }
 436
 437         buff->set(mHandle, mMatrixArrayVal.address(), arraySize);
 438      }
 439      else
 440      {
 441   #if TORQUE_DEBUG
 442         const char* err = avar("PostEffect::EffectConst::setToBuffer $s type is not implemented", mName.c_str());
 443         Con::errorf(err);
 444         GFXAssertFatal(0, err);
 445   #endif
 446      }
 447   }
 448}
 449
 450
 451//-------------------------------------------------------------------------
 452// PostEffect
 453//-------------------------------------------------------------------------
 454
 455PostEffect::PostEffect()
 456   :  mRenderTime( PFXAfterDiffuse ),
 457      mRenderPriority( 1.0 ),
 458      mEnabled( false ),
 459      mStateBlockData( NULL ),
 460      mUpdateShader( true ),
 461      mSkip( false ),
 462      mAllowReflectPass( false ),
 463      mTargetClear( PFXTargetClear_None ),
 464      mTargetScale( Point2F::One ),
 465      mTargetViewport( PFXTargetViewport_TargetSize ),
 466      mTargetSize( Point2I::Zero ),
 467      mTargetFormat( GFXFormatR8G8B8A8 ),
 468      mTargetClearColor( LinearColorF::BLACK ),
 469      mOneFrameOnly( false ),
 470      mOnThisFrame( true ),
 471      mRTSizeSC( NULL ),
 472      mIsValid( false ),
 473      mShaderReloadKey( 0 ),
 474      mOneOverRTSizeSC( NULL ),
 475      mViewportOffsetSC( NULL ),
 476      mTargetViewportSC( NULL ),
 477      mFogDataSC( NULL ),
 478      mFogColorSC( NULL ),
 479      mEyePosSC( NULL ),
 480      mMatWorldToScreenSC( NULL ),
 481      mMatScreenToWorldSC( NULL ),
 482      mMatPrevScreenToWorldSC( NULL ),
 483      mNearFarSC( NULL ),
 484      mInvNearFarSC( NULL ),
 485      mWorldToScreenScaleSC( NULL ),
 486      mProjectionOffsetSC( NULL ),
 487      mWaterColorSC( NULL ),
 488      mWaterFogDataSC( NULL ),
 489      mAmbientColorSC( NULL ),
 490      mWaterFogPlaneSC( NULL ),
 491      mWaterDepthGradMaxSC( NULL ),
 492      mScreenSunPosSC( NULL ),
 493      mLightDirectionSC( NULL ),
 494      mCameraForwardSC( NULL ),
 495      mAccumTimeSC( NULL ),
 496      mDeltaTimeSC( NULL ),
 497      mInvCameraMatSC( NULL ),
 498      mMatCameraToWorldSC( NULL),
 499      mInvCameraTransSC(NULL),
 500      mMatCameraToScreenSC(NULL),
 501      mMatScreenToCameraSC(NULL)
 502{
 503   dMemset( mTexSRGB, 0, sizeof(bool) * NumTextures);
 504   dMemset( mActiveTextures, 0, sizeof( GFXTextureObject* ) * NumTextures );
 505   dMemset( mActiveNamedTarget, 0, sizeof( NamedTexTarget* ) * NumTextures );
 506   dMemset( mActiveTextureViewport, 0, sizeof( RectI ) * NumTextures );
 507   dMemset( mTexSizeSC, 0, sizeof( GFXShaderConstHandle* ) * NumTextures );
 508   dMemset( mRenderTargetParamsSC, 0, sizeof( GFXShaderConstHandle* ) * NumTextures );
 509}
 510
 511PostEffect::~PostEffect()
 512{
 513   EffectConstTable::Iterator iter = mEffectConsts.begin();
 514   for ( ; iter != mEffectConsts.end(); iter++ )
 515      delete iter->value;
 516}
 517
 518void PostEffect::initPersistFields()
 519{
 520   addField( "shader", TypeRealString, Offset( mShaderName, PostEffect ),
 521      "Name of a GFXShaderData for this effect." );
 522
 523   addField( "stateBlock", TYPEID<GFXStateBlockData>(), Offset( mStateBlockData,  PostEffect ),
 524      "Name of a GFXStateBlockData for this effect." );
 525
 526   addField( "target", TypeRealString, Offset( mTargetName, PostEffect ),
 527      "String identifier of this effect's target texture.\n"
 528      "@see PFXTextureIdentifiers" );
 529   
 530   addField( "targetDepthStencil", TypeRealString, Offset( mTargetDepthStencilName, PostEffect ),
 531      "Optional string identifier for this effect's target depth/stencil texture.\n"
 532      "@see PFXTextureIdentifiers" );
 533
 534   addField( "targetScale", TypePoint2F, Offset( mTargetScale, PostEffect ),
 535       "If targetSize is zero this is used to set a relative size from the current target." );
 536       
 537   addField( "targetSize", TypePoint2I, Offset( mTargetSize, PostEffect ), 
 538      "If non-zero this is used as the absolute target size." );   
 539      
 540   addField( "targetFormat", TypeGFXFormat, Offset( mTargetFormat, PostEffect ),
 541      "Format of the target texture, not applicable if writing to the backbuffer." );
 542
 543   addField( "targetClearColor", TypeColorF, Offset( mTargetClearColor, PostEffect ),
 544      "Color to which the target texture is cleared before rendering." );
 545
 546   addField( "targetClear", TYPEID< PFXTargetClear >(), Offset( mTargetClear, PostEffect ),
 547      "Describes when the target texture should be cleared." );
 548
 549   addField( "targetViewport", TYPEID< PFXTargetViewport >(), Offset( mTargetViewport, PostEffect ),
 550      "Specifies how the viewport should be set up for a target texture." );
 551
 552   addField( "texture", TypeImageFilename, Offset( mTexFilename, PostEffect ), NumTextures,
 553      "Input textures to this effect ( samplers ).\n"
 554      "@see PFXTextureIdentifiers" );
 555
 556   addField("textureSRGB", TypeBool, Offset(mTexSRGB, PostEffect), NumTextures,
 557      "Set input texture to be sRGB");
 558
 559   addField( "renderTime", TYPEID< PFXRenderTime >(), Offset( mRenderTime, PostEffect ),
 560      "When to process this effect during the frame." );
 561
 562   addField( "renderBin", TypeRealString, Offset( mRenderBin, PostEffect ),
 563      "Name of a renderBin, used if renderTime is PFXBeforeBin or PFXAfterBin." );
 564
 565   addField( "renderPriority", TypeF32, Offset( mRenderPriority, PostEffect ), 
 566      "PostEffects are processed in DESCENDING order of renderPriority if more than one has the same renderBin/Time." );
 567
 568   addField( "allowReflectPass", TypeBool, Offset( mAllowReflectPass, PostEffect ), 
 569      "Is this effect processed during reflection render passes." );
 570
 571   addProtectedField( "enabled", TypeBool, Offset( mEnabled, PostEffect),
 572      &PostEffect::_setIsEnabled, &defaultProtectedGetFn,
 573      "Is the effect on." );
 574
 575   addField( "onThisFrame", TypeBool, Offset( mOnThisFrame, PostEffect ), 
 576      "Allows you to turn on a PostEffect for only a single frame." );
 577
 578   addField( "oneFrameOnly", TypeBool, Offset( mOneFrameOnly, PostEffect ), 
 579      "Allows you to turn on a PostEffect for only a single frame." );
 580
 581   addField( "skip", TypeBool, Offset( mSkip, PostEffect ), 
 582      "Skip processing of this PostEffect and its children even if its parent "
 583      "is enabled. Parent and sibling PostEffects in the chain are still processed." );
 584
 585   Parent::initPersistFields();
 586}
 587
 588bool PostEffect::onAdd()
 589{
 590   if( !Parent::onAdd() )
 591      return false;
 592
 593   LightManager::smActivateSignal.notify( this, &PostEffect::_onLMActivate );
 594   mUpdateShader = true;
 595
 596   // Grab the script path.
 597   Torque::Path scriptPath( Con::getVariable( "$Con::File" ) );
 598   scriptPath.setFileName( String::EmptyString );
 599   scriptPath.setExtension( String::EmptyString );
 600
 601   // Find additional textures
 602   for( S32 i = 0; i < NumTextures; i++ )
 603   {
 604      mTextureType[i] = NormalTextureType;
 605
 606      String texFilename = mTexFilename[i];
 607
 608      // Skip empty stages or ones with variable or target names.
 609      if (  texFilename.isEmpty() ||
 610            texFilename[0] == '$' ||
 611            texFilename[0] == '#' )
 612         continue;
 613
 614      GFXTextureProfile *profile = &PostFxTextureProfile;
 615      if (mTexSRGB[i])
 616         profile = &PostFxTextureSRGBProfile;
 617
 618      // Try to load the texture.
 619      bool success = mTextures[i].set( texFilename, &PostFxTextureProfile, avar( "%s() - (line %d)", __FUNCTION__, __LINE__ ) );
 620      if (!success)
 621         Con::errorf("Invalid Texture for PostEffect (%s), The Texture '%s' does not exist!", this->getName(), texFilename.c_str());
 622   }
 623
 624   // Is the target a named target?
 625   if ( mTargetName.isNotEmpty() && mTargetName[0] == '#' )
 626   {
 627      mNamedTarget.registerWithName( mTargetName.substr( 1 ) );
 628      mNamedTarget.getTextureDelegate().bind( this, &PostEffect::_getTargetTexture );
 629   }
 630   if ( mTargetDepthStencilName.isNotEmpty() && mTargetDepthStencilName[0] == '#' )
 631      mNamedTargetDepthStencil.registerWithName( mTargetDepthStencilName.substr( 1 ) );
 632
 633   if (mNamedTarget.isRegistered() || mNamedTargetDepthStencil.isRegistered())
 634      GFXTextureManager::addEventDelegate( this, &PostEffect::_onTextureEvent );
 635
 636   // Call onAdd in script
 637   onAdd_callback();
 638
 639   // Should we start enabled?
 640   if ( mEnabled )
 641   {
 642      mEnabled = false;
 643      enable();
 644   }
 645
 646   getSet()->addObject( this );
 647
 648   return true;
 649}
 650
 651void PostEffect::onRemove()
 652{
 653   Parent::onRemove();
 654
 655   PFXMGR->_removeEffect( this );
 656
 657   LightManager::smActivateSignal.remove( this, &PostEffect::_onLMActivate );
 658
 659   mShader = NULL;
 660   _cleanTargets();
 661
 662   if ( mNamedTarget.isRegistered() || mNamedTargetDepthStencil.isRegistered() )
 663      GFXTextureManager::removeEventDelegate( this, &PostEffect::_onTextureEvent );
 664
 665   if ( mNamedTarget.isRegistered() )
 666   {
 667      mNamedTarget.unregister();
 668      mNamedTarget.getTextureDelegate().clear();
 669   }
 670
 671   if ( mNamedTargetDepthStencil.isRegistered() )
 672      mNamedTargetDepthStencil.unregister();
 673}
 674
 675void PostEffect::_updateScreenGeometry(   const Frustum &frustum,
 676                                          GFXVertexBufferHandle<PFXVertex> *outVB )
 677{
 678   outVB->set( GFX, 4, GFXBufferTypeVolatile );
 679
 680   const Point3F *frustumPoints = frustum.getPoints();
 681   const Point3F& cameraPos = frustum.getPosition();
 682
 683   // Perform a camera offset.  We need to manually perform this offset on the postFx's
 684   // polygon, which is at the far plane.
 685   const Point2F& projOffset = frustum.getProjectionOffset();
 686   Point3F cameraOffsetPos = cameraPos;
 687   if(!projOffset.isZero())
 688   {
 689      // First we need to calculate the offset at the near plane.  The projOffset
 690      // given above can be thought of a percent as it ranges from 0..1 (or 0..-1).
 691      F32 nearOffset = frustum.getNearRight() * projOffset.x;
 692
 693      // Now given the near plane distance from the camera we can solve the right
 694      // triangle and calcuate the SIN theta for the offset at the near plane.
 695      // SIN theta = x/y
 696      F32 sinTheta = nearOffset / frustum.getNearDist();
 697
 698      // Finally, we can calcuate the offset at the far plane, which is where our sun (or vector)
 699      // light's polygon is drawn.
 700      F32 farOffset = frustum.getFarDist() * sinTheta;
 701
 702      // We can now apply this far plane offset to the far plane itself, which then compensates
 703      // for the project offset.
 704      MatrixF camTrans = frustum.getTransform();
 705      VectorF offset = camTrans.getRightVector();
 706      offset *= farOffset;
 707      cameraOffsetPos += offset;
 708   }
 709
 710   PFXVertex *vert = outVB->lock();
 711
 712   vert->point.set(-1.0, 1.0, 0.0);
 713   vert->texCoord.set(0.0f, 0.0f);
 714   vert->wsEyeRay = frustumPoints[Frustum::FarTopLeft] - cameraOffsetPos;
 715   vert++;
 716
 717   vert->point.set(1.0, 1.0, 0.0);
 718   vert->texCoord.set(1.0f, 0.0f);
 719   vert->wsEyeRay = frustumPoints[Frustum::FarTopRight] - cameraOffsetPos;
 720   vert++;
 721
 722   vert->point.set(-1.0, -1.0, 0.0);
 723   vert->texCoord.set(0.0f, 1.0f);
 724   vert->wsEyeRay = frustumPoints[Frustum::FarBottomLeft] - cameraOffsetPos;
 725   vert++;
 726
 727   vert->point.set(1.0, -1.0, 0.0);
 728   vert->texCoord.set(1.0f, 1.0f);
 729   vert->wsEyeRay = frustumPoints[Frustum::FarBottomRight] - cameraOffsetPos;
 730   vert++;
 731
 732   outVB->unlock();
 733}
 734
 735void PostEffect::_setupStateBlock( const SceneRenderState *state )
 736{
 737   if ( mStateBlock.isNull() )
 738   {
 739      GFXStateBlockDesc desc;
 740      if ( mStateBlockData )
 741         desc = mStateBlockData->getState();
 742
 743      mStateBlock = GFX->createStateBlock( desc );
 744   }
 745
 746   GFX->setStateBlock( mStateBlock );
 747}
 748
 749void PostEffect::_setupConstants( const SceneRenderState *state )
 750{
 751   // Alloc the const buffer.
 752   if ( mShaderConsts.isNull() )
 753   {
 754      mShaderConsts = mShader->allocConstBuffer();
 755
 756      mRTSizeSC = mShader->getShaderConstHandle( "$targetSize" );
 757      mOneOverRTSizeSC = mShader->getShaderConstHandle( "$oneOverTargetSize" );
 758
 759      mTexSizeSC[0] = mShader->getShaderConstHandle( "$texSize0" );
 760      mTexSizeSC[1] = mShader->getShaderConstHandle( "$texSize1" );
 761      mTexSizeSC[2] = mShader->getShaderConstHandle( "$texSize2" );
 762      mTexSizeSC[3] = mShader->getShaderConstHandle( "$texSize3" );
 763      mTexSizeSC[4] = mShader->getShaderConstHandle( "$texSize4" );
 764      mTexSizeSC[5] = mShader->getShaderConstHandle( "$texSize5" );
 765      mTexSizeSC[6] = mShader->getShaderConstHandle( "$texSize6" );
 766      mTexSizeSC[7] = mShader->getShaderConstHandle( "$texSize7" );
 767
 768      mRenderTargetParamsSC[0] = mShader->getShaderConstHandle( "$rtParams0" );
 769      mRenderTargetParamsSC[1] = mShader->getShaderConstHandle( "$rtParams1" );
 770      mRenderTargetParamsSC[2] = mShader->getShaderConstHandle( "$rtParams2" );
 771      mRenderTargetParamsSC[3] = mShader->getShaderConstHandle( "$rtParams3" );
 772      mRenderTargetParamsSC[4] = mShader->getShaderConstHandle( "$rtParams4" );
 773      mRenderTargetParamsSC[5] = mShader->getShaderConstHandle( "$rtParams5" );
 774      mRenderTargetParamsSC[6] = mShader->getShaderConstHandle( "$rtParams6" );
 775      mRenderTargetParamsSC[7] = mShader->getShaderConstHandle( "$rtParams7" );
 776
 777      //mViewportSC = shader->getShaderConstHandle( "$viewport" );
 778
 779      mTargetViewportSC = mShader->getShaderConstHandle( "$targetViewport" );
 780
 781      mFogDataSC = mShader->getShaderConstHandle( ShaderGenVars::fogData );
 782      mFogColorSC = mShader->getShaderConstHandle( ShaderGenVars::fogColor );
 783
 784      mEyePosSC = mShader->getShaderConstHandle( ShaderGenVars::eyePosWorld );
 785
 786      mNearFarSC = mShader->getShaderConstHandle( "$nearFar" );
 787      mInvNearFarSC = mShader->getShaderConstHandle( "$invNearFar" );
 788      mWorldToScreenScaleSC = mShader->getShaderConstHandle( "$worldToScreenScale" );
 789
 790      mMatWorldToScreenSC = mShader->getShaderConstHandle( "$matWorldToScreen" );
 791      mMatScreenToWorldSC = mShader->getShaderConstHandle( "$matScreenToWorld" );
 792      mMatPrevScreenToWorldSC = mShader->getShaderConstHandle( "$matPrevScreenToWorld" );
 793
 794      mProjectionOffsetSC = mShader->getShaderConstHandle( "$projectionOffset" );
 795
 796      mWaterColorSC = mShader->getShaderConstHandle( "$waterColor" );
 797      mAmbientColorSC = mShader->getShaderConstHandle( "$ambientColor" );
 798      mWaterFogDataSC = mShader->getShaderConstHandle( "$waterFogData" );
 799      mWaterFogPlaneSC = mShader->getShaderConstHandle( "$waterFogPlane" );      
 800      mWaterDepthGradMaxSC = mShader->getShaderConstHandle( "$waterDepthGradMax" );
 801      mScreenSunPosSC = mShader->getShaderConstHandle( "$screenSunPos" );
 802      mLightDirectionSC = mShader->getShaderConstHandle( "$lightDirection" );
 803      mCameraForwardSC = mShader->getShaderConstHandle( "$camForward" );
 804
 805      mAccumTimeSC = mShader->getShaderConstHandle( "$accumTime" );
 806      mDeltaTimeSC = mShader->getShaderConstHandle( "$deltaTime" );
 807
 808      mInvCameraMatSC = mShader->getShaderConstHandle( "$invCameraMat" );
 809
 810      mMatCameraToWorldSC = mShader->getShaderConstHandle("$cameraToWorld");
 811
 812      mInvCameraTransSC = mShader->getShaderConstHandle("$invCameraTrans");
 813      mMatCameraToScreenSC = mShader->getShaderConstHandle("$cameraToScreen");
 814      mMatScreenToCameraSC = mShader->getShaderConstHandle("$screenToCamera");
 815   }
 816
 817   // Set up shader constants for source image size
 818   if ( mRTSizeSC->isValid() )
 819   {
 820      const Point2I &resolution = GFX->getActiveRenderTarget()->getSize();
 821      Point2F pixelShaderConstantData;
 822
 823      pixelShaderConstantData.x = resolution.x;
 824      pixelShaderConstantData.y = resolution.y;
 825
 826      mShaderConsts->set( mRTSizeSC, pixelShaderConstantData );
 827   }
 828
 829   if ( mOneOverRTSizeSC->isValid() )
 830   {
 831      const Point2I &resolution = GFX->getActiveRenderTarget()->getSize();
 832      Point2F oneOverTargetSize( 1.0f / (F32)resolution.x, 1.0f / (F32)resolution.y );
 833
 834      mShaderConsts->set( mOneOverRTSizeSC, oneOverTargetSize );
 835   }
 836
 837   // Set up additional textures
 838   Point2F texSizeConst;
 839   for( U32 i = 0; i < NumTextures; i++ )
 840   {
 841      if( !mActiveTextures[i] )
 842         continue;
 843
 844      if ( mTexSizeSC[i]->isValid() )
 845      {
 846         texSizeConst.x = (F32)mActiveTextures[i]->getWidth();
 847         texSizeConst.y = (F32)mActiveTextures[i]->getHeight();
 848         mShaderConsts->set( mTexSizeSC[i], texSizeConst );
 849      }
 850   }
 851
 852   for ( U32 i = 0; i < NumTextures; i++ )
 853   {
 854      if ( !mRenderTargetParamsSC[i]->isValid() )
 855         continue;
 856
 857      Point4F rtParams( Point4F::One );
 858
 859      if ( mActiveTextures[i] )
 860      {
 861         const Point3I &targetSz = mActiveTextures[i]->getSize();
 862         RectI targetVp = mActiveTextureViewport[i];
 863         ScreenSpace::RenderTargetParameters(targetSz, targetVp, rtParams);
 864      }
 865
 866      mShaderConsts->set( mRenderTargetParamsSC[i], rtParams );
 867   }
 868
 869   // Target viewport (in target space)
 870   if ( mTargetViewportSC->isValid() )
 871   {
 872      const Point2I& targetSize = GFX->getActiveRenderTarget()->getSize();
 873      Point3I size(targetSize.x, targetSize.y, 0);
 874      const RectI& viewport = GFX->getViewport();
 875
 876      Point2F offset((F32)viewport.point.x / (F32)targetSize.x, (F32)viewport.point.y / (F32)targetSize.y );
 877      Point2F scale((F32)viewport.extent.x / (F32)targetSize.x, (F32)viewport.extent.y / (F32)targetSize.y );
 878
 879      Point4F targetParams;
 880      targetParams.x = offset.x;
 881      targetParams.y = offset.y;
 882      targetParams.z = offset.x + scale.x;
 883      targetParams.w = offset.y + scale.y;
 884
 885      mShaderConsts->set( mTargetViewportSC, targetParams );
 886   }
 887
 888   // Set the fog data.
 889   if ( mFogDataSC->isValid() )
 890   {
 891      const FogData &data = state->getSceneManager()->getFogData();
 892
 893      Point3F params;
 894      params.x = data.density;
 895      params.y = data.densityOffset;
 896
 897      if ( !mIsZero( data.atmosphereHeight ) )
 898         params.z = 1.0f / data.atmosphereHeight;
 899      else
 900         params.z = 0.0f;
 901
 902      mShaderConsts->set( mFogDataSC, params );
 903   }
 904
 905   const PFXFrameState &thisFrame = PFXMGR->getFrameState();
 906
 907   if ( mMatWorldToScreenSC->isValid() )
 908   {
 909      // Screen space->world space
 910      MatrixF tempMat = thisFrame.cameraToScreen;
 911      tempMat.mul( thisFrame.worldToCamera );
 912      tempMat.fullInverse();
 913      tempMat.transpose();
 914
 915      // Support using these matrices as float3x3 or float4x4...
 916      mShaderConsts->set( mMatWorldToScreenSC, tempMat, mMatWorldToScreenSC->getType() );
 917   }
 918
 919   if ( mMatScreenToWorldSC->isValid() )
 920   {
 921      // World space->screen space
 922      MatrixF tempMat = thisFrame.cameraToScreen;
 923      tempMat.mul( thisFrame.worldToCamera );
 924      tempMat.transpose();
 925
 926      // Support using these matrices as float3x3 or float4x4...
 927      mShaderConsts->set( mMatScreenToWorldSC, tempMat, mMatScreenToWorldSC->getType() );
 928   }
 929
 930   if ( mMatPrevScreenToWorldSC->isValid() )
 931   {
 932      const PFXFrameState &lastFrame = PFXMGR->getLastFrameState();
 933
 934      // Previous frame world space->screen space
 935      MatrixF tempMat = lastFrame.cameraToScreen;
 936      tempMat.mul( lastFrame.worldToCamera );
 937      tempMat.transpose();
 938      mShaderConsts->set( mMatPrevScreenToWorldSC, tempMat );
 939   }
 940
 941   if (mAmbientColorSC->isValid() && state)
 942   {
 943      const LinearColorF &sunlight = state->getAmbientLightColor();
 944      Point3F ambientColor( sunlight.red, sunlight.green, sunlight.blue );
 945
 946      mShaderConsts->set( mAmbientColorSC, ambientColor );
 947   }
 948
 949   if (mMatCameraToWorldSC->isValid())
 950   {
 951      MatrixF tempMat = thisFrame.worldToCamera;
 952      tempMat.inverse();
 953      mShaderConsts->set(mMatCameraToWorldSC, tempMat);
 954   }
 955
 956   if (mInvCameraTransSC->isValid())
 957   {
 958      MatrixF mat = state->getCameraTransform();
 959      mat.fullInverse();
 960      mShaderConsts->set(mInvCameraTransSC, mat, mInvCameraTransSC->getType());
 961   }
 962   //Projection Matrix
 963   if (mMatCameraToScreenSC->isValid())
 964   {
 965
 966      MatrixF tempMat = thisFrame.cameraToScreen;
 967      mShaderConsts->set(mMatCameraToScreenSC, tempMat, mMatCameraToScreenSC->getType());
 968   }
 969
 970
 971   //Inverse Projection Matrix
 972   if (mMatScreenToCameraSC->isValid())
 973   {
 974
 975      MatrixF tempMat = thisFrame.cameraToScreen;
 976      tempMat.fullInverse();
 977
 978      mShaderConsts->set(mMatScreenToCameraSC, tempMat, mMatScreenToCameraSC->getType());
 979   }
 980   mShaderConsts->setSafe( mAccumTimeSC, MATMGR->getTotalTime() );
 981   mShaderConsts->setSafe( mDeltaTimeSC, MATMGR->getDeltaTime() );
 982
 983   // Now set all the constants that are dependent on the scene state.
 984   if ( state )
 985   {
 986      mShaderConsts->setSafe( mEyePosSC, state->getDiffuseCameraPosition() );
 987      mShaderConsts->setSafe( mNearFarSC, Point2F( state->getNearPlane(), state->getFarPlane() ) );
 988      mShaderConsts->setSafe( mInvNearFarSC, Point2F( 1.0f / state->getNearPlane(), 1.0f / state->getFarPlane() ) );
 989      mShaderConsts->setSafe( mWorldToScreenScaleSC, state->getWorldToScreenScale() );
 990      mShaderConsts->setSafe( mProjectionOffsetSC, state->getCameraFrustum().getProjectionOffset() );
 991      mShaderConsts->setSafe( mFogColorSC, state->getSceneManager()->getFogData().color );
 992
 993      if ( mWaterColorSC->isValid() )
 994      {
 995         LinearColorF color( state->getSceneManager()->getWaterFogData().color );
 996         mShaderConsts->set( mWaterColorSC, color );
 997      }
 998
 999      if ( mWaterFogDataSC->isValid() )
1000      {
1001         const WaterFogData &data = state->getSceneManager()->getWaterFogData();
1002         Point4F params( data.density, data.densityOffset, data.wetDepth, data.wetDarkening );
1003         mShaderConsts->set( mWaterFogDataSC, params );
1004      }
1005
1006      if ( mWaterFogPlaneSC->isValid() )
1007      {
1008         const PlaneF &plane = state->getSceneManager()->getWaterFogData().plane;
1009         mShaderConsts->set( mWaterFogPlaneSC, plane );
1010      }
1011
1012      if ( mWaterDepthGradMaxSC->isValid() )
1013      {
1014         mShaderConsts->set( mWaterDepthGradMaxSC, state->getSceneManager()->getWaterFogData().depthGradMax );
1015      }
1016
1017      if ( mScreenSunPosSC->isValid() )
1018      {
1019         // Grab our projection matrix
1020         // from the frustum.
1021         Frustum frust = state->getCameraFrustum();
1022         MatrixF proj( true );
1023         frust.getProjectionMatrix( &proj );
1024
1025         // Grab the ScatterSky world matrix.
1026         MatrixF camMat = state->getCameraTransform();
1027         camMat.inverse();
1028         MatrixF tmp( true );
1029         tmp = camMat;
1030         tmp.setPosition( Point3F( 0, 0, 0 ) );
1031
1032         Point3F sunPos( 0, 0, 0 );
1033
1034         // Get the light manager and sun light object.
1035         LightInfo *sunLight = LIGHTMGR->getSpecialLight( LightManager::slSunLightType );
1036
1037         // Grab the light direction and scale
1038         // by the ScatterSky radius to get the world
1039         // space sun position.
1040         const VectorF &lightDir = sunLight->getDirection();
1041
1042         Point3F lightPos( lightDir.x * (6378.0f * 1000.0f),
1043                           lightDir.y * (6378.0f * 1000.0f),
1044                           lightDir.z * (6378.0f * 1000.0f) );
1045
1046         RectI viewPort = GFX->getViewport();
1047
1048         // Get the screen space sun position.
1049         MathUtils::mProjectWorldToScreen(lightPos, &sunPos, viewPort, tmp, proj);
1050
1051         // And normalize it to the 0 to 1 range.
1052         sunPos.x -= (F32)viewPort.point.x;
1053         sunPos.y -= (F32)viewPort.point.y;
1054         sunPos.x /= (F32)viewPort.extent.x;
1055         sunPos.y /= (F32)viewPort.extent.y;
1056
1057         mShaderConsts->set( mScreenSunPosSC, Point2F( sunPos.x, sunPos.y ) );
1058      }
1059
1060      if ( mLightDirectionSC->isValid() )
1061      {
1062         LightInfo *sunLight = LIGHTMGR->getSpecialLight( LightManager::slSunLightType );
1063
1064         const VectorF &lightDir = sunLight->getDirection();
1065         mShaderConsts->set( mLightDirectionSC, lightDir );
1066      }
1067
1068      if ( mCameraForwardSC->isValid() )
1069      {
1070         const MatrixF &camMat = state->getCameraTransform();
1071         VectorF camFwd( 0, 0, 0 );
1072
1073         camMat.getColumn( 1, &camFwd );
1074
1075         mShaderConsts->set( mCameraForwardSC, camFwd );
1076      }
1077
1078      if ( mInvCameraMatSC->isValid() )
1079      {
1080         MatrixF mat = state->getCameraTransform();
1081         mat.inverse();
1082         mShaderConsts->set( mInvCameraMatSC, mat, mInvCameraMatSC->getType() );
1083      }
1084
1085   } // if ( state )
1086
1087   // Set EffectConsts - specified from script
1088
1089   // If our shader has reloaded since last frame we must mark all
1090   // EffectConsts dirty so they will be reset.
1091   if ( mShader->getReloadKey() != mShaderReloadKey )
1092   {
1093      mShaderReloadKey = mShader->getReloadKey();
1094
1095      EffectConstTable::Iterator iter = mEffectConsts.begin();
1096      for ( ; iter != mEffectConsts.end(); iter++ )
1097      {
1098         iter->value->mDirty = true;
1099         iter->value->mHandle = NULL;
1100      }
1101   }
1102
1103   // Doesn't look like anyone is using this anymore.
1104   // But if we do want to pass this info to script,
1105   // we should do so in the same way as I am doing below.
1106   /*
1107   Point2F texSizeScriptConst( 0, 0 );
1108   String buffer;
1109   if ( mActiveTextures[0] )
1110   {
1111      texSizeScriptConst.x = (F32)mActiveTextures[0]->getWidth();
1112      texSizeScriptConst.y = (F32)mActiveTextures[0]->getHeight();
1113
1114      dSscanf( buffer.c_str(), "%g %g", texSizeScriptConst.x, texSizeScriptConst.y );
1115   }
1116   */
1117      
1118   {
1119      PROFILE_SCOPE( PostEffect_SetShaderConsts );
1120
1121      // Pass some data about the current render state to script.
1122      // 
1123      // TODO: This is pretty messy... it should go away.  This info
1124      // should be available from some other script accessible method
1125      // or field which isn't PostEffect specific.
1126      //
1127      if ( state )
1128      {
1129         Con::setFloatVariable( "$Param::NearDist", state->getNearPlane() );
1130         Con::setFloatVariable( "$Param::FarDist", state->getFarPlane() );   
1131      }
1132
1133      setShaderConsts_callback();
1134   }   
1135
1136   EffectConstTable::Iterator iter = mEffectConsts.begin();
1137   for ( ; iter != mEffectConsts.end(); iter++ )
1138      iter->value->setToBuffer( mShaderConsts );
1139}
1140
1141void PostEffect::_setupTexture( U32 stage, GFXTexHandle &inputTex, const RectI *inTexViewport )
1142{
1143   const String &texFilename = mTexFilename[ stage ];
1144
1145   GFXTexHandle theTex;
1146   NamedTexTarget *namedTarget = NULL;
1147
1148   RectI viewport = GFX->getViewport();
1149
1150   if ( texFilename.compare( "$inTex", 0, String::NoCase ) == 0 )
1151   {
1152      theTex = inputTex;
1153
1154      if ( inTexViewport )
1155      {
1156         viewport = *inTexViewport;
1157      }
1158      else if ( theTex )
1159      {
1160         viewport.set( 0, 0, theTex->getWidth(), theTex->getHeight() );
1161      }
1162   }
1163   else if ( texFilename.compare( "$backBuffer", 0, String::NoCase ) == 0 )
1164   {
1165      theTex = PFXMGR->getBackBufferTex();
1166
1167      // Always use the GFX viewport when reading from the backbuffer
1168   }
1169   else if ( texFilename.isNotEmpty() && texFilename[0] == '#' )
1170   {
1171      namedTarget = NamedTexTarget::find( texFilename.c_str() + 1 );
1172      if ( namedTarget )
1173      {
1174         theTex = namedTarget->getTexture( 0 );
1175         viewport = namedTarget->getViewport();
1176      }
1177   }
1178   else
1179   {
1180      theTex = mTextures[ stage ];
1181      if ( theTex )
1182         viewport.set( 0, 0, theTex->getWidth(), theTex->getHeight() );
1183   }
1184
1185   mActiveTextures[ stage ] = theTex;
1186   mActiveNamedTarget[ stage ] = namedTarget;
1187   mActiveTextureViewport[ stage ] = viewport;
1188
1189   if ( theTex.isValid() )
1190      GFX->setTexture( stage, theTex );
1191}
1192
1193void PostEffect::_setupCubemapTexture(U32 stage, GFXCubemapHandle &inputTex)
1194{
1195   RectI viewport = GFX->getViewport();
1196
1197   mActiveTextures[stage] = nullptr;
1198   mActiveNamedTarget[stage] = nullptr;
1199   mActiveTextureViewport[stage] = viewport;
1200
1201   if (inputTex.isValid())
1202      GFX->setCubeTexture(stage, inputTex);
1203}
1204
1205void PostEffect::_setupCubemapArrayTexture(U32 stage, GFXCubemapArrayHandle &inputTex)
1206{
1207   RectI viewport = GFX->getViewport();
1208
1209   mActiveTextures[stage] = nullptr;
1210   mActiveNamedTarget[stage] = nullptr;
1211   mActiveTextureViewport[stage] = viewport;
1212
1213   if (inputTex.isValid())
1214      GFX->setCubeArrayTexture(stage, inputTex);
1215}
1216
1217void PostEffect::_setupTransforms()
1218{
1219   // Set everything to identity.
1220   GFX->setWorldMatrix( MatrixF::Identity );
1221   GFX->setProjectionMatrix( MatrixF::Identity );
1222}
1223
1224void PostEffect::_setupTarget( const SceneRenderState *state, bool *outClearTarget )
1225{
1226   if (  mNamedTarget.isRegistered() || 
1227         mTargetName.compare( "$outTex", 0, String::NoCase ) == 0 )
1228   {
1229      // Size it relative to the texture of the first stage or
1230      // if NULL then use the current target.
1231
1232      Point2I targetSize;
1233
1234      // If we have an absolute target size then use that.
1235      if ( !mTargetSize.isZero() )
1236         targetSize = mTargetSize;
1237
1238      // Else generate a relative size using the target scale.
1239      else if ( mActiveTextures[ 0 ] )
1240      {
1241         const Point3I &texSize = mActiveTextures[ 0 ]->getSize();
1242
1243         targetSize.set(   texSize.x * mTargetScale.x,
1244                           texSize.y * mTargetScale.y );
1245      }
1246      else
1247      {
1248         GFXTarget *oldTarget = GFX->getActiveRenderTarget();
1249         const Point2I &oldTargetSize = oldTarget->getSize();
1250
1251         targetSize.set(   oldTargetSize.x * mTargetScale.x,
1252                           oldTargetSize.y * mTargetScale.y );
1253      }
1254
1255      // Make sure its at least 1x1.
1256      targetSize.setMax( Point2I::One );
1257
1258      if (  mNamedTarget.isRegistered() ||
1259            !mTargetTex ||
1260            mTargetTex.getWidthHeight() != targetSize )
1261      {
1262         mTargetTex.set( targetSize.x, targetSize.y, mTargetFormat,
1263            &PostFxTargetProfile, "PostEffect::_setupTarget" );
1264
1265         if ( mTargetClear == PFXTargetClear_OnCreate )
1266            *outClearTarget = true;
1267
1268         if(mTargetViewport == PFXTargetViewport_GFXViewport)
1269         {
1270            // We may need to scale the GFX viewport to fit within
1271            // our target texture size
1272            GFXTarget *oldTarget = GFX->getActiveRenderTarget();
1273            const Point2I &oldTargetSize = oldTarget->getSize();
1274            Point2F scale(targetSize.x / F32(oldTargetSize.x), targetSize.y / F32(oldTargetSize.y));
1275
1276            const RectI &viewport = GFX->getViewport();
1277
1278            mNamedTarget.setViewport( RectI( viewport.point.x*scale.x, viewport.point.y*scale.y, viewport.extent.x*scale.x, viewport.extent.y*scale.y ) );
1279         }
1280         else if(mTargetViewport == PFXTargetViewport_NamedInTexture0 && mActiveNamedTarget[0] && mActiveNamedTarget[0]->getTexture())
1281         {
1282            // Scale the named input texture's viewport to match our target
1283            const Point3I &namedTargetSize = mActiveNamedTarget[0]->getTexture()->getSize();
1284            Point2F scale(targetSize.x / F32(namedTargetSize.x), targetSize.y / F32(namedTargetSize.y));
1285
1286            const RectI &viewport = mActiveNamedTarget[0]->getViewport();
1287
1288            mNamedTarget.setViewport( RectI( viewport.point.x*scale.x, viewport.point.y*scale.y, viewport.extent.x*scale.x, viewport.extent.y*scale.y ) );
1289         }
1290         else
1291         {
1292            // PFXTargetViewport_TargetSize
1293            mNamedTarget.setViewport( RectI( 0, 0, targetSize.x, targetSize.y ) );
1294         }
1295      }
1296   }
1297   else
1298      mTargetTex = NULL;
1299
1300   // Do we have a named depthStencil target?
1301   if ( mNamedTargetDepthStencil.isRegistered() )
1302   {
1303      // Size it relative to the texture of the first stage or
1304      // if NULL then use the current target.
1305      Point2I targetSize;
1306
1307      // If we have an absolute target size then use that.
1308      if ( !mTargetSize.isZero() )
1309         targetSize = mTargetSize;
1310
1311      // Else generate a relative size using the target scale.
1312      else if ( mActiveTextures[ 0 ] )
1313      {
1314         const Point3I &texSize = mActiveTextures[ 0 ]->getSize();
1315
1316         targetSize.set(   texSize.x * mTargetScale.x,
1317                           texSize.y * mTargetScale.y );
1318      }
1319      else
1320      {
1321         GFXTarget *oldTarget = GFX->getActiveRenderTarget();
1322         const Point2I &oldTargetSize = oldTarget->getSize();
1323
1324         targetSize.set(   oldTargetSize.x * mTargetScale.x,
1325                           oldTargetSize.y * mTargetScale.y );
1326      }
1327
1328      // Make sure its at least 1x1.
1329      targetSize.setMax( Point2I::One );
1330      
1331      if (  mNamedTargetDepthStencil.isRegistered() &&
1332            mTargetDepthStencil.getWidthHeight() != targetSize )
1333      {         
1334         mTargetDepthStencil.set( targetSize.x, targetSize.y, GFXFormatD24S8,
1335                     &GFXZTargetProfile, "PostEffect::_setupTarget" );
1336
1337         if ( mTargetClear == PFXTargetClear_OnCreate )
1338            *outClearTarget = true;
1339
1340         if(mTargetViewport == PFXTargetViewport_GFXViewport)
1341         {
1342            // We may need to scale the GFX viewport to fit within
1343            // our target texture size
1344            GFXTarget *oldTarget = GFX->getActiveRenderTarget();
1345            const Point2I &oldTargetSize = oldTarget->getSize();
1346            Point2F scale(targetSize.x / F32(oldTargetSize.x), targetSize.y / F32(oldTargetSize.y));
1347
1348            const RectI &viewport = GFX->getViewport();
1349
1350            mNamedTargetDepthStencil.setViewport( RectI( viewport.point.x*scale.x, viewport.point.y*scale.y, viewport.extent.x*scale.x, viewport.extent.y*scale.y ) );
1351         }
1352         else if(mTargetViewport == PFXTargetViewport_NamedInTexture0 && mActiveNamedTarget[0] && mActiveNamedTarget[0]->getTexture())
1353         {
1354            // Scale the named input texture's viewport to match our target
1355            const Point3I &namedTargetSize = mActiveNamedTarget[0]->getTexture()->getSize();
1356            Point2F scale(targetSize.x / F32(namedTargetSize.x), targetSize.y / F32(namedTargetSize.y));
1357
1358            const RectI &viewport = mActiveNamedTarget[0]->getViewport();
1359
1360            mNamedTargetDepthStencil.setViewport( RectI( viewport.point.x*scale.x, viewport.point.y*scale.y, viewport.extent.x*scale.x, viewport.extent.y*scale.y ) );
1361         }
1362         else
1363         {
1364            // PFXTargetViewport_TargetSize
1365            mNamedTargetDepthStencil.setViewport( RectI( 0, 0, targetSize.x, targetSize.y ) );
1366         }
1367      }
1368   }
1369   else
1370      mTargetDepthStencil = NULL;
1371
1372   if ( mTargetClear == PFXTargetClear_OnDraw )
1373      *outClearTarget = true;
1374
1375   if ( !mTarget && (mTargetTex || mTargetDepthStencil) )
1376      mTarget = GFX->allocRenderToTextureTarget();
1377}
1378
1379void PostEffect::_cleanTargets( bool recurse )
1380{
1381   mTargetTex = NULL;
1382   mTargetDepthStencil = NULL;
1383   mTarget = NULL;
1384
1385   if ( !recurse )
1386      return;
1387
1388   // Clear the children too!
1389   for ( U32 i = 0; i < size(); i++ )
1390   {
1391      PostEffect *effect = (PostEffect*)(*this)[i];
1392      effect->_cleanTargets( true );
1393   }
1394}
1395
1396void PostEffect::process(  const SceneRenderState *state,
1397                           GFXTexHandle &inOutTex,
1398                           const RectI *inTexViewport )
1399{
1400   // If the shader is forced to be skipped... then skip.
1401   if ( mSkip )
1402      return;
1403
1404   // Skip out if we don't support reflection passes.
1405   if ( state && state->isReflectPass() && !mAllowReflectPass )
1406      return;
1407
1408   if ( mOneFrameOnly && !mOnThisFrame )
1409      return;
1410
1411   // Check requirements if the shader needs updating.
1412   if ( mUpdateShader )
1413   {
1414      _checkRequirements();
1415
1416      // Clear the targets if we failed passing
1417      // the requirements at this time.
1418      if ( !mIsValid )
1419         _cleanTargets( true );
1420   }
1421
1422   // If we're not valid then we cannot render.
1423   if ( !mIsValid )
1424      return;
1425
1426   GFXDEBUGEVENT_SCOPE_EX( PostEffect_Process, ColorI::GREEN, avar("PostEffect: %s", getName()) );
1427
1428   preProcess_callback();   
1429
1430   GFXTransformSaver saver;
1431
1432   // Set the textures.
1433   for (U32 i = 0; i < NumTextures; i++)
1434   {
1435      if (mTextureType[i] == NormalTextureType)
1436         _setupTexture(i, inOutTex, inTexViewport);
1437      else if (mTextureType[i] == CubemapType)
1438         _setupCubemapTexture(i, mCubemapTextures[i]);
1439      else if (mTextureType[i] == CubemapArrayType)
1440         _setupCubemapArrayTexture(i, mCubemapArrayTextures[i]);
1441   }
1442
1443   _setupStateBlock( state ) ;
1444   _setupTransforms();
1445
1446   bool clearTarget = false;
1447   _setupTarget( state, &clearTarget );
1448
1449   if ( mTargetTex || mTargetDepthStencil )
1450   {
1451      const RectI &oldViewport = GFX->getViewport();
1452      GFXTarget *oldTarget = GFX->getActiveRenderTarget();
1453
1454      GFX->pushActiveRenderTarget();
1455      mTarget->attachTexture( GFXTextureTarget::Color0, mTargetTex );
1456
1457      // Set the right depth stencil target.
1458      if ( !mTargetDepthStencil && mTargetTex.getWidthHeight() == GFX->getActiveRenderTarget()->getSize() )
1459         mTarget->attachTexture( GFXTextureTarget::DepthStencil, GFXTextureTarget::sDefaultDepthStencil );
1460      else
1461         mTarget->attachTexture( GFXTextureTarget::DepthStencil, mTargetDepthStencil );
1462
1463      // Set the render target but not its viewport.  We'll do that below.
1464      GFX->setActiveRenderTarget( mTarget, false );
1465
1466      if(mNamedTarget.isRegistered())
1467      {
1468         // Always use the name target's viewport, if available.  It was set up in _setupTarget().
1469         GFX->setViewport(mNamedTarget.getViewport());
1470      }
1471      else if(mTargetViewport == PFXTargetViewport_GFXViewport)
1472      {
1473         // Go with the current viewport as scaled against our render target.
1474         const Point2I &oldTargetSize = oldTarget->getSize();
1475         const Point2I &targetSize = mTarget->getSize();
1476         Point2F scale(targetSize.x / F32(oldTargetSize.x), targetSize.y / F32(oldTargetSize.y));
1477         GFX->setViewport( RectI( oldViewport.point.x*scale.x, oldViewport.point.y*scale.y, oldViewport.extent.x*scale.x, oldViewport.extent.y*scale.y ) );
1478      }
1479      else if(mTargetViewport == PFXTargetViewport_NamedInTexture0 && mActiveNamedTarget[0] && mActiveNamedTarget[0]->getTexture())
1480      {
1481         // Go with the first input texture, if it is named.  Scale the named input texture's viewport to match our target
1482         const Point3I &namedTargetSize = mActiveNamedTarget[0]->getTexture()->getSize();
1483         const Point2I &targetSize = mTarget->getSize();
1484         Point2F scale(targetSize.x / F32(namedTargetSize.x), targetSize.y / F32(namedTargetSize.y));
1485
1486         const RectI &viewport = mActiveNamedTarget[0]->getViewport();
1487
1488         GFX->setViewport( RectI( viewport.point.x*scale.x, viewport.point.y*scale.y, viewport.extent.x*scale.x, viewport.extent.y*scale.y ) );
1489      }
1490      else
1491      {
1492         // Default to using the whole target as the viewport
1493         GFX->setViewport( RectI( Point2I::Zero, mTarget->getSize() ) );
1494      }
1495   }
1496
1497   if ( clearTarget )
1498      GFX->clear( GFXClearTarget, mTargetClearColor, 1.f, 0 );
1499
1500   // Setup the shader and constants.
1501   if ( mShader )
1502   {
1503      GFX->setShader( mShader );
1504      _setupConstants( state );
1505
1506      GFX->setShaderConstBuffer( mShaderConsts );
1507   }
1508   else
1509      GFX->setupGenericShaders();
1510
1511   Frustum frustum;
1512   if ( state )
1513      frustum = state->getCameraFrustum();
1514   else
1515   {
1516      // If we don't have a scene state then setup
1517      // a dummy frustum... you better not be depending
1518      // on this being related to the camera in any way.
1519      
1520      frustum = Frustum();
1521   }
1522
1523   GFXVertexBufferHandle<PFXVertex> vb;
1524   _updateScreenGeometry( frustum, &vb );
1525
1526   // Draw it.
1527   GFX->setVertexBuffer( vb );
1528   GFX->drawPrimitive( GFXTriangleStrip, 0, 2 );
1529
1530   // Allow PostEffecVis to hook in.
1531   PFXVIS->onPFXProcessed( this );
1532
1533   if ( mTargetTex || mTargetDepthStencil )
1534   {
1535      mTarget->resolve();
1536      GFX->popActiveRenderTarget();
1537   }
1538   else
1539   {
1540      // We wrote to the active back buffer, so release
1541      // the current texture copy held by the manager.
1542      //
1543      // This ensures a new copy is made.
1544      PFXMGR->releaseBackBufferTex();
1545   }
1546
1547   // Return and release our target texture.
1548   inOutTex = mTargetTex;
1549   if ( !mNamedTarget.isRegistered() )
1550      mTargetTex = NULL;
1551
1552   // Restore the transforms before the children
1553   // are processed as it screws up the viewport.
1554   saver.restore();
1555
1556   // Now process my children.
1557   iterator i = begin();
1558   for ( ; i != end(); i++ )
1559   {
1560      PostEffect *effect = static_cast<PostEffect*>(*i);
1561      effect->process( state, inOutTex );
1562   }
1563
1564   if ( mOneFrameOnly )
1565      mOnThisFrame = false;
1566}
1567
1568bool PostEffect::_setIsEnabled( void *object, const char *index, const char *data )
1569{
1570   bool enabled = dAtob( data );
1571   if ( enabled )
1572      static_cast<PostEffect*>( object )->enable();
1573   else
1574      static_cast<PostEffect*>( object )->disable();
1575
1576   // Always return false from a protected field.
1577   return false;
1578}
1579
1580void PostEffect::enable()
1581{
1582   // Don't add TexGen PostEffects to the PostEffectManager!
1583   if ( mRenderTime == PFXTexGenOnDemand )
1584      return;
1585
1586   // Ignore it if its already enabled.
1587   if ( mEnabled )
1588      return;
1589
1590   mEnabled = true;
1591
1592   // We cannot really enable the effect 
1593   // until its been registed.
1594   if ( !isProperlyAdded() )
1595      return;
1596
1597   // If the enable callback returns 'false' then 
1598   // leave the effect disabled.
1599   if ( !onEnabled_callback() )   
1600   {
1601      mEnabled = false;
1602      return;
1603   }
1604
1605   PFXMGR->_addEffect( this );
1606}
1607
1608void PostEffect::disable()
1609{
1610   if ( !mEnabled )
1611      return;
1612
1613   mEnabled = false;
1614   _cleanTargets( true );
1615
1616   if ( isProperlyAdded() )
1617   {
1618      PFXMGR->_removeEffect( this );
1619      onDisabled_callback();      
1620   }
1621}
1622
1623void PostEffect::reload()
1624{
1625   // Reload the shader if we have one or mark it
1626   // for updating when its processed next.
1627   if ( mShader )
1628      mShader->reload();
1629   else
1630      mUpdateShader = true;
1631
1632   // Null stateblock so it is reloaded.
1633   mStateBlock = NULL;
1634
1635   // Call reload on any children
1636   // this PostEffect may have.
1637   for ( U32 i = 0; i < size(); i++ )
1638   {
1639      PostEffect *effect = (PostEffect*)(*this)[i];
1640      effect->reload();
1641   }
1642}
1643
1644void PostEffect::setTexture( U32 index, const String &texFilePath )
1645{
1646   // Set the new texture name.
1647   mTexFilename[index] = texFilePath;
1648   mTextures[index].free();
1649
1650    // Skip empty stages or ones with variable or target names.
1651    if ( texFilePath.isEmpty() ||
1652         texFilePath[0] == '$' ||
1653         texFilePath[0] == '#' )
1654      return;
1655
1656    // Try to load the texture.
1657    mTextures[index].set( texFilePath, &PostFxTextureProfile, avar( "%s() - (line %d)", __FUNCTION__, __LINE__ ) );
1658
1659    mTextureType[index] = NormalTextureType;
1660}
1661
1662void PostEffect::setTexture(U32 index, const GFXTexHandle& texHandle)
1663{
1664   // Set the new texture name.
1665   mTexFilename[index] = "";
1666   mTextures[index].free();
1667
1668   // Skip empty stages or ones with variable or target names.
1669   if (!texHandle.isValid())
1670      return;
1671
1672   // Try to load the texture.
1673   mTextures[index] = texHandle;
1674
1675   mTextureType[index] = NormalTextureType;
1676}
1677
1678void PostEffect::setCubemapTexture(U32 index, const GFXCubemapHandle &cubemapHandle)
1679{
1680   // Set the new texture name.
1681   mCubemapTextures[index].free();
1682
1683   // Skip empty stages or ones with variable or target names.
1684   if (cubemapHandle.isNull())
1685      return;
1686
1687   // Try to load the texture.
1688   mCubemapTextures[index] = cubemapHandle;
1689
1690   mTextureType[index] = CubemapType;
1691}
1692
1693void PostEffect::setCubemapArrayTexture(U32 index, const GFXCubemapArrayHandle &cubemapArrayHandle)
1694{
1695   // Set the new texture name.
1696   mCubemapArrayTextures[index].free();
1697
1698   // Skip empty stages or ones with variable or target names.
1699   if (cubemapArrayHandle.isNull())
1700      return;
1701
1702   // Try to load the texture.
1703   mCubemapArrayTextures[index] = cubemapArrayHandle;
1704
1705   mTextureType[index] = CubemapArrayType;
1706}
1707
1708void PostEffect::setShaderConst( const String &name, const String &val )
1709{
1710   PROFILE_SCOPE( PostEffect_SetShaderConst );
1711
1712   EffectConstTable::Iterator iter = mEffectConsts.find( name );
1713   if ( iter == mEffectConsts.end() )
1714   {
1715      EffectConst *newConst = new EffectConst( name, val );
1716      iter = mEffectConsts.insertUnique( name, newConst );
1717   }
1718
1719   iter->value->set( val );
1720}
1721
1722void PostEffect::setShaderConst(const String &name, const F32 &val)
1723{
1724   PROFILE_SCOPE(PostEffect_SetShaderConst_Float);
1725
1726   EffectConstTable::Iterator iter = mEffectConsts.find(name);
1727   if (iter == mEffectConsts.end())
1728   {
1729      EffectConst *newConst = new EffectConst(name, val);
1730      iter = mEffectConsts.insertUnique(name, newConst);
1731   }
1732
1733   iter->value->set(val);
1734}
1735
1736void PostEffect::setShaderConst(const String& name, const int& val)
1737{
1738   PROFILE_SCOPE(PostEffect_SetShaderConst_Int);
1739
1740   EffectConstTable::Iterator iter = mEffectConsts.find(name);
1741   if (iter == mEffectConsts.end())
1742   {
1743      EffectConst* newConst = new EffectConst(name, val);
1744      iter = mEffectConsts.insertUnique(name, newConst);
1745   }
1746
1747   iter->value->set(val);
1748}
1749
1750void PostEffect::setShaderConst(const String &name, const Point4F &val)
1751{
1752   PROFILE_SCOPE(PostEffect_SetShaderConst_Point);
1753
1754   EffectConstTable::Iterator iter = mEffectConsts.find(name);
1755   if (iter == mEffectConsts.end())
1756   {
1757      EffectConst *newConst = new EffectConst(name, val);
1758      iter = mEffectConsts.insertUnique(name, newConst);
1759   }
1760
1761   iter->value->set(val);
1762}
1763
1764void PostEffect::setShaderConst(const String &name, const MatrixF &val)
1765{
1766   PROFILE_SCOPE(PostEffect_SetShaderConst_Matrix);
1767
1768   EffectConstTable::Iterator iter = mEffectConsts.find(name);
1769   if (iter == mEffectConsts.end())
1770   {
1771      EffectConst *newConst = new EffectConst(name, val);
1772      iter = mEffectConsts.insertUnique(name, newConst);
1773   }
1774
1775   iter->value->set(val);
1776}
1777
1778void PostEffect::setShaderConst(const String &name, const Vector<Point4F> &val)
1779{
1780   PROFILE_SCOPE(PostEffect_SetShaderConst_PointArray);
1781
1782   EffectConstTable::Iterator iter = mEffectConsts.find(name);
1783   if (iter == mEffectConsts.end())
1784   {
1785      EffectConst *newConst = new EffectConst(name, val);
1786      iter = mEffectConsts.insertUnique(name, newConst);
1787   }
1788
1789   iter->value->set(val);
1790}
1791
1792void PostEffect::setShaderConst(const String &name, const Vector<MatrixF> &val)
1793{
1794   PROFILE_SCOPE(PostEffect_SetShaderConst_MatrixArray);
1795
1796   EffectConstTable::Iterator iter = mEffectConsts.find(name);
1797   if (iter == mEffectConsts.end())
1798   {
1799      EffectConst *newConst = new EffectConst(name, val);
1800      iter = mEffectConsts.insertUnique(name, newConst);
1801   }
1802
1803   iter->value->set(val);
1804}
1805
1806F32 PostEffect::getAspectRatio() const
1807{
1808   const Point2I &rtSize = GFX->getActiveRenderTarget()->getSize();
1809   return (F32)rtSize.x / (F32)rtSize.y;
1810}
1811
1812void PostEffect::_checkRequirements()
1813{
1814   // This meets requirements if its shader loads
1815   // properly, we can find all the input textures,
1816   // and its formats are supported.
1817
1818   mIsValid = false;
1819   mUpdateShader = false;
1820   mShader = NULL;
1821   mShaderConsts = NULL;
1822   EffectConstTable::Iterator iter = mEffectConsts.begin();
1823   for ( ; iter != mEffectConsts.end(); iter++ )
1824   {
1825      iter->value->mDirty = true;
1826      iter->value->mHandle = NULL;
1827   }
1828
1829   // First make sure the target format is supported.
1830   if ( mNamedTarget.isRegistered() )
1831   {
1832      Vector<GFXFormat> formats;
1833      formats.push_back( mTargetFormat );
1834      GFXFormat format = GFX->selectSupportedFormat(  &PostFxTargetProfile,
1835                                                      formats, 
1836                                                      true,
1837                                                      false,
1838                                                      false );
1839      
1840      // If we didn't get our format out then its unsupported!
1841      if ( format != mTargetFormat )
1842         return;
1843   }
1844
1845   // Gather macros specified on this PostEffect.
1846   Vector<GFXShaderMacro> macros( mShaderMacros );
1847
1848   // Now check the input named targets and make sure
1849   // they exist... else we're invalid.
1850   for ( U32 i=0; i < NumTextures; i++ )
1851   {
1852      if (mTextureType[i] == NormalTextureType)
1853      {
1854         const String &texFilename = mTexFilename[i];
1855
1856         if (texFilename.isNotEmpty() && texFilename[0] == '#')
1857         {
1858            NamedTexTarget *namedTarget = NamedTexTarget::find(texFilename.c_str() + 1);
1859            if (!namedTarget)
1860            {
1861               return;
1862            }
1863
1864            // Grab the macros for shader initialization.
1865            namedTarget->getShaderMacros(&macros);
1866         }
1867      }
1868   }
1869
1870   // Finally find and load the shader.
1871   ShaderData *shaderData;
1872   if ( Sim::findObject( mShaderName, shaderData ) )   
1873      if ( shaderData->getPixVersion() <= GFX->getPixelShaderVersion() )
1874         mShader = shaderData->getShader( macros );
1875
1876   // If we didn't get a shader... we're done.
1877   if ( !mShader )
1878      return;
1879
1880   // If we got here then we're valid.
1881   mIsValid = true;
1882}
1883
1884bool PostEffect::dumpShaderDisassembly( String &outFilename ) const
1885{
1886   String data;
1887
1888   if ( !mShader || !mShader->getDisassembly( data ) )
1889      return false;
1890         
1891   outFilename = FS::MakeUniquePath( "", "ShaderDisassembly", "txt" );
1892
1893   FileStream *fstream = FileStream::createAndOpen( outFilename, Torque::FS::File::Write );
1894   if ( !fstream )
1895      return false;
1896
1897   fstream->write( data );
1898   fstream->close();
1899   delete fstream;   
1900
1901   return true;
1902}
1903
1904SimSet* PostEffect::getSet() const
1905{
1906   SimSet *set;
1907   if ( !Sim::findObject( "PFXSet", set ) )
1908   {
1909      set = new SimSet();
1910      set->registerObject( "PFXSet" );
1911      Sim::getRootGroup()->addObject( set );
1912   }
1913
1914   return set;
1915}
1916
1917void PostEffect::setShaderMacro( const String &name, const String &value )
1918{
1919   // Check to see if we already have this macro.
1920   Vector<GFXShaderMacro>::iterator iter = mShaderMacros.begin();
1921   for ( ; iter != mShaderMacros.end(); iter++ )
1922   {
1923      if ( iter->name == name )
1924      {
1925         if ( iter->value != value )
1926         {
1927            iter->value = value;
1928            mUpdateShader = true;
1929         }
1930         return;
1931      }
1932   }
1933
1934   // Add a new macro.
1935   mShaderMacros.increment();
1936   mShaderMacros.last().name = name;
1937   mShaderMacros.last().value = value;
1938   mUpdateShader = true;
1939}
1940
1941bool PostEffect::removeShaderMacro( const String &name )
1942{
1943   Vector<GFXShaderMacro>::iterator iter = mShaderMacros.begin();
1944   for ( ; iter != mShaderMacros.end(); iter++ )
1945   {
1946      if ( iter->name == name )
1947      {
1948         mShaderMacros.erase( iter );
1949         mUpdateShader = true;
1950         return true;
1951      }
1952   }
1953
1954   return false;
1955}
1956
1957void PostEffect::clearShaderMacros()
1958{
1959   if ( mShaderMacros.empty() )
1960      return;
1961
1962   mShaderMacros.clear();
1963   mUpdateShader = true;
1964}
1965
1966GFXTextureObject* PostEffect::_getTargetTexture( U32 )
1967{
1968   // A TexGen PostEffect will generate its texture now if it
1969   // has not already.
1970   if (  mRenderTime == PFXTexGenOnDemand &&
1971         ( !mTargetTex || mUpdateShader ) )
1972   {
1973      GFXTexHandle chainTex;
1974      process( NULL, chainTex );
1975      
1976      // TODO: We should add a conditional copy
1977      // to a non-RT texture here to reduce the
1978      // amount of non-swappable RTs in use.      
1979   }
1980
1981   return mTargetTex.getPointer();
1982}
1983
1984DefineEngineMethod( PostEffect, reload, void, (),,
1985   "Reloads the effect shader and textures." )
1986{
1987   return object->reload();
1988}
1989
1990DefineEngineMethod( PostEffect, enable, void, (),,
1991   "Enables the effect." )
1992{
1993   object->enable();
1994}
1995
1996DefineEngineMethod( PostEffect, disable, void, (),,
1997   "Disables the effect." )
1998{
1999   object->disable();
2000}
2001
2002DefineEngineMethod( PostEffect, toggle, bool, (),,
2003   "Toggles the effect between enabled / disabled.\n"
2004   "@return True if effect is enabled." )
2005{
2006   if ( object->isEnabled() )
2007      object->disable();
2008   else
2009      object->enable();
2010
2011   return object->isEnabled();
2012}
2013
2014DefineEngineMethod( PostEffect, isEnabled, bool, (),,
2015   "@return True if the effect is enabled." )
2016{
2017   return object->isEnabled();
2018}
2019
2020DefineEngineMethod( PostEffect, setTexture, void, ( S32 index, const char *filePath ),,
2021   "This is used to set the texture file and load the texture on a running effect. "
2022   "If the texture file is not different from the current file nothing is changed.  If "
2023   "the texture cannot be found a null texture is assigned.\n"    
2024   "@param index The texture stage index.\n" 
2025   "@param filePath The file name of the texture to set.\n" )
2026{   
2027   if ( index > -1 && index < PostEffect::NumTextures )
2028      object->setTexture( index, filePath );
2029}
2030
2031DefineEngineMethod( PostEffect, setShaderConst, void, ( const char* name, const char* value ),,
2032   "Sets the value of a uniform defined in the shader. This will usually "
2033   "be called within the setShaderConsts callback. Array type constants are "
2034   "not supported.\n"    
2035   "@param name Name of the constanst, prefixed with '$'.\n" 
2036   "@param value Value to set, space seperate values with more than one element.\n"
2037   "@tsexample\n"
2038   "function MyPfx::setShaderConsts( %this )\n"
2039   "{\n"
2040   "   // example float4 uniform\n"
2041   "   %this.setShaderConst( \"$colorMod\", \"1.0 0.9 1.0 1.0\" );\n"
2042   "   // example float1 uniform\n"
2043   "   %this.setShaderConst( \"$strength\", \"3.0\" );\n"
2044   "   // example integer uniform\n"
2045   "   %this.setShaderConst( \"$loops\", \"5\" );"
2046   "}\n"
2047   "@endtsexample" )   
2048{
2049   object->setShaderConst( name, value );
2050}
2051
2052DefineEngineMethod( PostEffect, getAspectRatio, F32, (),,
2053   "@return Width over height of the backbuffer." )
2054{
2055   return object->getAspectRatio();
2056}
2057
2058DefineEngineMethod( PostEffect, dumpShaderDisassembly, String, (),,
2059   "Dumps this PostEffect shader's disassembly to a temporary text file.\n"
2060   "@return Full path to the dumped file or an empty string if failed." )
2061{
2062   String fileName;
2063   object->dumpShaderDisassembly( fileName );
2064
2065   return fileName;   
2066}
2067
2068DefineEngineMethod( PostEffect, setShaderMacro, void, ( const char* key, const char* value ), ( "" ),
2069   "Adds a macro to the effect's shader or sets an existing one's value. "
2070   "This will usually be called within the onAdd or preProcess callback.\n"
2071   "@param key lval of the macro."
2072   "@param value rval of the macro, or may be empty."
2073   "@tsexample\n"
2074   "function MyPfx::onAdd( %this )\n"
2075   "{\n"
2076   "   %this.setShaderMacro( \"NUM_SAMPLES\", \"10\" );\n"
2077   "   %this.setShaderMacro( \"HIGH_QUALITY_MODE\" );\n"
2078   "   \n"
2079   "   // In the shader looks like... \n"
2080   "   // #define NUM_SAMPLES 10\n"
2081   "   // #define HIGH_QUALITY_MODE\n"
2082   "}\n"
2083   "@endtsexample" )
2084{   
2085   object->setShaderMacro( key, value );
2086}
2087
2088DefineEngineMethod( PostEffect, removeShaderMacro, void, ( const char* key ),,
2089   "Remove a shader macro. This will usually be called within the preProcess callback.\n"
2090   "@param key Macro to remove." )
2091{
2092   object->removeShaderMacro( key );
2093}
2094
2095DefineEngineMethod( PostEffect, clearShaderMacros, void, (),,
2096   "Remove all shader macros." )
2097{
2098   object->clearShaderMacros();
2099}
2100
2101DefineEngineFunction( dumpRandomNormalMap, void, (),,
2102   "Creates a 64x64 normal map texture filled with noise. The texture is saved "
2103   "to randNormTex.png in the location of the game executable.\n\n"
2104   "@ingroup GFX")
2105{
2106   GFXTexHandle tex;
2107
2108   tex.set( 64, 64, GFXFormatR8G8B8A8, &GFXTexturePersistentProfile, "" );
2109
2110   GFXLockedRect *rect = tex.lock();
2111   U8 *f = rect->bits;
2112
2113   for ( U32 i = 0; i < 64*64; i++, f += 4 )
2114   {               
2115      VectorF vec;
2116
2117      vec.x = mRandF( -1.0f, 1.0f );
2118      vec.y = mRandF( -1.0f, 1.0f );
2119      vec.z = mRandF( -1.0f, 1.0f );
2120
2121      vec.normalizeSafe();
2122
2123      f[0] = U8_MAX * ( ( 1.0f + vec.x ) * 0.5f );
2124      f[1] = U8_MAX * ( ( 1.0f + vec.y ) * 0.5f );
2125      f[2] = U8_MAX * ( ( 1.0f + vec.z ) * 0.5f );
2126      f[3] = U8_MAX;
2127   }
2128
2129   tex.unlock();
2130
2131   String path = Torque::FS::MakeUniquePath( "", "randNormTex", "png" );
2132   tex->dumpToDisk( "png", path );   
2133}
2134