2
0

postEffect.cpp 67 KB

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