1 // =============================================================================
2 // PROJECT CHRONO - http://projectchrono.org
3 //
4 // Copyright (c) 2014 projectchrono.org
5 // All rights reserved.
6 //
7 // Use of this source code is governed by a BSD-style license that can be found
8 // in the LICENSE file at the top level of the distribution and at
9 // http://projectchrono.org/license-chrono.txt.
10 //
11 // =============================================================================
12 
13 #ifndef CHIRREFFECTS_H
14 #define CHIRREFFECTS_H
15 
16 #include <irrlicht.h>
17 
18 namespace chrono {
19 namespace irrlicht {
20 
21 /// @addtogroup irrlicht_module
22 /// @{
23 
24 /// CShaderPreprocessor
25 class CShaderPreprocessor {
26   public:
27     CShaderPreprocessor(irr::video::IVideoDriver* driverIn);
28     irr::core::stringc ppShader(irr::core::stringc shaderProgram);
29     irr::core::stringc ppShaderFF(irr::core::stringc shaderProgram);
30     void addShaderDefine(const irr::core::stringc name, const irr::core::stringc value = "");
31     void removeShaderDefine(const irr::core::stringc name);
32 
33   private:
34     void initDefineMap();
35 
36     irr::video::IVideoDriver* driver;
37     irr::core::map<irr::core::stringc, irr::core::stringc> DefineMap;
38 };
39 
40 class EffectHandler;
41 
42 /// DepthShaderCB
43 class DepthShaderCB : public irr::video::IShaderConstantSetCallBack {
44   public:
DepthShaderCB(EffectHandler * effectIn)45     DepthShaderCB(EffectHandler* effectIn) : effect(effectIn){};
46 
OnSetConstants(irr::video::IMaterialRendererServices * services,irr::s32 userData)47     virtual void OnSetConstants(irr::video::IMaterialRendererServices* services, irr::s32 userData) {
48         irr::video::IVideoDriver* driver = services->getVideoDriver();
49 
50         worldViewProj = driver->getTransform(irr::video::ETS_PROJECTION);
51         worldViewProj *= driver->getTransform(irr::video::ETS_VIEW);
52         worldViewProj *= driver->getTransform(irr::video::ETS_WORLD);
53 
54         services->setVertexShaderConstant("mWorldViewProj", worldViewProj.pointer(), 16);
55 
56         services->setVertexShaderConstant("MaxD", &FarLink, 1);
57     }
58 
59     EffectHandler* effect;
60     irr::f32 FarLink;
61     irr::core::matrix4 worldViewProj;
62 };
63 
64 /// ShadowShaderCB
65 class ShadowShaderCB : public irr::video::IShaderConstantSetCallBack {
66   public:
ShadowShaderCB(EffectHandler * effectIn)67     ShadowShaderCB(EffectHandler* effectIn) : effect(effectIn){};
68 
OnSetMaterial(const irr::video::SMaterial & material)69     virtual void OnSetMaterial(const irr::video::SMaterial& material) {}
70 
OnSetConstants(irr::video::IMaterialRendererServices * services,irr::s32 userData)71     virtual void OnSetConstants(irr::video::IMaterialRendererServices* services, irr::s32 userData) {
72         irr::video::IVideoDriver* driver = services->getVideoDriver();
73 
74         irr::core::matrix4 worldViewProj = driver->getTransform(irr::video::ETS_PROJECTION);
75         worldViewProj *= driver->getTransform(irr::video::ETS_VIEW);
76         worldViewProj *= driver->getTransform(irr::video::ETS_WORLD);
77         services->setVertexShaderConstant("mWorldViewProj", worldViewProj.pointer(), 16);
78 
79         worldViewProj = ProjLink;
80         worldViewProj *= ViewLink;
81         worldViewProj *= driver->getTransform(irr::video::ETS_WORLD);
82         services->setVertexShaderConstant("mWorldViewProj2", worldViewProj.pointer(), 16);
83 
84         driver->getTransform(irr::video::ETS_WORLD).getInverse(invWorld);
85         irr::core::vector3df lightPosOS = LightLink;
86         invWorld.transformVect(lightPosOS);
87         services->setVertexShaderConstant("LightPos", reinterpret_cast<irr::f32*>(&lightPosOS.X), 4);
88 
89         services->setVertexShaderConstant("MaxD", reinterpret_cast<irr::f32*>(&FarLink), 1);
90         services->setVertexShaderConstant("MAPRES", &MapRes, 1);
91 
92         services->setPixelShaderConstant("LightColour", reinterpret_cast<irr::f32*>(&LightColour.r), 4);
93         float fclipborder = clipborder;
94         services->setPixelShaderConstant("ClipBorder", reinterpret_cast<irr::f32*>(&fclipborder), 1);
95     }
96 
97     EffectHandler* effect;
98     irr::core::matrix4 invWorld;
99 
100     irr::video::SColorf LightColour;
101     irr::core::matrix4 ProjLink;
102     irr::core::matrix4 ViewLink;
103     irr::core::vector3df LightLink;
104     irr::f32 FarLink, MapRes;
105     bool clipborder;  //***ALEX***
106 };
107 
108 /// ScreenQuadCB
109 class ScreenQuadCB : public irr::video::IShaderConstantSetCallBack {
110   public:
effect(effectIn)111     ScreenQuadCB(EffectHandler* effectIn, bool defaultV = true) : effect(effectIn), defaultVertexShader(defaultV){};
112 
113     EffectHandler* effect;
114     bool defaultVertexShader;
115 
116     virtual void OnSetConstants(irr::video::IMaterialRendererServices* services, irr::s32 userData);
117 
118     struct SUniformDescriptor {
SUniformDescriptorSUniformDescriptor119         SUniformDescriptor() : fPointer(0), paramCount(0) {}
120 
SUniformDescriptorSUniformDescriptor121         SUniformDescriptor(const irr::f32* fPointerIn, irr::u32 paramCountIn)
122             : fPointer(fPointerIn), paramCount(paramCountIn) {}
123 
124         const irr::f32* fPointer;
125         irr::u32 paramCount;
126     };
127 
128     irr::core::map<irr::core::stringc, SUniformDescriptor> uniformDescriptors;
129 };
130 
131 struct SDefineExp {
SDefineExpSDefineExp132     SDefineExp() : IfPos(-1), ElsePos(-1), EndPos(-1), IfExp(""), Inverse(false){};
133     irr::s32 IfPos;
134     irr::s32 ElsePos;
135     irr::s32 EndPos;
136     irr::core::stringc IfExp;
137     bool Inverse;
138 };
139 
grabDefineExpressions(irr::core::stringc & shaderProgram)140 inline irr::core::array<SDefineExp> grabDefineExpressions(irr::core::stringc& shaderProgram) {
141     irr::s32 CurrentSearchPos = 1;
142     irr::s32 FindHelper = 1;
143     irr::s32 FindHelper2 = 1;
144 
145     irr::core::array<SDefineExp> DefineArray;
146 
147     // Dont bother stripping comments if theres no defines.
148     CurrentSearchPos = shaderProgram.find("##ifdef");
149     if (CurrentSearchPos == -1)
150         return DefineArray;
151 
152     // Strip all comments, they get in the way.
153     while ((CurrentSearchPos = shaderProgram.find("//")) > -1) {
154         FindHelper = shaderProgram.findNext('\n', CurrentSearchPos);
155         if (FindHelper != -1)
156             for (irr::u32 i = CurrentSearchPos; i < (irr::u32)FindHelper; ++i)
157                 shaderProgram[i] = ' ';
158         else
159             for (irr::u32 i = CurrentSearchPos; i < shaderProgram.size(); ++i)
160                 shaderProgram[i] = ' ';
161     }
162 
163     while ((CurrentSearchPos = shaderProgram.find("/*")) > -1) {
164         FindHelper = shaderProgram.find("*/");
165         if (FindHelper > CurrentSearchPos)
166             for (irr::u32 i = CurrentSearchPos; i <= (irr::u32)(FindHelper + 1); ++i)
167                 shaderProgram[i] = ' ';
168         else
169             for (irr::u32 i = CurrentSearchPos; i < shaderProgram.size(); ++i)
170                 shaderProgram[i] = ' ';
171     }
172 
173     while ((CurrentSearchPos = shaderProgram.find("##ifdef")) > -1) {
174         SDefineExp DExp;
175 
176         DExp.IfPos = CurrentSearchPos;
177 
178         // Comment out the ##ifdef so that we do not find it again, and so that the compiler ignores it.
179         shaderProgram[CurrentSearchPos] = '/';
180         shaderProgram[CurrentSearchPos + 1] = '/';
181 
182         FindHelper = shaderProgram.findNext(' ', CurrentSearchPos);
183         FindHelper2 = shaderProgram.findNext('\n', FindHelper);
184 
185         if (FindHelper == -1 || FindHelper2 == -1) {
186             std::cerr << "Shader preprocessor encountered invalid if statement." << std::endl;
187             return DefineArray;
188         }
189 
190         // Find the appropriate expression and trim all white space.
191         DExp.IfExp = shaderProgram.subString(FindHelper, FindHelper2 - FindHelper);
192         DExp.IfExp.trim();
193 
194         // Record if its inverse and remove ! sign from expression.
195         if (DExp.IfExp[0] == '!') {
196             DExp.IfExp[0] = ' ';
197             DExp.IfExp.trim();
198             DExp.Inverse = true;
199         }
200 
201         bool EndIfFound = false;
202 
203         FindHelper2 = CurrentSearchPos;
204         irr::s32 IfEndScope = 0;
205 
206         while (!EndIfFound) {
207             FindHelper = shaderProgram.findNext('#', FindHelper2);
208 
209             if (FindHelper == -1 || FindHelper >= (irr::s32)(shaderProgram.size() - 3)) {
210                 std::cerr << "Shader preprocessor encountered unmatched if statement." << std::endl;
211                 return DefineArray;
212             }
213 
214             if (IfEndScope < 0) {
215                 std::cerr << "Shader preprocessor encountered unmatched endif statement." << std::endl;
216                 return DefineArray;
217             }
218 
219             if (shaderProgram[FindHelper + 1] != '#') {
220                 FindHelper2 = FindHelper + 1;
221                 continue;
222             } else if (shaderProgram[FindHelper + 2] == 'i') {
223                 IfEndScope++;
224             } else if (shaderProgram[FindHelper + 2] == 'e' && shaderProgram[FindHelper + 3] == 'n') {
225                 if (IfEndScope == 0)
226                     break;
227 
228                 IfEndScope--;
229             } else if (shaderProgram[FindHelper + 2] == 'e' && shaderProgram[FindHelper + 3] == 'l') {
230                 if (IfEndScope == 0) {
231                     if (DExp.ElsePos != -1) {
232                         std::cerr << "Shader preprocessor encountered duplicate else statements per if statement."
233                                   << std::endl;
234                         return DefineArray;
235                     }
236 
237                     // Comment out the ##else so that we do not find it again, and so that the compiler ignores it.
238                     shaderProgram[FindHelper] = '/';
239                     shaderProgram[FindHelper + 1] = '/';
240 
241                     DExp.ElsePos = FindHelper;
242                 }
243             }
244 
245             FindHelper2 = FindHelper + 2;
246         }
247 
248         // Comment out the ##endif so that we do not find it again, and so that the compiler ignores it.
249         shaderProgram[FindHelper] = '/';
250         shaderProgram[FindHelper + 1] = '/';
251 
252         DExp.EndPos = FindHelper;
253 
254         // Add the define expression to the array.
255         DefineArray.push_back(DExp);
256     }
257 
258     return DefineArray;
259 }
260 
CShaderPreprocessor(irr::video::IVideoDriver * driverIn)261 inline CShaderPreprocessor::CShaderPreprocessor(irr::video::IVideoDriver* driverIn) : driver(driverIn) {
262     initDefineMap();
263 };
264 
initDefineMap()265 inline void CShaderPreprocessor::initDefineMap() {
266     if (driver->queryFeature(irr::video::EVDF_TEXTURE_NPOT))
267         DefineMap["EVDF_TEXTURE_NPOT"] = "";
268     if (driver->queryFeature(irr::video::EVDF_FRAMEBUFFER_OBJECT))
269         DefineMap["EVDF_FRAMEBUFFER_OBJECT"] = "";
270     if (driver->queryFeature(irr::video::EVDF_VERTEX_SHADER_1_1))
271         DefineMap["EVDF_VERTEX_SHADER_1_1"] = "";
272     if (driver->queryFeature(irr::video::EVDF_VERTEX_SHADER_2_0))
273         DefineMap["EVDF_VERTEX_SHADER_2_0"] = "";
274     if (driver->queryFeature(irr::video::EVDF_VERTEX_SHADER_3_0))
275         DefineMap["EVDF_VERTEX_SHADER_3_0"] = "";
276     if (driver->queryFeature(irr::video::EVDF_PIXEL_SHADER_1_1))
277         DefineMap["EVDF_PIXEL_SHADER_1_1"] = "";
278     if (driver->queryFeature(irr::video::EVDF_PIXEL_SHADER_1_2))
279         DefineMap["EVDF_PIXEL_SHADER_1_2"] = "";
280     if (driver->queryFeature(irr::video::EVDF_PIXEL_SHADER_1_3))
281         DefineMap["EVDF_PIXEL_SHADER_1_3"] = "";
282     if (driver->queryFeature(irr::video::EVDF_PIXEL_SHADER_1_4))
283         DefineMap["EVDF_PIXEL_SHADER_1_4"] = "";
284     if (driver->queryFeature(irr::video::EVDF_PIXEL_SHADER_2_0))
285         DefineMap["EVDF_PIXEL_SHADER_2_0"] = "";
286     if (driver->queryFeature(irr::video::EVDF_PIXEL_SHADER_3_0))
287         DefineMap["EVDF_PIXEL_SHADER_3_0"] = "";
288 
289     // Commented for backwards compatibility.
290     // DefineMap[driver->getVendorInfo()] = "";
291 }
292 
addShaderDefine(const irr::core::stringc name,const irr::core::stringc value)293 inline void CShaderPreprocessor::addShaderDefine(const irr::core::stringc name, const irr::core::stringc value) {
294     // No need for this as its already inited at startup.
295     //// If DefineMap is empty then initialize it.
296     // if(DefineMap.isEmpty())
297     //	initDefineMap();
298 
299     DefineMap[name] = value;
300 }
301 
removeShaderDefine(const irr::core::stringc name)302 inline void CShaderPreprocessor::removeShaderDefine(const irr::core::stringc name) {
303     DefineMap.remove(name);
304 }
305 
306 //! PreProcesses a shader using Irrlicht's built-in shader preprocessor.
ppShader(irr::core::stringc shaderProgram)307 inline irr::core::stringc CShaderPreprocessor::ppShader(irr::core::stringc shaderProgram) {
308     irr::core::array<SDefineExp> DefineArray = grabDefineExpressions(shaderProgram);
309 
310     // No need for this as its already inited at startup.
311     //// If DefineMap is empty then initialize it.
312     // if(DefineMap.isEmpty())
313     //	initDefineMap();
314 
315     for (irr::u32 i = 0; i < DefineArray.size(); ++i) {
316         if (DefineArray[i].IfPos == -1)
317             break;
318 
319         // Either it is true and not inversed, or it is false, but inversed.
320         // (Wish C++ had a built-in (logical) XOR operator sometimes. :P)
321         if ((DefineMap.find(DefineArray[i].IfExp) && !DefineArray[i].Inverse) ||
322             (!DefineMap.find(DefineArray[i].IfExp) && DefineArray[i].Inverse)) {
323             if (DefineArray[i].ElsePos > -1) {
324                 // If there is an else statement then clear the else section.
325                 if (DefineArray[i].EndPos != -1) {
326                     for (int z = DefineArray[i].ElsePos; z <= DefineArray[i].EndPos + 6; ++z)
327                         shaderProgram[z] = ' ';
328                 }
329             }
330         } else if (DefineArray[i].ElsePos != -1) {
331             // If there is an else statement then clear the if section.
332             for (int z = DefineArray[i].IfPos; z <= DefineArray[i].ElsePos + 5; ++z)
333                 shaderProgram[z] = ' ';
334         } else {
335             // Else just clear the whole block.
336             if (DefineArray[i].EndPos != -1) {
337                 for (int z = DefineArray[i].IfPos; z <= DefineArray[i].EndPos + 6; ++z)
338                     shaderProgram[z] = ' ';
339             }
340         }
341     }
342 
343     irr::core::map<irr::core::stringc, irr::core::stringc>::ParentFirstIterator DefIter;
344     irr::s32 DefFinder = 1;
345 
346     // Replace all shader defines.
347     for (DefIter = DefineMap.getParentFirstIterator(); !DefIter.atEnd(); DefIter++) {
348         if (DefIter->getValue().size() == 0)
349             continue;
350 
351         // Replace all occurrences.
352         while ((DefFinder = shaderProgram.find(DefIter->getKey().c_str())) > -1) {
353             // Clear the define from the code.
354             for (irr::u32 z = DefFinder; z < DefFinder + DefIter->getKey().size(); ++z)
355                 shaderProgram[z] = ' ';
356 
357             // Stitch value and shader program together. (Is there a faster way?)
358             shaderProgram = shaderProgram.subString(0, DefFinder) + DefIter->getValue() +
359                             shaderProgram.subString(DefFinder, shaderProgram.size() - 1);
360         }
361     }
362 
363     return shaderProgram;
364 }
365 
getFileContent(const std::string pFile)366 inline std::string getFileContent(const std::string pFile) {
367     std::ifstream File(pFile.c_str(), std::ios::in);
368     std::string Content;
369 
370     if (File.is_open()) {
371         for (std::string Line; std::getline(File, Line);)
372             Content += Line + "\n";
373 
374         File.close();
375     }
376 
377     return Content;
378 }
379 
380 //! PreProcesses a shader using Irrlicht's built-in shader preprocessor.
ppShaderFF(irr::core::stringc shaderProgram)381 inline irr::core::stringc CShaderPreprocessor::ppShaderFF(irr::core::stringc shaderProgram) {
382     return ppShader(getFileContent(shaderProgram.c_str()).c_str());
383 }
384 
385 //***ALEX*** fixes for Irrlicht 1.8
386 
387 /// CScreenQuad
388 class CScreenQuad {
389   public:
CScreenQuad()390     CScreenQuad() {
391         Material.Wireframe = false;
392         Material.Lighting = false;
393         Material.ZWriteEnable = false;
394 
395         Vertices[0] = irr::video::S3DVertex(-1.0f, -1.0f, 0.0f, 0, 0, 1, irr::video::SColor(0x0), 0.0f, 1.0f);
396         Vertices[1] = irr::video::S3DVertex(-1.0f, 1.0f, 0.0f, 0, 0, 1, irr::video::SColor(0x0), 0.0f, 0.0f);
397         Vertices[2] = irr::video::S3DVertex(1.0f, 1.0f, 0.0f, 0, 0, 1, irr::video::SColor(0x0), 1.0f, 0.0f);
398         Vertices[3] = irr::video::S3DVertex(1.0f, -1.0f, 0.0f, 0, 0, 1, irr::video::SColor(0x0), 1.0f, 1.0f);
399     }
400 
~CScreenQuad()401     virtual ~CScreenQuad() {}
402 
render(irr::video::IVideoDriver * driver)403     virtual void render(irr::video::IVideoDriver* driver) {
404         const irr::u16 indices[6] = {0, 1, 2, 0, 2, 3};
405 
406         driver->setMaterial(Material);
407         driver->setTransform(irr::video::ETS_WORLD, irr::core::matrix4());
408         driver->drawIndexedTriangleList(&Vertices[0], 4, &indices[0], 2);
409     }
410 
getMaterial()411     virtual irr::video::SMaterial& getMaterial() { return Material; }
412 
413     irr::video::ITexture* rt[2];
414 
415   private:
416     irr::video::S3DVertex Vertices[4];
417     irr::video::SMaterial Material;
418 };
419 
420 /*
421 class CScreenQuad
422 {
423 public:
424     CScreenQuad()
425     {
426         Material.Wireframe = false;
427         Material.Lighting = false;
428         Material.ZWriteEnable = false;
429 
430         Vertices[0] = irr::video::S3DVertex(-1.0f,-1.0f,0.0f,0,0,1,irr::video::SColor(0x0),0.0f,1.0f);
431         Vertices[1] = irr::video::S3DVertex(-1.0f, 1.0f,0.0f,0,0,1,irr::video::SColor(0x0),0.0f,0.0f);
432         Vertices[2] = irr::video::S3DVertex( 1.0f, 1.0f,0.0f,0,0,1,irr::video::SColor(0x0),1.0f,0.0f);
433         Vertices[3] = irr::video::S3DVertex( 1.0f,-1.0f,0.0f,0,0,1,irr::video::SColor(0x0),1.0f,1.0f);
434         Vertices[4] = irr::video::S3DVertex(-1.0f,-1.0f,0.0f,0,0,1,irr::video::SColor(0x0),0.0f,1.0f);
435         Vertices[5] = irr::video::S3DVertex( 1.0f, 1.0f,0.0f,0,0,1,irr::video::SColor(0x0),1.0f,0.0f);
436     }
437 
438     virtual void render(irr::video::IVideoDriver* driver)
439     {
440         u16 indices[6] = {0, 1, 2, 3, 4, 5};
441 
442         driver->setMaterial(Material);
443         driver->setTransform(irr::video::ETS_WORLD, irr::core::matrix4());
444         driver->drawIndexedTriangleList(&Vertices[0], 6, &indices[0], 2);
445     }
446 
447     virtual irr::video::SMaterial& getMaterial()
448     {
449         return Material;
450     }
451 
452     irr::video::ITexture* rt[2];
453 
454 private:
455     irr::video::S3DVertex Vertices[6];
456     irr::video::SMaterial Material;
457 };
458 */
459 
460 //////////////////////////////////////EffectShaders.h
461 
462 enum E_SHADER_EXTENSION {
463     ESE_GLSL,
464     ESE_HLSL,
465 
466     ESE_COUNT
467 };
468 
469 //***ALEX***
470 // from ... const char* LIGHT_MODULATE_P ... to ... const char* const LIGHT_MODULATE_P .. to avoid multiple defined
471 // symbols
472 const char* const LIGHT_MODULATE_P[ESE_COUNT] = {
473     "uniform sampler2D ColorMapSampler;\n"
474     "uniform sampler2D ScreenMapSampler;\n"
475     ""
476     "void main() "
477     "{		"
478     "	vec4 finalCol = texture2D(ColorMapSampler, gl_TexCoord[0].xy);\n"
479     "	vec4 lightCol = texture2D(ScreenMapSampler, gl_TexCoord[0].xy);\n"
480     ""
481     "	gl_FragColor = finalCol * lightCol;\n"
482     "}",
483     "sampler2D ColorMapSampler : register(s0);\n"
484     "sampler2D ScreenMapSampler : register(s1);\n"
485     ""
486     "float4 pixelMain(float2 TexCoords : TEXCOORD0) : COLOR0"
487     "{		"
488     "	float4 finalCol = tex2D(ColorMapSampler, TexCoords);\n"
489     "	float4 lightCol = tex2D(ScreenMapSampler, TexCoords);\n"
490     ""
491     "	return finalCol * lightCol;\n"
492     "}"};
493 
494 const char* const SHADOW_PASS_1P[ESE_COUNT] = {
495     "void main() "
496     "{"
497     "	vec4 vInfo = gl_TexCoord[0];\n"
498     "	float depth = vInfo.z / vInfo.x;\n"
499     "   gl_FragColor = vec4(depth, depth * depth, 0.0, 0.0);\n"
500     "}",
501     "float4 pixelMain(float4 ClipPos: TEXCOORD0) : COLOR0"
502     "{"
503     "	float depth = ClipPos.z / ClipPos.x;\n"
504     "	return float4(depth, depth * depth, 0.0, 0.0);\n"
505     "}"};
506 
507 const char* const SHADOW_PASS_1PT[ESE_COUNT] = {
508     "uniform sampler2D ColorMapSampler;\n"
509     ""
510     "void main() "
511     "{"
512     "	vec4 vInfo = gl_TexCoord[0];\n"
513     ""
514     "	float depth = vInfo.z / vInfo.x;\n"
515     ""
516     "	float alpha = texture2D(ColorMapSampler, gl_TexCoord[1].xy).a;\n"
517     ""
518     "    gl_FragColor = vec4(depth, depth * depth, 0.0, alpha);\n"
519     "}",
520     "sampler2D ColorMapSampler : register(s0);\n"
521     ""
522     "float4 pixelMain(float4 Color: TEXCOORD0, float2 Texcoords: TEXCOORD1) : COLOR0"
523     "{"
524     "	float depth = Color.z / Color.w;\n"
525     "	"
526     "	float alpha = tex2D(ColorMapSampler, Texcoords).a;\n"
527     "	"
528     "	return float4(depth, depth * depth, 0.0, alpha);\n"
529     "}"};
530 
531 const char* const SHADOW_PASS_1V[ESE_COUNT] = {
532     "uniform mat4 mWorldViewProj;\n"
533     "uniform float MaxD;\n"
534     ""
535     "void main()"
536     "{"
537     "	vec4 tPos = mWorldViewProj * gl_Vertex;\n"
538     "	gl_Position = tPos;\n"
539     "	gl_TexCoord[0] = vec4(MaxD, tPos.y, tPos.z, tPos.w);\n"
540     ""
541     "	gl_TexCoord[1].xy = gl_MultiTexCoord0.xy;\n"
542     "}",
543     "float4x4 mWorldViewProj;\n"
544     "float MaxD;\n"
545     ""
546     "struct VS_OUTPUT "
547     "{"
548     "	float4 Position: POSITION0;\n"
549     "	float4 ClipPos: TEXCOORD0;\n"
550     "	float2 Texcoords: TEXCOORD1;\n"
551     "	float4 VColor: TEXCOORD2;\n"
552     "};\n"
553     ""
554     "VS_OUTPUT vertexMain(float3 Position : POSITION0, float2 Texcoords : TEXCOORD0, float4 vColor : COLOR0)"
555     "{"
556     "	VS_OUTPUT  OUT;\n"
557     "	float4 hpos = mul(float4(Position.x, Position.y, Position.z, 1.0), mWorldViewProj);\n"
558     "   OUT.ClipPos = hpos;\n"
559     "	OUT.ClipPos.x = MaxD;\n"
560     "   OUT.Position = hpos;\n"
561     "	OUT.Texcoords = Texcoords;\n"
562     "	OUT.VColor = vColor;\n"
563     "	return(OUT);\n"
564     "}"};
565 
566 const char* const SHADOW_PASS_2P[ESE_COUNT] = {
567     "uniform sampler2D ShadowMapSampler;\n"
568     "uniform vec4 LightColour;\n"
569     "varying float lightVal;\n"
570     ""
571     "\n##ifdef VSM\n"
572     "float testShadow(vec2 texCoords, vec2 offset, float RealDist)\n"
573     "{\n"
574     "	vec4 shadTexCol = texture2D(ShadowMapSampler, texCoords + offset);\n"
575     ""
576     "	float lit_factor = (RealDist <= shadTexCol.x) ? 1.0 : 0.0;\n"
577     ""
578     "	float E_x2 = shadTexCol.y;\n"
579     "	float Ex_2 = shadTexCol.x * shadTexCol.x;\n"
580     "	float variance = min(max(E_x2 - Ex_2, 0.00001) + 0.000001, 1.0);\n"
581     "	float m_d = (shadTexCol.x - RealDist);\n"
582     "	float p = variance / (variance + m_d * m_d);\n"
583     ""
584     "	return (1.0 - max(lit_factor, p)) / float(SAMPLE_AMOUNT);\n"
585     "}\n"
586     "##else\n"
587     "float testShadow(vec2 smTexCoord, vec2 offset, float realDistance)"
588     "{"
589     "	vec4 texDepth = texture2D(ShadowMapSampler, vec2( smTexCoord + offset));\n"
590     "	float extractedDistance = texDepth.r;\n"
591     "	"
592     "	return (extractedDistance <= realDistance) ? (1.0  / float(SAMPLE_AMOUNT)) : 0.0;\n"
593     "}\n"
594     "##endif\n"
595     "\n"
596     "vec2 offsetArray[16];\n"
597     "\n"
598     "void main() \n"
599     "{"
600     "	vec4 SMPos = gl_TexCoord[0];\n"
601     "	vec4 MVar = gl_TexCoord[1];\n"
602     ""
603     "	offsetArray[0] = vec2(0.0, 0.0);\n"
604     "	offsetArray[1] = vec2(0.0, 1.0);\n"
605     "	offsetArray[2] = vec2(1.0, 1.0);\n"
606     "	offsetArray[3] = vec2(-1.0, -1.0);\n"
607     "	offsetArray[4] = vec2(-2.0, 0.0);\n"
608     "	offsetArray[5] = vec2(0.0, -2.0);\n"
609     "	offsetArray[6] = vec2(2.0, -2.0);\n"
610     "	offsetArray[7] = vec2(-2.0, 2.0);\n"
611     "	offsetArray[8] = vec2(3.0, 0.0);\n"
612     "	offsetArray[9] = vec2(0.0, 3.0);\n"
613     "	offsetArray[10] = vec2(3.0, 3.0);\n"
614     "	offsetArray[11] = vec2(-3.0, -3.0);\n"
615     "	offsetArray[12] = vec2(-4.0, 0.0);\n"
616     "	offsetArray[13] = vec2(0.0, -4.0);\n"
617     "	offsetArray[14] = vec2(4.0, -4.0);\n"
618     "	offsetArray[15] = vec2(-4.0, 4.0);\n"
619     ""
620     "    SMPos.xy  = SMPos.xy / SMPos.w / 2.0 + vec2(0.5, 0.5);\n"
621     ""
622     "	vec4 finalCol = vec4(0.0, 0.0, 0.0, 0.0);\n"
623     ""
624     "	// If this point is within the light's frustum.\n"
625     "##ifdef ROUND_SPOTLIGHTS\n"
626     "	float lengthToCenter = length(SMPos.xy - vec2(0.5, 0.5));\n"
627     "	if(SMPos.z - 0.01 > 0.0 && SMPos.z + 0.01 < MVar.z)\n"
628     "##else\n"
629     "	vec2 clampedSMPos = clamp(SMPos.xy, vec2(0.0, 0.0), vec2(1.0, 1.0));\n"
630     "	if(clampedSMPos.x == SMPos.x && clampedSMPos.y == SMPos.y && SMPos.z > 0.0 && SMPos.z < MVar.z)\n"
631     "##endif\n"
632     "	{"
633     "		float lightFactor = 1.0;\n"
634     "		float realDist = MVar.x / MVar.z - 0.002;\n"
635     "	"
636     "		for(int i = 0;i < SAMPLE_AMOUNT; i++)"
637     "			lightFactor -= testShadow(SMPos.xy, offsetArray[i] * MVar.w, realDist);\n"
638     ""
639     "		// Multiply with diffuse.\n"
640     "##ifdef ROUND_SPOTLIGHTS\n"
641     "		finalCol = LightColour * lightFactor * MVar.y * clamp(5.0 - 10.0 * lengthToCenter, 0.0, 1.0);\n"
642     "##else\n"
643     "		finalCol = LightColour * lightFactor * MVar.y;\n"
644     "##endif\n"
645     "	}"
646     ""
647     "	gl_FragColor = finalCol;\n"
648     "}",
649     "sampler2D ShadowMapSampler : register(s0);\n"
650     "float4 LightColour;\n"
651     "float ClipBorder;\n"
652     "\n"
653     "##ifdef VSM\n"
654     "float calcShadow(float2 texCoords, float2 offset, float RealDist)"
655     "{"
656     "	float4 shadTexCol = tex2D(ShadowMapSampler, texCoords + offset);\n"
657     ""
658     "	float lit_factor = (RealDist <= shadTexCol.x);\n"
659     ""
660     "	float E_x2 = shadTexCol.y;\n"
661     "	float Ex_2 = shadTexCol.x * shadTexCol.x;\n"
662     "	float variance = min(max(E_x2 - Ex_2, 0.00001) + 0.000001, 1.0);\n"
663     "	float m_d = (shadTexCol.x - RealDist);\n"
664     "	float p = variance / (variance + m_d * m_d);\n"
665     "	  "
666     "	return (1.0 - max(lit_factor, p)) / SAMPLE_AMOUNT;\n"
667     "}\n"
668     "##else\n"
669     "float calcShadow(float2 texCoords, float2 offset, float RealDist)"
670     "{"
671     "   float4 shadTexCol = tex2D(ShadowMapSampler,texCoords + offset);\n"
672     "   float extractedDistance = shadTexCol.r;\n"
673     "      "
674     "   return (extractedDistance <= RealDist ? (1.0  / SAMPLE_AMOUNT) : 0.0);\n"
675     "}\n"
676     "##endif\n"
677     ""
678     "float4 pixelMain"
679     "("
680     "   float4 SMPos       : TEXCOORD0,"
681     "   float4 MVar        : TEXCOORD1,"
682     "   float2 TexCoords    : TEXCOORD2"
683     ") : COLOR0"
684     "{"
685     "	const float2 offsetArray[16] = "
686     "	{"
687     "		float2(0.0, 0.0),"
688     "		float2(0.0, 1.0),"
689     "		float2(1.0, -1.0),"
690     "		float2(-1.0, 1.0),"
691     "		float2(-2.0, 0.0),"
692     "		float2(0.0, -2.0),"
693     "		float2(-2.0, -2.0),"
694     "		float2(2.0, 2.0),"
695     "		float2(3.0, 0.0),"
696     "		float2(0.0, 3.0),"
697     "		float2(3.0, -3.0),"
698     "		float2(-3.0, 3.0),"
699     "		float2(-4.0, 0.0),"
700     "		float2(0.0, -4.0),"
701     "		float2(-4.0, -4.0),"
702     "		float2(4.0, 4.0)"
703     "	};\n"
704     ""
705     "	SMPos.xy = SMPos.xy / SMPos.w + float2(0.5, 0.5);\n"
706     ""
707     "	float4 finalCol = float4(0.0, 0.0, 0.0, 0.0);\n"
708     ""
709     "	// If this point is within the light's frustum.\n"
710     "##ifdef ROUND_SPOTLIGHTS\n"
711     "	float lengthToCenter = length(SMPos.xy - float2(0.5, 0.5));\n"
712     "	if(lengthToCenter < 0.5 && SMPos.z > 0.0 && SMPos.z < MVar[3])\n"
713     "##else\n"
714     "	float2 clampedSMPos = saturate(SMPos.xy);\n"
715     "	if(clampedSMPos.x == SMPos.x && clampedSMPos.y == SMPos.y && SMPos.z > 0.0 && SMPos.z < MVar[3])\n"
716     "##endif\n"
717     "	{"
718     "		float lightFactor = 1.0;\n"
719     "		float realDistance = MVar[0] / MVar[3] - 0.005;\n"
720     "	"
721     "		for(int i = 0;i < SAMPLE_AMOUNT; ++i)"
722     "			lightFactor -= calcShadow(SMPos.xy, offsetArray[i] * MVar[2], realDistance);\n"
723     ""
724     "		// Multiply with diffuse.\n"
725     "##ifdef ROUND_SPOTLIGHTS\n"
726     "		finalCol = LightColour * lightFactor * MVar[1] * clamp(5.0 - 10.0 * lengthToCenter, 0.0, 1.0);\n"
727     "##else\n"
728     "		finalCol = LightColour * lightFactor * MVar[1];\n"
729     "##endif\n"
730     "	}"
731     "   else \n"
732     "   { \n"
733     "     if (!ClipBorder) finalCol = LightColour; \n"
734     "   } \n"
735     "	"
736     "	return finalCol;\n"
737     "}"};
738 
739 const char* const SHADOW_PASS_2V[ESE_COUNT] = {
740     "struct VS_OUTPUT "
741     "{"
742     "	vec4 Position;\n"
743     "	vec4 ShadowMapSamplingPos;\n"
744     "	vec4 MVar;\n"
745     "};\n"
746     ""
747     "uniform float MaxD, MAPRES;\n"
748     "uniform vec3 LightPos;\n"
749     "uniform mat4 mWorldViewProj;\n"
750     "uniform mat4 mWorldViewProj2;\n"
751     ""
752     "VS_OUTPUT vertexMain( in vec3 Position) "
753     "{"
754     "	VS_OUTPUT OUT;\n"
755     ""
756     "	OUT.Position = (mWorldViewProj * vec4(Position.x, Position.y, Position.z, 1.0));\n"
757     "	OUT.ShadowMapSamplingPos = (mWorldViewProj2 * vec4(Position.x, Position.y, Position.z, 1.0));\n"
758     ""
759     "	vec3 lightDir = normalize(LightPos - Position);\n"
760     "	"
761     "	OUT.MVar.x = OUT.ShadowMapSamplingPos.z;\n"
762     "	OUT.MVar.y = dot(normalize(gl_Normal.xyz), lightDir);\n"
763     "	OUT.MVar.z = MaxD;\n"
764     "	OUT.MVar.w = 1.0 / MAPRES;\n"
765     ""
766     "	return OUT;\n"
767     "}"
768     ""
769     "void main() "
770     "{"
771     "	VS_OUTPUT vOut = vertexMain(gl_Vertex.xyz);\n"
772     ""
773     "	gl_Position = vOut.Position;\n"
774     "	gl_TexCoord[0] = vOut.ShadowMapSamplingPos;\n"
775     "	gl_TexCoord[1] = vOut.MVar;\n"
776     "}",
777     "float4x4 mWorldViewProj;\n"
778     "float4x4 mWorldViewProj2;\n"
779     "float3 LightPos;\n"
780     "float ShadDark;\n"
781     "float MaxD;\n"
782     "float EnableLighting;\n"
783     "float MAPRES;\n"
784     ""
785     "struct VS_OUTPUT "
786     "{"
787     "	float4 Position				: POSITION0;\n"
788     "	float4 ShadowMapSamplingPos : TEXCOORD0; "
789     "	float4 MVar        			: TEXCOORD1;\n"
790     "	float2 TexCoords            : TEXCOORD2;\n"
791     "};\n"
792     ""
793     "VS_OUTPUT vertexMain( "
794     "   	float3 Position	: POSITION0,"
795     "	float2 TexCoords : TEXCOORD0,"
796     "	float2 TexCoords2 : TEXCOORD1,"
797     "	float3 Normal : NORMAL"
798     "  )"
799     "{"
800     "	VS_OUTPUT  OUT;\n"
801     "    OUT.Position = mul(float4(Position.x,Position.y,Position.z,1.0), mWorldViewProj);\n"
802     "	float4 SMPos = mul(float4(Position.x,Position.y,Position.z,1.0), mWorldViewProj2);\n"
803     "	SMPos.xy = float2(SMPos.x, -SMPos.y) / 2.0;\n"
804     "	"
805     "	OUT.ShadowMapSamplingPos = SMPos;\n"
806     "		"
807     "	float3 LightDir = normalize(LightPos - Position.xyz);\n"
808     "	"
809     "	OUT.MVar = float4(SMPos.z, dot(Normal, LightDir), 1.0 / MAPRES, MaxD);\n"
810     "	OUT.TexCoords = TexCoords;\n"
811     "	"
812     "	return(OUT);\n"
813     "}"};
814 
815 const char* const SIMPLE_P[ESE_COUNT] = {
816     "uniform sampler2D ColorMapSampler;\n"
817     ""
818     "void main() "
819     "{		"
820     "	vec4 finalCol = texture2D(ColorMapSampler, gl_TexCoord[0].xy);\n"
821     "	gl_FragColor = finalCol;\n"
822     "}",
823     "sampler2D ColorMapSampler : register(s0);\n"
824     ""
825     "float4 pixelMain(float2 TexCoords : TEXCOORD0) : COLOR0"
826     "{		"
827     "	float4 finalCol = tex2D(ColorMapSampler, TexCoords);\n"
828     "	return finalCol;\n"
829     "}"};
830 
831 const char* const WHITE_WASH_P[ESE_COUNT] = {
832     "uniform sampler2D ColorMapSampler;\n"
833     ""
834     "void main() "
835     "{"
836     "	float alpha = texture2D(ColorMapSampler, gl_TexCoord[1].xy).a;\n"
837     ""
838     "    gl_FragColor = vec4(1.0, 1.0, 1.0, alpha);\n"
839     "}",
840     "sampler2D ColorMapSampler : register(s0);\n"
841     ""
842     "float4 pixelMain(float4 Color: TEXCOORD0, float2 Texcoords: TEXCOORD1) : COLOR0"
843     "{"
844     "	float alpha = tex2D(ColorMapSampler, Texcoords).a;\n"
845     ""
846     "	return float4(1.0, 1.0, 1.0, alpha);\n"
847     "}"};
848 
849 const char* const WHITE_WASH_P_ADD[ESE_COUNT] = {
850     "uniform sampler2D ColorMapSampler;\n"
851     "float luminance(vec3 color)"
852     "{"
853     "	return clamp(color.r * 0.3 + color.g * 0.59 + color.b * 0.11, 0.0, 1.0);\n"
854     "}"
855     "void main() "
856     "{"
857     "	vec4 diffuseTex = texture2D(ColorMapSampler, gl_TexCoord[1].xy);\n"
858     "	//diffuseTex *= gl_TexCoord[2];\n"
859     ""
860     "    gl_FragColor = vec4(1.0, 1.0, 1.0, luminance(diffuseTex.rgb));\n"
861     "}",
862     "sampler2D ColorMapSampler : register(s0);\n"
863     ""
864     "float luminance(float3 color)"
865     "{"
866     "	return clamp(color.r * 0.3 + color.g * 0.59 + color.b * 0.11, 0.0, 1.0);\n"
867     "}"
868     ""
869     "float4 pixelMain(float4 Color : TEXCOORD0, float2 Texcoords : TEXCOORD1, float4 VColor : TEXCOORD2) : COLOR0"
870     "{"
871     "	float4 diffuseTex = tex2D(ColorMapSampler, Texcoords);\n"
872     "	diffuseTex *= VColor;\n"
873     ""
874     "	return float4(1.0, 1.0, 1.0, luminance(diffuseTex.rgb));\n"
875     "}"};
876 
877 const char* const SCREEN_QUAD_V[ESE_COUNT] = {
878     "uniform float screenX, screenY; \n"
879     "uniform vec3 LineStarts0, LineStarts1, LineStarts2, LineStarts3; \n"
880     "uniform vec3 LineEnds0, LineEnds1, LineEnds2, LineEnds3; \n"
881     "void main() \n"
882     "{\n"
883     "	gl_Position = vec4(gl_Vertex.x, gl_Vertex.y, 0.0, 1.0); \n"
884     "	vec2 tCoords; \n"
885     "	tCoords.x = 0.5 * (1.0 + gl_Vertex.x); \n"
886     "	tCoords.y = 0.5 * (1.0 + gl_Vertex.y); \n"
887     "	gl_TexCoord[0].xy = tCoords.xy; \n"
888     "	tCoords.y = 1.0 - tCoords.y; \n"
889     "	vec3 tLStart = mix(LineStarts0, LineStarts1, tCoords.x); \n"
890     "	vec3 bLStart = mix(LineStarts2, LineStarts3, tCoords.x); \n"
891     "	gl_TexCoord[1].xyz = mix(tLStart, bLStart, tCoords.y); \n"
892     "	vec3 tLEnd = mix(LineEnds0, LineEnds1, tCoords.x); \n"
893     "	vec3 bLEnd = mix(LineEnds2, LineEnds3, tCoords.x); \n"
894     "	gl_TexCoord[2].xyz = mix(tLEnd, bLEnd, tCoords.y); \n"
895     "	gl_TexCoord[3].xy = vec2(screenX, screenY); \n"
896     "}",
897     "float screenX, screenY; \n"
898     "float3 LineStarts0, LineStarts1, LineStarts2, LineStarts3; \n"
899     "float3 LineEnds0, LineEnds1, LineEnds2, LineEnds3; \n"
900     "struct VS_OUTPUT \n"
901     "{"
902     "	float4 Position		: POSITION0;"
903     "	float2 TexCoords	: TEXCOORD0;"
904     "	float3 LStart		: TEXCOORD1;"
905     "	float3 LEnd			: TEXCOORD2;"
906     "	float2 ScreenSize	: TEXCOORD3;"
907     "}; \n"
908     "VS_OUTPUT vertexMain(float3 Position : POSITION0) \n"
909     "{ \n"
910     "	VS_OUTPUT OUT; \n"
911     "   OUT.Position = float4(Position.x,Position.y, 0.0, 1.0); \n"
912     "	OUT.TexCoords.x = 0.5 * (1.0 + Position.x + (1.0 / screenX)); \n"
913     "	OUT.TexCoords.y = 1.0 - 0.5 * (1.0 + Position.y - (1.0 / screenY)); \n"
914     "	float3 tLStart = lerp(LineStarts0, LineStarts1, OUT.TexCoords.x); \n"
915     "	float3 bLStart = lerp(LineStarts2, LineStarts3, OUT.TexCoords.x); \n"
916     "	OUT.LStart = lerp(tLStart, bLStart, OUT.TexCoords.y); \n"
917     "	float3 tLEnd = lerp(LineEnds0, LineEnds1, OUT.TexCoords.x); \n"
918     "	float3 bLEnd = lerp(LineEnds2, LineEnds3, OUT.TexCoords.x); \n"
919     "	OUT.LEnd = lerp(tLEnd, bLEnd, OUT.TexCoords.y); \n"
920     "	OUT.ScreenSize = float2(screenX, screenY); \n"
921     "	return(OUT); \n"
922     "} \n"};
923 
924 const char* const VSM_BLUR_P[ESE_COUNT] = {
925     "uniform sampler2D ColorMapSampler;\n"
926     "\n"
927     "vec2 offsetArray[5];\n"
928     "\n"
929     "void main() \n"
930     "{\n"
931     "\n"
932     "##ifdef VERTICAL_VSM_BLUR\n"
933     "	offsetArray[0] = vec2(0.0, 0.0);\n"
934     "	offsetArray[1] = vec2(0.0, -1.5 / gl_TexCoord[3].y);\n"
935     "	offsetArray[2] = vec2(0.0, 1.5 / gl_TexCoord[3].y);\n"
936     "	offsetArray[3] = vec2(0.0, -2.5 / gl_TexCoord[3].y);\n"
937     "	offsetArray[4] = vec2(0.0, 2.5 / gl_TexCoord[3].y);\n"
938     "##else\n"
939     "	offsetArray[0] = vec2(0.0, 0.0);\n"
940     "	offsetArray[1] = vec2(-1.5 / gl_TexCoord[3].x, 0.0);\n"
941     "	offsetArray[2] = vec2(1.5 / gl_TexCoord[3].x, 0.0);\n"
942     "	offsetArray[3] = vec2(-2.5 / gl_TexCoord[3].x, 0.0);\n"
943     "	offsetArray[4] = vec2(2.5 / gl_TexCoord[3].x, 0.0);\n"
944     "##endif\n"
945     "\n"
946     "	vec4 BlurCol = vec4(0.0, 0.0, 0.0, 0.0);\n"
947     "\n"
948     "	for(int i = 0;i < 5;++i)\n"
949     "		BlurCol += texture2D(ColorMapSampler, clamp(gl_TexCoord[0].xy + offsetArray[i], vec2(0.001, 0.001), "
950     "vec2(0.999, 0.999)));\n"
951     "\n"
952     "	gl_FragColor = BlurCol / 5.0;\n"
953     "}\n",
954     "sampler2D ColorMapSampler : register(s0);\n"
955     "\n"
956     "float4 pixelMain ( float4 Texcoords : TEXCOORD0, float2 ScreenSize : TEXCOORD3 ) : COLOR0\n"
957     "{\n"
958     "	float2 offsetArray[5];\n"
959     "##ifdef VERTICAL_VSM_BLUR\n"
960     "	offsetArray[0] = float2(0, 0);\n"
961     "	offsetArray[1] = float2(0, 1.5 / ScreenSize.y);\n"
962     "	offsetArray[2] = float2(0, -1.5 / ScreenSize.y);\n"
963     "	offsetArray[3] = float2(0, 2.5 / ScreenSize.y);\n"
964     "	offsetArray[4] = float2(0, -2.5 / ScreenSize.y);\n"
965     "##else\n"
966     "	offsetArray[0] = float2(0, 0);\n"
967     "	offsetArray[1] = float2(1.5 / ScreenSize.x, 0);\n"
968     "	offsetArray[2] = float2(-1.5 / ScreenSize.x, 0);\n"
969     "	offsetArray[3] = float2(2.5 / ScreenSize.x, 0);\n"
970     "	offsetArray[4] = float2(-2.5 / ScreenSize.x, 0);\n"
971     "##endif\n"
972     "\n"
973     "	float4 finalVal = float4(0.0, 0.0, 0.0, 0.0);\n"
974     "\n"
975     "	for(int i = 0;i < 5;++i)\n"
976     "		finalVal += tex2D(ColorMapSampler, clamp(Texcoords.xy + offsetArray[i], float2(0.001, 0.001), "
977     "float2(0.999, 0.999)));\n"
978     "\n"
979     "	return finalVal / 5.0;\n"
980     "}\n"};
981 
982 ///////////////////////////// EffectHandler.h
983 
984 /// Shadow mode enums, sets whether a node recieves shadows, casts shadows, or both.
985 /// If the mode is ESM_CAST, it will not be affected by shadows or lighting.
986 enum E_SHADOW_MODE { ESM_RECEIVE, ESM_CAST, ESM_BOTH, ESM_EXCLUDE, ESM_COUNT };
987 
988 /// Various filter types, up to 16 samples PCF.
989 enum E_FILTER_TYPE { EFT_NONE, EFT_4PCF, EFT_8PCF, EFT_12PCF, EFT_16PCF, EFT_COUNT };
990 
991 struct SShadowLight {
992     /// Shadow light constructor. The first parameter is the square shadow map resolution.
993     /// This should be a power of 2 number, and within reasonable size to achieve optimal
994     /// performance and quality. Recommended sizes are 512 to 4096 subject to your target
995     /// hardware and quality requirements. The next two parameters are position and target,
996     /// the next one is the light color. The next two are very important parameters,
997     /// the far value and the near value. The higher the near value, and the lower the
998     /// far value, the better the depth precision of the shadows will be, however it will
999     /// cover a smaller volume. The next is the FOV, if the light was to be considered
1000     /// a camera, this would be similar to setting the camera's field of view. The last
1001     /// parameter is whether the light is directional or not, if it is, an orthogonal
1002     /// projection matrix will be created instead of a perspective one.
1003     SShadowLight(const irr::u32 shadowMapResolution,
1004                  const irr::core::vector3df& position,
1005                  const irr::core::vector3df& target,
1006                  irr::video::SColorf lightColour = irr::video::SColor(0xffffffff),
1007                  irr::f32 nearValue = 10.0,
1008                  irr::f32 farValue = 100.0,
1009                  irr::f32 fov = 90.0 * irr::core::DEGTORAD64,
1010                  bool directional = false)
diffuseColourSShadowLight1011         : diffuseColour(lightColour),
1012           pos(position),
1013           tar(target),
1014           farPlane(directional ? 1.0f : farValue),
1015           mapRes(shadowMapResolution) {
1016         nearValue = nearValue <= 0.0f ? 0.1f : nearValue;
1017 
1018         updateViewMatrix();
1019 
1020         if (directional)
1021             projMat.buildProjectionMatrixOrthoLH(fov, fov, nearValue, farValue);
1022         else
1023             projMat.buildProjectionMatrixPerspectiveFovLH(fov, 1.0f, nearValue, farValue);
1024 
1025         clipborder = true;  //***ALEX***
1026     }
1027 
1028     /// Sets the light's position.
setPositionSShadowLight1029     void setPosition(const irr::core::vector3df& position) {
1030         pos = position;
1031         updateViewMatrix();
1032     }
1033 
1034     /// Sets the light's target.
setTargetSShadowLight1035     void setTarget(const irr::core::vector3df& target) {
1036         tar = target;
1037         updateViewMatrix();
1038     }
1039 
1040     /// Gets the light's position.
getPositionSShadowLight1041     const irr::core::vector3df& getPosition() const { return pos; }
1042 
1043     /// Gets the light's target.
getTargetSShadowLight1044     const irr::core::vector3df& getTarget() const { return tar; }
1045 
1046     /// Sets the light's view matrix.
setViewMatrixSShadowLight1047     void setViewMatrix(const irr::core::matrix4& matrix) {
1048         viewMat = matrix;
1049         irr::core::matrix4 vInverse;
1050         viewMat.getInverse(vInverse);
1051         pos = vInverse.getTranslation();
1052     }
1053 
1054     /// Sets the light's projection matrix.
setProjectionMatrixSShadowLight1055     void setProjectionMatrix(const irr::core::matrix4& matrix) { projMat = matrix; }
1056 
1057     /// Gets the light's view matrix.
getViewMatrixSShadowLight1058     irr::core::matrix4& getViewMatrix() { return viewMat; }
1059 
1060     /// Gets the light's projection matrix.
getProjectionMatrixSShadowLight1061     irr::core::matrix4& getProjectionMatrix() { return projMat; }
1062 
1063     /// Gets the light's far value.
getFarValueSShadowLight1064     irr::f32 getFarValue() const { return farPlane; }
1065 
1066     /// Gets the light's color.
getLightColorSShadowLight1067     const irr::video::SColorf& getLightColor() const { return diffuseColour; }
1068 
1069     /// Sets the light's color.
setLightColorSShadowLight1070     void setLightColor(const irr::video::SColorf& lightColour) { diffuseColour = lightColour; }
1071 
1072     /// Sets the shadow map resolution for this light.
setShadowMapResolutionSShadowLight1073     void setShadowMapResolution(const irr::u32 shadowMapResolution) { mapRes = shadowMapResolution; }
1074 
1075     /// Gets the shadow map resolution for this light.
getShadowMapResolutionSShadowLight1076     irr::u32 getShadowMapResolution() const { return mapRes; }
1077 
1078     ///***ALEX***
setClipBorderSShadowLight1079     void setClipBorder(bool mb) { clipborder = mb; }
1080     ///***ALEX***
getClipBorderSShadowLight1081     bool getClipBorder() const { return clipborder; }
1082 
1083   private:
updateViewMatrixSShadowLight1084     void updateViewMatrix() {
1085         viewMat.buildCameraLookAtMatrixLH(pos, tar,
1086                                           (pos - tar).dotProduct(irr::core::vector3df(1.0f, 0.0f, 1.0f)) == 0.0f
1087                                               ? irr::core::vector3df(0.0f, 0.0f, 1.0f)
1088                                               : irr::core::vector3df(0.0f, 1.0f, 0.0f));
1089     }
1090 
1091     irr::video::SColorf diffuseColour;
1092     irr::core::vector3df pos, tar;
1093     irr::f32 farPlane;
1094     irr::core::matrix4 viewMat, projMat;
1095     irr::u32 mapRes;
1096     bool clipborder;  //***ALEX***
1097 };
1098 
1099 // This is a general interface that can be overidden if you want to perform operations before or after
1100 // a specific post-processing effect. You will be passed an instance of the EffectHandler.
1101 // The function names themselves should be self-explanatory ;)
1102 class EffectHandler;
1103 class IPostProcessingRenderCallback {
1104   public:
1105     virtual void OnPreRender(EffectHandler* effect) = 0;
1106     virtual void OnPostRender(EffectHandler* effect) = 0;
1107 
~IPostProcessingRenderCallback()1108     virtual ~IPostProcessingRenderCallback() {}
1109 };
1110 
1111 // Shader callback prototypes.
1112 class DepthShaderCB;
1113 class ShadowShaderCB;
1114 class ScreenQuadCB;
1115 
1116 /// Main effect handling class, use this to apply shadows and effects.
1117 class EffectHandler {
1118   public:
1119     /*	EffectHandler constructor. Initializes the EffectHandler.
1120 
1121         Parameters:
1122         irrlichtDevice: Current Irrlicht device.
1123         screenRTTSize: Size of screen render target for post processing. Default is screen size.
1124         useVSMShadows: Shadows will use VSM filtering. It is recommended to only use EFT_NONE when this is enabled.
1125         useRoundSpotlights: Shadow lights will have a soft round spot light mask. Default is false.
1126         use32BitDepthBuffers: XEffects will use 32-bit depth buffers if this is true, otherwise 16-bit. Default is
1127        false.
1128     */
1129     EffectHandler(irr::IrrlichtDevice* irrlichtDevice,
1130                   const irr::core::dimension2du& screenRTTSize = irr::core::dimension2du(0, 0),
1131                   const bool useVSMShadows = false,
1132                   const bool useRoundSpotLights = false,
1133                   const bool use32BitDepthBuffers = false);
1134 
1135     /// Destructor.
1136     ~EffectHandler();
1137 
1138     /// Adds a shadow light. Check out the shadow light constructor for more information.
addShadowLight(const SShadowLight & shadowLight)1139     void addShadowLight(const SShadowLight& shadowLight) { LightList.push_back(shadowLight); }
1140 
1141     /// Retrieves a reference to a shadow light. You may get the max amount from getShadowLightCount.
getShadowLight(irr::u32 index)1142     SShadowLight& getShadowLight(irr::u32 index) { return LightList[index]; }
1143 
1144     /// Retrieves the current number of shadow lights.
getShadowLightCount()1145     irr::u32 getShadowLightCount() const { return LightList.size(); }
1146 
1147     /// Retrieves the shadow map texture for the specified square shadow map resolution.
1148     /// Only one shadow map is kept for each resolution, so if multiple lights are using
1149     /// the same resolution, you will only see the last light drawn's output.
1150     /// The secondary param specifies whether to retrieve the secondary shadow map used in blurring.
1151     irr::video::ITexture* getShadowMapTexture(const irr::u32 resolution, const bool secondary = false);
1152 
1153     /// Retrieves the screen depth map texture if the depth pass is enabled. This is unrelated to the shadow map, and is
1154     /// meant to be used for post processing effects that require screen depth info, eg. DOF or SSAO.
getDepthMapTexture()1155     irr::video::ITexture* getDepthMapTexture() { return DepthRTT; }
1156 
1157     /// This function is now unrelated to shadow mapping. It simply adds a node to the screen space depth map render,
1158     /// for use
1159     /// with post processing effects that require screen depth info. If you want the functionality of the old method (A
1160     /// node that
1161     /// only casts but does not receive shadows, use addShadowToNode with the ESM_CAST shadow mode.
1162     void addNodeToDepthPass(irr::scene::ISceneNode* node);
1163 
1164     /// This function is now unrelated to shadow mapping. It simply removes a node to the screen space depth map render,
1165     /// for use
1166     /// with post processing effects that require screen depth info.
1167     void removeNodeFromDepthPass(irr::scene::ISceneNode* node);
1168 
1169     /// Enables/disables an additional pass before applying post processing effects (If there are any) which records
1170     /// screen depth info
1171     /// to the depth buffer for use with post processing effects that require screen depth info, such as SSAO or DOF.
1172     /// For nodes to be
1173     /// rendered in this pass, they must first be added using addNodeToDepthPass(SceneNode).
1174     void enableDepthPass(bool enableDepthPass);
1175 
1176     /// Removes shadows from a scene node.
removeShadowFromNode(irr::scene::ISceneNode * node)1177     void removeShadowFromNode(irr::scene::ISceneNode* node) {
1178         SShadowNode tmpShadowNode = {node, ESM_RECEIVE, EFT_NONE};
1179         irr::s32 i = ShadowNodeArray.binary_search(tmpShadowNode);
1180 
1181         if (i != -1)
1182             ShadowNodeArray.erase(i);
1183     }
1184 
1185     // Excludes a scene node from lighting calculations, avoiding any side effects that may
1186     // occur from XEffect's light modulation on this particular scene node.
excludeNodeFromLightingCalculations(irr::scene::ISceneNode * node)1187     void excludeNodeFromLightingCalculations(irr::scene::ISceneNode* node) {
1188         SShadowNode tmpShadowNode = {node, ESM_EXCLUDE, EFT_NONE};
1189         ShadowNodeArray.push_back(tmpShadowNode);
1190     }
1191 
1192     /// Updates the effects handler. This must be done between IVideoDriver::beginScene and IVideoDriver::endScene.
1193     /// This function now replaces smgr->drawAll(). So place it where smgr->drawAll() would normally go. Please note
1194     /// that the clear color from IVideoDriver::beginScene is not preserved, so you must instead specify the clear
1195     /// color using EffectHandler::setClearColour(Color).
1196     /// A render target may be passed as the output target, else rendering will commence on the backbuffer.
1197     void update(irr::video::ITexture* outputTarget = 0);
1198 
1199     /// Adds a shadow to the scene node. The filter type specifies how many shadow map samples
1200     /// to take, a higher value can produce a smoother or softer result. The shadow mode can
1201     /// be either ESM_BOTH, ESM_CAST, or ESM_RECEIVE. ESM_BOTH casts and receives shadows,
1202     /// ESM_CAST only casts shadows, and is unaffected by shadows or lighting, and ESM_RECEIVE
1203     /// only receives but does not cast shadows.
1204     void addShadowToNode(irr::scene::ISceneNode* node,
1205                          E_FILTER_TYPE filterType = EFT_NONE,
1206                          E_SHADOW_MODE shadowMode = ESM_BOTH);
1207 
1208     /// Returns the device time divided by 100, for use with the shader callbacks.
getTime()1209     irr::f32 getTime() { return device->getTimer()->getTime() / 100.0f; }
1210 
1211     /// Sets the scene clear color, for when the scene is cleared before smgr->drawAll().
setClearColour(irr::video::SColor ClearCol)1212     void setClearColour(irr::video::SColor ClearCol) { ClearColour = ClearCol; }
1213 
1214     /**
1215     A very easy to use post processing function. Simply add a material type to apply to the screen as a post processing
1216     effect and it will be applied. You can add as many material types as you desire, and they will be double buffered
1217     and
1218     executed in sequence.
1219 
1220     For the material types, I recommend using "ScreenQuadCB" as the callback and referring to the texture names that are
1221     passed
1222     (When using OpenGL, in DirectX uniforms are not required to bind textures).
1223     Please note that this will only work in OpenGL on vanilla Irrlicht, DX requires the large RTT patch to be able to
1224     create
1225     sufficiently sized render targets for post processing. (Or you can just remove the engine check for Pow2).
1226 
1227     The structure of the textures is as follows:
1228 
1229     Texture1 - "ColorMapSampler"
1230     This is passed on from the previous post processing effect as they are executed in sequence. For example, if you do
1231     a
1232     horizontal blur on the first post processing material, then a vertical blur in the second material, you will use
1233     this
1234     sampler to access the post processed data of the horizontal blur when it is time to do the vertical blur. If
1235     accessed
1236     from the first post processing material, it will just contain the untainted screen map data.
1237 
1238     Texture2 - "ScreenMapSampler"
1239     The second texture will always contain the untainted screen map data, from when the scene is first rendered. It will
1240     remain unchanged no matter how many post processing materials are applied. This kind of data is necessary, for
1241     example
1242     in bloom or DOF, you would require a copy of the blurred scene data and a copy of the normal untainted, unblurred
1243     screen
1244     data, and mix between them based on certain factors such as depth or luminance.
1245 
1246     Texture3 - "DepthMapSampler"
1247     If a depth pass has been enabled using enableDepthPass, then this sampler will contain the screen space depth
1248     information.
1249     For better quality this is encoded to 16bits, and can be decoded like so:
1250         Texture.red + (Texture.green / 256.0f);
1251     That is by adding the red channel to the green channel which is first divided by 256.
1252     The data can still be used without decoding, in 8 bit precision, by just accessing the red component of the texture.
1253     Though
1254     this is not recommended as 8 bit precision is usually not sufficient for modern post processing effects.
1255 
1256     Texture4 - "UserMapSampler"
1257     A custom texture that can be set by the user using setPostProcessingUserTexture(irr::video::ITexture* userTexture).
1258 
1259     The last parameter is the render callback, you may pass 0 if you do not need one.
1260     Please see IPostProcessingRenderCallback for more info about this callback.
1261     */
1262     void addPostProcessingEffect(irr::s32 MaterialType, IPostProcessingRenderCallback* callback = 0);
1263 
1264     /// Sets the IPostProcessingRenderCallback for the specified post processing effect.
1265     /// The old callback if previously set will be automatically deleted.
1266     void setPostProcessingRenderCallback(irr::s32 MaterialType, IPostProcessingRenderCallback* callback = 0) {
1267         SPostProcessingPair tempPair(MaterialType, 0);
1268         irr::s32 i = PostProcessingRoutines.binary_search(tempPair);
1269 
1270         if (i != -1) {
1271             if (PostProcessingRoutines[i].renderCallback)
1272                 delete PostProcessingRoutines[i].renderCallback;
1273 
1274             PostProcessingRoutines[i].renderCallback = callback;
1275         }
1276     }
1277 
1278     /// Removes the first encountered post processing effect with the specified material type.
removePostProcessingEffect(irr::s32 MaterialType)1279     void removePostProcessingEffect(irr::s32 MaterialType) {
1280         SPostProcessingPair tempPair(MaterialType, 0);
1281         irr::s32 i = PostProcessingRoutines.binary_search(tempPair);
1282 
1283         if (i != -1) {
1284             if (PostProcessingRoutines[i].renderCallback)
1285                 delete PostProcessingRoutines[i].renderCallback;
1286 
1287             PostProcessingRoutines.erase(i);
1288         }
1289     }
1290 
1291     /// Adds a post processing effect by reading a pixel shader from a file. The vertex shader is taken care of.
1292     /// The vertex shader will pass the correct screen quad texture coordinates via the TEXCOORD0 semantic in
1293     /// Direct3D or the gl_TexCoord[0] varying in OpenGL.
1294     /// See addPostProcessingEffect for more info.
1295     /// Returns the Irrlicht material type of the post processing effect.
1296     irr::s32 addPostProcessingEffectFromFile(const irr::core::stringc& filename,
1297                                              IPostProcessingRenderCallback* callback = 0);
1298 
1299     /// Sets a shader parameter for a post-processing effect. The first parameter is the material type, the second
1300     /// is the uniform paratmeter name, the third is a float pointer that points to the data and the last is the
1301     /// component count of the data. Please note that the float pointer must remain valid during render time.
1302     /// To disable the setting of a parameter you may simply pass a null float pointer.
1303     void setPostProcessingEffectConstant(const irr::s32 materialType,
1304                                          const irr::core::stringc& name,
1305                                          const irr::f32* data,
1306                                          const irr::u32 count);
1307 
1308     /// Returns the screen quad scene node. This is not required in any way, but some advanced users may want to adjust
1309     /// its material settings accordingly.
getScreenQuad()1310     const CScreenQuad& getScreenQuad() { return ScreenQuad; }
1311 
1312     /// Sets the active scene manager.
setActiveSceneManager(irr::scene::ISceneManager * smgrIn)1313     void setActiveSceneManager(irr::scene::ISceneManager* smgrIn) { smgr = smgrIn; }
1314 
1315     /// Gets the active scene manager.
getActiveSceneManager()1316     irr::scene::ISceneManager* getActiveSceneManager() { return smgr; }
1317 
1318     /// This allows the user to specify a custom, fourth texture to be used in the post-processing effects.
1319     /// See addPostProcessingEffect for more info.
setPostProcessingUserTexture(irr::video::ITexture * userTexture)1320     void setPostProcessingUserTexture(irr::video::ITexture* userTexture) {
1321         ScreenQuad.getMaterial().setTexture(3, userTexture);
1322     }
1323 
1324     /// Sets the global ambient color for shadowed scene nodes.
setAmbientColor(irr::video::SColor ambientColour)1325     void setAmbientColor(irr::video::SColor ambientColour) { AmbientColour = ambientColour; }
1326 
1327     /// Gets the global ambient color.
getAmbientColor()1328     irr::video::SColor getAmbientColor() const { return AmbientColour; }
1329 
1330     /// Generates a randomized texture composed of uniformly distributed 3 dimensional vectors.
1331     irr::video::ITexture* generateRandomVectorTexture(const irr::core::dimension2du& dimensions,
1332                                                       const irr::core::stringc& name = "randVec");
1333 
1334     /// Sets a new screen render target resolution.
1335     void setScreenRenderTargetResolution(const irr::core::dimension2du& resolution);
1336 
1337     /// Returns the device that this EffectHandler was initialized with.
getIrrlichtDevice()1338     irr::IrrlichtDevice* getIrrlichtDevice() { return device; }
1339 
1340   private:
1341     struct SShadowNode {
1342         bool operator<(const SShadowNode& other) const { return node < other.node; }
1343 
1344         irr::scene::ISceneNode* node;
1345 
1346         E_SHADOW_MODE shadowMode;
1347         E_FILTER_TYPE filterType;
1348     };
1349 
1350     struct SPostProcessingPair {
1351         SPostProcessingPair(const irr::s32 materialTypeIn,
1352                             ScreenQuadCB* callbackIn,
1353                             IPostProcessingRenderCallback* renderCallbackIn = 0)
callbackSPostProcessingPair1354             : callback(callbackIn), renderCallback(renderCallbackIn), materialType(materialTypeIn) {}
1355 
1356         bool operator<(const SPostProcessingPair& other) const { return materialType < other.materialType; }
1357 
1358         ScreenQuadCB* callback;
1359         IPostProcessingRenderCallback* renderCallback;
1360         irr::s32 materialType;
1361     };
1362 
1363     SPostProcessingPair obtainScreenQuadMaterialFromFile(
1364         const irr::core::stringc& filename,
1365         irr::video::E_MATERIAL_TYPE baseMaterial = irr::video::EMT_SOLID);
1366 
1367     irr::IrrlichtDevice* device;
1368     irr::video::IVideoDriver* driver;
1369     irr::scene::ISceneManager* smgr;
1370     irr::core::dimension2du mapRes;
1371 
1372     irr::s32 Depth;
1373     irr::s32 DepthT;
1374     irr::s32 Shadow[EFT_COUNT];
1375     irr::s32 LightModulate;
1376     irr::s32 Simple;
1377     irr::s32 WhiteWash;
1378     irr::s32 WhiteWashTRef;
1379     irr::s32 WhiteWashTAdd;
1380     irr::s32 WhiteWashTAlpha;
1381     irr::s32 VSMBlurH;
1382     irr::s32 VSMBlurV;
1383 
1384     DepthShaderCB* depthMC;
1385     ShadowShaderCB* shadowMC;
1386 
1387     irr::video::ITexture* ScreenRTT;
1388     irr::video::ITexture* DepthRTT;
1389 
1390     irr::core::array<SPostProcessingPair> PostProcessingRoutines;
1391     irr::core::array<SShadowLight> LightList;
1392     irr::core::array<SShadowNode> ShadowNodeArray;
1393     irr::core::array<irr::scene::ISceneNode*> DepthPassArray;
1394 
1395     irr::core::dimension2du ScreenRTTSize;
1396     irr::video::SColor ClearColour;
1397     irr::video::SColor AmbientColour;
1398     CScreenQuad ScreenQuad;
1399 
1400     bool shadowsUnsupported;
1401     bool use32BitDepth;
1402     bool useVSM;
1403     bool DepthPass;
1404 };
1405 
1406 ////////////////////////////////// EffectHandler.cpp
1407 
EffectHandler(irr::IrrlichtDevice * dev,const irr::core::dimension2du & screenRTTSize,const bool useVSMShadows,const bool useRoundSpotLights,const bool use32BitDepthBuffers)1408 inline EffectHandler::EffectHandler(irr::IrrlichtDevice* dev,
1409                                     const irr::core::dimension2du& screenRTTSize,
1410                                     const bool useVSMShadows,
1411                                     const bool useRoundSpotLights,
1412                                     const bool use32BitDepthBuffers)
1413     : device(dev),
1414       driver(dev->getVideoDriver()),
1415       smgr(dev->getSceneManager()),
1416       depthMC(nullptr),
1417       shadowMC(nullptr),
1418       DepthRTT(nullptr),
1419       ScreenRTTSize(screenRTTSize.getArea() == 0 ? dev->getVideoDriver()->getScreenSize() : screenRTTSize),
1420       ClearColour(0x0),
1421       AmbientColour(0x0),
1422       shadowsUnsupported(false),
1423       use32BitDepth(use32BitDepthBuffers),
1424       useVSM(useVSMShadows),
1425       DepthPass(false) {
1426     bool tempTexFlagMipMaps = driver->getTextureCreationFlag(irr::video::ETCF_CREATE_MIP_MAPS);
1427     bool tempTexFlag32 = driver->getTextureCreationFlag(irr::video::ETCF_ALWAYS_32_BIT);
1428 
1429     ScreenRTT = driver->addRenderTargetTexture(ScreenRTTSize);
1430     ScreenQuad.rt[0] = driver->addRenderTargetTexture(ScreenRTTSize);
1431     ScreenQuad.rt[1] = driver->addRenderTargetTexture(ScreenRTTSize);
1432 
1433     driver->setTextureCreationFlag(irr::video::ETCF_CREATE_MIP_MAPS, tempTexFlagMipMaps);
1434     driver->setTextureCreationFlag(irr::video::ETCF_ALWAYS_32_BIT, tempTexFlag32);
1435 
1436     CShaderPreprocessor sPP(driver);
1437 
1438     E_SHADER_EXTENSION shaderExt = (driver->getDriverType() == irr::video::EDT_DIRECT3D9) ? ESE_HLSL : ESE_GLSL;
1439 
1440     irr::video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices();
1441 
1442     if (gpu &&
1443         ((driver->getDriverType() == irr::video::EDT_OPENGL && driver->queryFeature(irr::video::EVDF_ARB_GLSL)) ||
1444          (driver->getDriverType() == irr::video::EDT_DIRECT3D9 &&
1445           driver->queryFeature(irr::video::EVDF_PIXEL_SHADER_2_0)))) {
1446         depthMC = new DepthShaderCB(this);
1447         shadowMC = new ShadowShaderCB(this);
1448 
1449         Depth =
1450             gpu->addHighLevelShaderMaterial(sPP.ppShader(SHADOW_PASS_1V[shaderExt]).c_str(), "vertexMain",
1451                                             irr::video::EVST_VS_2_0, sPP.ppShader(SHADOW_PASS_1P[shaderExt]).c_str(),
1452                                             "pixelMain", irr::video::EPST_PS_2_0, depthMC, irr::video::EMT_SOLID);
1453 
1454         DepthT = gpu->addHighLevelShaderMaterial(
1455             sPP.ppShader(SHADOW_PASS_1V[shaderExt]).c_str(), "vertexMain", irr::video::EVST_VS_2_0,
1456             sPP.ppShader(SHADOW_PASS_1PT[shaderExt]).c_str(), "pixelMain", irr::video::EPST_PS_2_0, depthMC,
1457             irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
1458 
1459         WhiteWash =
1460             gpu->addHighLevelShaderMaterial(sPP.ppShader(SHADOW_PASS_1V[shaderExt]).c_str(), "vertexMain",
1461                                             irr::video::EVST_VS_2_0, sPP.ppShader(WHITE_WASH_P[shaderExt]).c_str(),
1462                                             "pixelMain", irr::video::EPST_PS_2_0, depthMC, irr::video::EMT_SOLID);
1463 
1464         WhiteWashTRef = gpu->addHighLevelShaderMaterial(
1465             sPP.ppShader(SHADOW_PASS_1V[shaderExt]).c_str(), "vertexMain", irr::video::EVST_VS_2_0,
1466             sPP.ppShader(WHITE_WASH_P[shaderExt]).c_str(), "pixelMain", irr::video::EPST_PS_2_0, depthMC,
1467             irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
1468 
1469         WhiteWashTAdd = gpu->addHighLevelShaderMaterial(
1470             sPP.ppShader(SHADOW_PASS_1V[shaderExt]).c_str(), "vertexMain", irr::video::EVST_VS_2_0,
1471             sPP.ppShader(WHITE_WASH_P_ADD[shaderExt]).c_str(), "pixelMain", irr::video::EPST_PS_2_0, depthMC,
1472             irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL);
1473 
1474         WhiteWashTAlpha = gpu->addHighLevelShaderMaterial(
1475             sPP.ppShader(SHADOW_PASS_1V[shaderExt]).c_str(), "vertexMain", irr::video::EVST_VS_2_0,
1476             sPP.ppShader(WHITE_WASH_P[shaderExt]).c_str(), "pixelMain", irr::video::EPST_PS_2_0, depthMC,
1477             irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL);
1478 
1479         if (useRoundSpotLights)
1480             sPP.addShaderDefine("ROUND_SPOTLIGHTS");
1481 
1482         if (useVSMShadows)
1483             sPP.addShaderDefine("VSM");
1484 
1485         const irr::u32 sampleCounts[EFT_COUNT] = {1, 4, 8, 12, 16};
1486 
1487         const irr::video::E_VERTEX_SHADER_TYPE vertexProfile = driver->queryFeature(irr::video::EVDF_VERTEX_SHADER_3_0)
1488                                                                    ? irr::video::EVST_VS_3_0
1489                                                                    : irr::video::EVST_VS_2_0;
1490 
1491         const irr::video::E_PIXEL_SHADER_TYPE pixelProfile =
1492             driver->queryFeature(irr::video::EVDF_PIXEL_SHADER_3_0) ? irr::video::EPST_PS_3_0 : irr::video::EPST_PS_2_0;
1493 
1494         for (irr::u32 i = 0; i < EFT_COUNT; i++) {
1495             sPP.addShaderDefine("SAMPLE_AMOUNT", irr::core::stringc(sampleCounts[i]));
1496             Shadow[i] = gpu->addHighLevelShaderMaterial(sPP.ppShader(SHADOW_PASS_2V[shaderExt]).c_str(), "vertexMain",
1497                                                         vertexProfile, sPP.ppShader(SHADOW_PASS_2P[shaderExt]).c_str(),
1498                                                         "pixelMain", pixelProfile, shadowMC, irr::video::EMT_SOLID);
1499         }
1500 
1501         // Set resolution preprocessor defines.
1502         sPP.addShaderDefine("SCREENX", irr::core::stringc(ScreenRTTSize.Width));
1503         sPP.addShaderDefine("SCREENY", irr::core::stringc(ScreenRTTSize.Height));
1504 
1505         // Create screen quad shader callback.
1506         ScreenQuadCB* SQCB = new ScreenQuadCB(this, true);
1507 
1508         // Light modulate.
1509         LightModulate = gpu->addHighLevelShaderMaterial(
1510             sPP.ppShader(SCREEN_QUAD_V[shaderExt]).c_str(), "vertexMain", vertexProfile,
1511             sPP.ppShader(LIGHT_MODULATE_P[shaderExt]).c_str(), "pixelMain", pixelProfile, SQCB);
1512 
1513         // Simple present.
1514         Simple = gpu->addHighLevelShaderMaterial(sPP.ppShader(SCREEN_QUAD_V[shaderExt]).c_str(), "vertexMain",
1515                                                  vertexProfile, sPP.ppShader(SIMPLE_P[shaderExt]).c_str(), "pixelMain",
1516                                                  pixelProfile, SQCB, irr::video::EMT_TRANSPARENT_ADD_COLOR);
1517 
1518         // VSM blur.
1519         VSMBlurH = gpu->addHighLevelShaderMaterial(sPP.ppShader(SCREEN_QUAD_V[shaderExt]).c_str(), "vertexMain",
1520                                                    vertexProfile, sPP.ppShader(VSM_BLUR_P[shaderExt]).c_str(),
1521                                                    "pixelMain", pixelProfile, SQCB);
1522 
1523         sPP.addShaderDefine("VERTICAL_VSM_BLUR");
1524 
1525         VSMBlurV = gpu->addHighLevelShaderMaterial(sPP.ppShader(SCREEN_QUAD_V[shaderExt]).c_str(), "vertexMain",
1526                                                    vertexProfile, sPP.ppShader(VSM_BLUR_P[shaderExt]).c_str(),
1527                                                    "pixelMain", pixelProfile, SQCB);
1528 
1529         // Drop the screen quad callback.
1530         SQCB->drop();
1531     } else {
1532         Depth = irr::video::EMT_SOLID;
1533         DepthT = irr::video::EMT_SOLID;
1534         WhiteWash = irr::video::EMT_SOLID;
1535         WhiteWashTRef = irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
1536         WhiteWashTAdd = irr::video::EMT_TRANSPARENT_ADD_COLOR;
1537         WhiteWashTAlpha = irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL;
1538         Simple = irr::video::EMT_SOLID;
1539 
1540         for (irr::u32 i = 0; i < EFT_COUNT; ++i)
1541             Shadow[i] = irr::video::EMT_SOLID;
1542 
1543         device->getLogger()->log("XEffects: Shader effects not supported on this system.");
1544         shadowsUnsupported = true;
1545     }
1546 }
1547 
~EffectHandler()1548 inline EffectHandler::~EffectHandler() {
1549     if (ScreenRTT)
1550         driver->removeTexture(ScreenRTT);
1551 
1552     if (ScreenQuad.rt[0])
1553         driver->removeTexture(ScreenQuad.rt[0]);
1554 
1555     if (ScreenQuad.rt[1])
1556         driver->removeTexture(ScreenQuad.rt[1]);
1557 
1558     if (DepthRTT)
1559         driver->removeTexture(DepthRTT);
1560 }
1561 
setScreenRenderTargetResolution(const irr::core::dimension2du & resolution)1562 inline void EffectHandler::setScreenRenderTargetResolution(const irr::core::dimension2du& resolution) {
1563     bool tempTexFlagMipMaps = driver->getTextureCreationFlag(irr::video::ETCF_CREATE_MIP_MAPS);
1564     bool tempTexFlag32 = driver->getTextureCreationFlag(irr::video::ETCF_ALWAYS_32_BIT);
1565 
1566     if (ScreenRTT)
1567         driver->removeTexture(ScreenRTT);
1568 
1569     ScreenRTT = driver->addRenderTargetTexture(resolution);
1570 
1571     if (ScreenQuad.rt[0])
1572         driver->removeTexture(ScreenQuad.rt[0]);
1573 
1574     ScreenQuad.rt[0] = driver->addRenderTargetTexture(resolution);
1575 
1576     if (ScreenQuad.rt[1])
1577         driver->removeTexture(ScreenQuad.rt[1]);
1578 
1579     ScreenQuad.rt[1] = driver->addRenderTargetTexture(resolution);
1580 
1581     if (DepthRTT != 0) {
1582         driver->removeTexture(DepthRTT);
1583         DepthRTT = driver->addRenderTargetTexture(resolution);
1584     }
1585 
1586     driver->setTextureCreationFlag(irr::video::ETCF_CREATE_MIP_MAPS, tempTexFlagMipMaps);
1587     driver->setTextureCreationFlag(irr::video::ETCF_ALWAYS_32_BIT, tempTexFlag32);
1588 
1589     ScreenRTTSize = resolution;
1590 }
1591 
enableDepthPass(bool enableDepthPass)1592 inline void EffectHandler::enableDepthPass(bool enableDepthPass) {
1593     DepthPass = enableDepthPass;
1594 
1595     if (DepthPass && DepthRTT == 0)
1596         DepthRTT = driver->addRenderTargetTexture(ScreenRTTSize, "depthRTT",
1597                                                   use32BitDepth ? irr::video::ECF_G32R32F : irr::video::ECF_G16R16F);
1598 }
1599 
addPostProcessingEffect(irr::s32 MaterialType,IPostProcessingRenderCallback * callback)1600 inline void EffectHandler::addPostProcessingEffect(irr::s32 MaterialType, IPostProcessingRenderCallback* callback) {
1601     SPostProcessingPair pPair(MaterialType, 0);
1602     pPair.renderCallback = callback;
1603     PostProcessingRoutines.push_back(pPair);
1604 }
1605 
addShadowToNode(irr::scene::ISceneNode * node,E_FILTER_TYPE filterType,E_SHADOW_MODE shadowMode)1606 inline void EffectHandler::addShadowToNode(irr::scene::ISceneNode* node,
1607                                            E_FILTER_TYPE filterType,
1608                                            E_SHADOW_MODE shadowMode) {
1609     SShadowNode snode = {node, shadowMode, filterType};
1610     ShadowNodeArray.push_back(snode);
1611 }
1612 
addNodeToDepthPass(irr::scene::ISceneNode * node)1613 inline void EffectHandler::addNodeToDepthPass(irr::scene::ISceneNode* node) {
1614     if (DepthPassArray.binary_search(node) == -1)
1615         DepthPassArray.push_back(node);
1616 }
1617 
removeNodeFromDepthPass(irr::scene::ISceneNode * node)1618 inline void EffectHandler::removeNodeFromDepthPass(irr::scene::ISceneNode* node) {
1619     irr::s32 i = DepthPassArray.binary_search(node);
1620 
1621     if (i != -1)
1622         DepthPassArray.erase(i);
1623 }
1624 
update(irr::video::ITexture * outputTarget)1625 inline void EffectHandler::update(irr::video::ITexture* outputTarget) {
1626     if (shadowsUnsupported || smgr->getActiveCamera() == 0)
1627         return;
1628 
1629     this->smgr->getRootSceneNode()->OnAnimate(device->getTimer()->getTime());
1630 
1631     if (!ShadowNodeArray.empty() && !LightList.empty()) {
1632         driver->setRenderTarget(ScreenQuad.rt[0], true, true, AmbientColour);
1633 
1634         irr::scene::ICameraSceneNode* activeCam = smgr->getActiveCamera();
1635         activeCam->OnAnimate(device->getTimer()->getTime());
1636         activeCam->OnRegisterSceneNode();
1637         activeCam->render();
1638 
1639         const irr::u32 ShadowNodeArraySize = ShadowNodeArray.size();
1640         const irr::u32 LightListSize = LightList.size();
1641         for (irr::u32 l = 0; l < LightListSize; ++l) {
1642             // Set max distance constant for depth shader.
1643             depthMC->FarLink = LightList[l].getFarValue();
1644 
1645             driver->setTransform(irr::video::ETS_VIEW, LightList[l].getViewMatrix());
1646             driver->setTransform(irr::video::ETS_PROJECTION, LightList[l].getProjectionMatrix());
1647 
1648             irr::video::ITexture* currentShadowMapTexture = getShadowMapTexture(LightList[l].getShadowMapResolution());
1649             driver->setRenderTarget(currentShadowMapTexture, true, true, irr::video::SColor(0xffffffff));
1650 
1651             for (irr::u32 i = 0; i < ShadowNodeArraySize; ++i) {
1652                 if (ShadowNodeArray[i].shadowMode == ESM_RECEIVE || ShadowNodeArray[i].shadowMode == ESM_EXCLUDE)
1653                     continue;
1654 
1655                 const irr::u32 CurrentMaterialCount = ShadowNodeArray[i].node->getMaterialCount();
1656                 irr::core::array<irr::s32> BufferMaterialList(CurrentMaterialCount);
1657                 BufferMaterialList.set_used(0);
1658 
1659                 for (irr::u32 m = 0; m < CurrentMaterialCount; ++m) {
1660                     BufferMaterialList.push_back(ShadowNodeArray[i].node->getMaterial(m).MaterialType);
1661                     ShadowNodeArray[i].node->getMaterial(m).MaterialType = (irr::video::E_MATERIAL_TYPE)(
1662                         BufferMaterialList[m] == irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF ? DepthT : Depth);
1663                 }
1664 
1665                 ShadowNodeArray[i].node->OnAnimate(device->getTimer()->getTime());
1666                 ShadowNodeArray[i].node->render();
1667 
1668                 const irr::u32 BufferMaterialListSize = BufferMaterialList.size();
1669                 for (irr::u32 m = 0; m < BufferMaterialListSize; ++m)
1670                     ShadowNodeArray[i].node->getMaterial(m).MaterialType =
1671                         (irr::video::E_MATERIAL_TYPE)BufferMaterialList[m];
1672             }
1673 
1674             // Blur the shadow map texture if we're using VSM filtering.
1675             if (useVSM) {
1676                 irr::video::ITexture* currentSecondaryShadowMap =
1677                     getShadowMapTexture(LightList[l].getShadowMapResolution(), true);
1678 
1679                 driver->setRenderTarget(currentSecondaryShadowMap, true, true, irr::video::SColor(0xffffffff));
1680                 ScreenQuad.getMaterial().setTexture(0, currentShadowMapTexture);
1681                 ScreenQuad.getMaterial().MaterialType = (irr::video::E_MATERIAL_TYPE)VSMBlurH;
1682 
1683                 ScreenQuad.render(driver);
1684 
1685                 driver->setRenderTarget(currentShadowMapTexture, true, true, irr::video::SColor(0xffffffff));
1686                 ScreenQuad.getMaterial().setTexture(0, currentSecondaryShadowMap);
1687                 ScreenQuad.getMaterial().MaterialType = (irr::video::E_MATERIAL_TYPE)VSMBlurV;
1688 
1689                 ScreenQuad.render(driver);
1690             }
1691 
1692             driver->setRenderTarget(ScreenQuad.rt[1], true, true, irr::video::SColor(0xffffffff));
1693 
1694             driver->setTransform(irr::video::ETS_VIEW, activeCam->getViewMatrix());
1695             driver->setTransform(irr::video::ETS_PROJECTION, activeCam->getProjectionMatrix());
1696 
1697             shadowMC->LightColour = LightList[l].getLightColor();
1698             shadowMC->LightLink = LightList[l].getPosition();
1699             shadowMC->FarLink = LightList[l].getFarValue();
1700             shadowMC->ViewLink = LightList[l].getViewMatrix();
1701             shadowMC->ProjLink = LightList[l].getProjectionMatrix();
1702             shadowMC->MapRes = (irr::f32)LightList[l].getShadowMapResolution();
1703             shadowMC->clipborder = LightList[l].getClipBorder();  //***ALEX***
1704 
1705             for (irr::u32 i = 0; i < ShadowNodeArraySize; ++i) {
1706                 if (ShadowNodeArray[i].shadowMode == ESM_CAST || ShadowNodeArray[i].shadowMode == ESM_EXCLUDE)
1707                     continue;
1708 
1709                 const irr::u32 CurrentMaterialCount = ShadowNodeArray[i].node->getMaterialCount();
1710                 irr::core::array<irr::s32> BufferMaterialList(CurrentMaterialCount);
1711                 irr::core::array<irr::video::ITexture*> BufferTextureList(CurrentMaterialCount);
1712 
1713                 for (irr::u32 m = 0; m < CurrentMaterialCount; ++m) {
1714                     BufferMaterialList.push_back(ShadowNodeArray[i].node->getMaterial(m).MaterialType);
1715                     BufferTextureList.push_back(ShadowNodeArray[i].node->getMaterial(m).getTexture(0));
1716 
1717                     ShadowNodeArray[i].node->getMaterial(m).MaterialType =
1718                         (irr::video::E_MATERIAL_TYPE)Shadow[ShadowNodeArray[i].filterType];
1719                     ShadowNodeArray[i].node->getMaterial(m).setTexture(0, currentShadowMapTexture);
1720                 }
1721 
1722                 ShadowNodeArray[i].node->OnAnimate(device->getTimer()->getTime());
1723                 ShadowNodeArray[i].node->render();
1724 
1725                 for (irr::u32 m = 0; m < CurrentMaterialCount; ++m) {
1726                     ShadowNodeArray[i].node->getMaterial(m).MaterialType =
1727                         (irr::video::E_MATERIAL_TYPE)BufferMaterialList[m];
1728                     ShadowNodeArray[i].node->getMaterial(m).setTexture(0, BufferTextureList[m]);
1729                 }
1730             }
1731 
1732             driver->setRenderTarget(ScreenQuad.rt[0], false, false, irr::video::SColor(0x0));
1733             ScreenQuad.getMaterial().setTexture(0, ScreenQuad.rt[1]);
1734             ScreenQuad.getMaterial().MaterialType = (irr::video::E_MATERIAL_TYPE)Simple;
1735 
1736             ScreenQuad.render(driver);
1737         }
1738 
1739         // Render all the excluded and casting-only nodes.
1740         for (irr::u32 i = 0; i < ShadowNodeArraySize; ++i) {
1741             if (ShadowNodeArray[i].shadowMode != ESM_CAST && ShadowNodeArray[i].shadowMode != ESM_EXCLUDE)
1742                 continue;
1743 
1744             const irr::u32 CurrentMaterialCount = ShadowNodeArray[i].node->getMaterialCount();
1745             irr::core::array<irr::s32> BufferMaterialList(CurrentMaterialCount);
1746             BufferMaterialList.set_used(0);
1747 
1748             for (irr::u32 m = 0; m < CurrentMaterialCount; ++m) {
1749                 BufferMaterialList.push_back(ShadowNodeArray[i].node->getMaterial(m).MaterialType);
1750 
1751                 switch (BufferMaterialList[m]) {
1752                     case irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF:
1753                         ShadowNodeArray[i].node->getMaterial(m).MaterialType =
1754                             (irr::video::E_MATERIAL_TYPE)WhiteWashTRef;
1755                         break;
1756                     case irr::video::EMT_TRANSPARENT_ADD_COLOR:
1757                         ShadowNodeArray[i].node->getMaterial(m).MaterialType =
1758                             (irr::video::E_MATERIAL_TYPE)WhiteWashTAdd;
1759                         break;
1760                     case irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL:
1761                         ShadowNodeArray[i].node->getMaterial(m).MaterialType =
1762                             (irr::video::E_MATERIAL_TYPE)WhiteWashTAlpha;
1763                         break;
1764                     default:
1765                         ShadowNodeArray[i].node->getMaterial(m).MaterialType = (irr::video::E_MATERIAL_TYPE)WhiteWash;
1766                         break;
1767                 }
1768             }
1769 
1770             ShadowNodeArray[i].node->OnAnimate(device->getTimer()->getTime());
1771             ShadowNodeArray[i].node->render();
1772 
1773             for (irr::u32 m = 0; m < CurrentMaterialCount; ++m)
1774                 ShadowNodeArray[i].node->getMaterial(m).MaterialType =
1775                     (irr::video::E_MATERIAL_TYPE)BufferMaterialList[m];
1776         }
1777     } else {
1778         driver->setRenderTarget(ScreenQuad.rt[0], true, true, irr::video::SColor(0xffffffff));
1779     }
1780 
1781     driver->setRenderTarget(ScreenQuad.rt[1], true, true, ClearColour);
1782     smgr->drawAll();
1783 
1784     const irr::u32 PostProcessingRoutinesSize = PostProcessingRoutines.size();
1785 
1786     driver->setRenderTarget(PostProcessingRoutinesSize ? ScreenRTT : outputTarget, true, true, irr::video::SColor(0x0));
1787 
1788     ScreenQuad.getMaterial().setTexture(0, ScreenQuad.rt[1]);
1789     ScreenQuad.getMaterial().setTexture(1, ScreenQuad.rt[0]);
1790 
1791     ScreenQuad.getMaterial().MaterialType = (irr::video::E_MATERIAL_TYPE)LightModulate;
1792     ScreenQuad.render(driver);
1793 
1794     // Perform depth pass after rendering, to ensure animations stay up to date.
1795     if (DepthPass) {
1796         driver->setRenderTarget(DepthRTT, true, true, irr::video::SColor(0xffffffff));
1797 
1798         // Set max distance constant for depth shader.
1799         depthMC->FarLink = smgr->getActiveCamera()->getFarValue();
1800 
1801         for (irr::u32 i = 0; i < DepthPassArray.size(); ++i) {
1802             irr::core::array<irr::s32> BufferMaterialList(DepthPassArray[i]->getMaterialCount());
1803             BufferMaterialList.set_used(0);
1804 
1805             for (irr::u32 g = 0; g < DepthPassArray[i]->getMaterialCount(); ++g)
1806                 BufferMaterialList.push_back(DepthPassArray[i]->getMaterial(g).MaterialType);
1807 
1808             DepthPassArray[i]->setMaterialType((irr::video::E_MATERIAL_TYPE)Depth);
1809             DepthPassArray[i]->OnAnimate(device->getTimer()->getTime());
1810             DepthPassArray[i]->render();
1811 
1812             for (irr::u32 g = 0; g < DepthPassArray[i]->getMaterialCount(); ++g)
1813                 DepthPassArray[i]->getMaterial(g).MaterialType = (irr::video::E_MATERIAL_TYPE)BufferMaterialList[g];
1814         }
1815 
1816         driver->setRenderTarget(0, false, false);
1817     }
1818 
1819     if (PostProcessingRoutinesSize) {
1820         bool Alter = false;
1821         ScreenQuad.getMaterial().setTexture(1, ScreenRTT);
1822         ScreenQuad.getMaterial().setTexture(2, DepthRTT);
1823         for (irr::u32 i = 0; i < PostProcessingRoutinesSize; ++i) {
1824             ScreenQuad.getMaterial().MaterialType = (irr::video::E_MATERIAL_TYPE)PostProcessingRoutines[i].materialType;
1825 
1826             Alter = !Alter;
1827             ScreenQuad.getMaterial().setTexture(0, i == 0 ? ScreenRTT : ScreenQuad.rt[int(!Alter)]);
1828             driver->setRenderTarget(i >= PostProcessingRoutinesSize - 1 ? outputTarget : ScreenQuad.rt[int(Alter)],
1829                                     true, true, ClearColour);
1830 
1831             if (PostProcessingRoutines[i].renderCallback)
1832                 PostProcessingRoutines[i].renderCallback->OnPreRender(this);
1833             ScreenQuad.render(driver);
1834             if (PostProcessingRoutines[i].renderCallback)
1835                 PostProcessingRoutines[i].renderCallback->OnPostRender(this);
1836         }
1837     }
1838 }
1839 
getShadowMapTexture(const irr::u32 resolution,const bool secondary)1840 inline irr::video::ITexture* EffectHandler::getShadowMapTexture(const irr::u32 resolution, const bool secondary) {
1841     // Using Irrlicht cache now.
1842     irr::core::stringc shadowMapName = irr::core::stringc("XEFFECTS_SM_") + irr::core::stringc(resolution);
1843 
1844     if (secondary)
1845         shadowMapName += "_2";
1846 
1847     irr::video::ITexture* shadowMapTexture = driver->getTexture(shadowMapName);
1848 
1849     if (shadowMapTexture == 0) {
1850         device->getLogger()->log("XEffects: Please ignore previous warning, it is harmless.");
1851 
1852         shadowMapTexture =
1853             driver->addRenderTargetTexture(irr::core::dimension2du(resolution, resolution), shadowMapName,
1854                                            use32BitDepth ? irr::video::ECF_G32R32F : irr::video::ECF_G16R16F);
1855     }
1856 
1857     return shadowMapTexture;
1858 }
1859 
generateRandomVectorTexture(const irr::core::dimension2du & dimensions,const irr::core::stringc & name)1860 inline irr::video::ITexture* EffectHandler::generateRandomVectorTexture(const irr::core::dimension2du& dimensions,
1861                                                                         const irr::core::stringc& name) {
1862     irr::video::IImage* tmpImage = driver->createImage(irr::video::ECF_A8R8G8B8, dimensions);
1863 
1864     srand(device->getTimer()->getRealTime());
1865 
1866     for (irr::u32 x = 0; x < dimensions.Width; ++x) {
1867         for (irr::u32 y = 0; y < dimensions.Height; ++y) {
1868             irr::core::vector3df randVec;
1869 
1870             // Reject vectors outside the unit sphere to get a uniform distribution.
1871             do {
1872                 randVec =
1873                     irr::core::vector3df((irr::f32)rand() / (irr::f32)RAND_MAX, (irr::f32)rand() / (irr::f32)RAND_MAX,
1874                                          (irr::f32)rand() / (irr::f32)RAND_MAX);
1875             } while (randVec.getLengthSQ() > 1.0f);
1876 
1877             const irr::video::SColorf randCol(randVec.X, randVec.Y, randVec.Z);
1878             tmpImage->setPixel(x, y, randCol.toSColor());
1879         }
1880     }
1881 
1882     irr::video::ITexture* randTexture = driver->addTexture(name, tmpImage);
1883 
1884     tmpImage->drop();
1885 
1886     return randTexture;
1887 }
1888 
obtainScreenQuadMaterialFromFile(const irr::core::stringc & filename,irr::video::E_MATERIAL_TYPE baseMaterial)1889 inline EffectHandler::SPostProcessingPair EffectHandler::obtainScreenQuadMaterialFromFile(
1890     const irr::core::stringc& filename,
1891     irr::video::E_MATERIAL_TYPE baseMaterial) {
1892     CShaderPreprocessor sPP(driver);
1893 
1894     sPP.addShaderDefine("SCREENX", irr::core::stringc(ScreenRTTSize.Width));
1895     sPP.addShaderDefine("SCREENY", irr::core::stringc(ScreenRTTSize.Height));
1896 
1897     irr::video::E_VERTEX_SHADER_TYPE VertexLevel =
1898         driver->queryFeature(irr::video::EVDF_VERTEX_SHADER_3_0) ? irr::video::EVST_VS_3_0 : irr::video::EVST_VS_2_0;
1899     irr::video::E_PIXEL_SHADER_TYPE PixelLevel =
1900         driver->queryFeature(irr::video::EVDF_PIXEL_SHADER_3_0) ? irr::video::EPST_PS_2_0 : irr::video::EPST_PS_2_0;
1901 
1902     E_SHADER_EXTENSION shaderExt = (driver->getDriverType() == irr::video::EDT_DIRECT3D9) ? ESE_HLSL : ESE_GLSL;
1903 
1904     irr::video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices();
1905 
1906     const irr::core::stringc shaderString = sPP.ppShaderFF(filename.c_str());
1907 
1908     ScreenQuadCB* SQCB = new ScreenQuadCB(this, true);
1909 
1910     irr::s32 PostMat =
1911         gpu->addHighLevelShaderMaterial(sPP.ppShader(SCREEN_QUAD_V[shaderExt]).c_str(), "vertexMain", VertexLevel,
1912                                         shaderString.c_str(), "pixelMain", PixelLevel, SQCB, baseMaterial);
1913 
1914     SPostProcessingPair pPair(PostMat, SQCB);
1915 
1916     SQCB->drop();
1917 
1918     return pPair;
1919 }
1920 
setPostProcessingEffectConstant(const irr::s32 materialType,const irr::core::stringc & name,const irr::f32 * data,const irr::u32 count)1921 inline void EffectHandler::setPostProcessingEffectConstant(const irr::s32 materialType,
1922                                                            const irr::core::stringc& name,
1923                                                            const irr::f32* data,
1924                                                            const irr::u32 count) {
1925     SPostProcessingPair tempPair(materialType, 0);
1926     irr::s32 matIndex = PostProcessingRoutines.binary_search(tempPair);
1927 
1928     if (matIndex != -1)
1929         PostProcessingRoutines[matIndex].callback->uniformDescriptors[name] =
1930             ScreenQuadCB::SUniformDescriptor(data, count);
1931 }
1932 
addPostProcessingEffectFromFile(const irr::core::stringc & filename,IPostProcessingRenderCallback * callback)1933 inline irr::s32 EffectHandler::addPostProcessingEffectFromFile(const irr::core::stringc& filename,
1934                                                                IPostProcessingRenderCallback* callback) {
1935     SPostProcessingPair pPair = obtainScreenQuadMaterialFromFile(filename);
1936     pPair.renderCallback = callback;
1937     PostProcessingRoutines.push_back(pPair);
1938 
1939     return pPair.materialType;
1940 }
1941 
1942 ///////////////ScreenQuadCB impl.
1943 
OnSetConstants(irr::video::IMaterialRendererServices * services,irr::s32 userData)1944 inline void ScreenQuadCB::OnSetConstants(irr::video::IMaterialRendererServices* services, irr::s32 userData) {
1945     if (services->getVideoDriver()->getDriverType() == irr::video::EDT_OPENGL) {
1946         //***ALEX*** modified for Irrlicht 1.8
1947         /*
1948         irr::s32 TexVar = 0;
1949         services->setPixelShaderConstant("ColorMapSampler", &TexVar, 1);
1950 
1951         TexVar = 1;
1952         services->setPixelShaderConstant("ScreenMapSampler", &TexVar, 1);
1953 
1954         TexVar = 2;
1955         services->setPixelShaderConstant("DepthMapSampler", &TexVar, 1);
1956 
1957         TexVar = 3;
1958         services->setPixelShaderConstant("UserMapSampler", &TexVar, 1);
1959         */
1960         /// Version for Irrlicht 1.7.3
1961         irr::u32 TexVar = 0;
1962         services->setPixelShaderConstant("ColorMapSampler", (irr::f32*)(&TexVar), 1);
1963 
1964         TexVar = 1;
1965         services->setPixelShaderConstant("ScreenMapSampler", (irr::f32*)(&TexVar), 1);
1966 
1967         TexVar = 2;
1968         services->setPixelShaderConstant("DepthMapSampler", (irr::f32*)(&TexVar), 1);
1969 
1970         TexVar = 3;
1971         services->setPixelShaderConstant("UserMapSampler", (irr::f32*)(&TexVar), 1);
1972     }
1973 
1974     if (defaultVertexShader) {
1975         const irr::core::dimension2du currentRTTSize = services->getVideoDriver()->getCurrentRenderTargetSize();
1976         const irr::f32 screenX = (irr::f32)currentRTTSize.Width, screenY = (irr::f32)currentRTTSize.Height;
1977 
1978         services->setVertexShaderConstant("screenX", &screenX, 1);
1979         services->setVertexShaderConstant("screenY", &screenY, 1);
1980 
1981         irr::scene::ISceneManager* smgr = effect->getActiveSceneManager();
1982         irr::scene::ICameraSceneNode* cam = smgr->getActiveCamera();
1983 
1984         const irr::core::position2di tLeft = services->getVideoDriver()->getViewPort().UpperLeftCorner;
1985         const irr::core::position2di bRight = services->getVideoDriver()->getViewPort().LowerRightCorner;
1986 
1987         const irr::core::line3df sLines[4] = {smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(
1988                                                   irr::core::position2di(tLeft.X, tLeft.Y), cam),
1989                                               smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(
1990                                                   irr::core::position2di(bRight.X, tLeft.Y), cam),
1991                                               smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(
1992                                                   irr::core::position2di(tLeft.X, bRight.Y), cam),
1993                                               smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(
1994                                                   irr::core::position2di(bRight.X, bRight.Y), cam)};
1995 
1996         services->setVertexShaderConstant("LineStarts0", &sLines[0].start.X, 3);
1997         services->setVertexShaderConstant("LineStarts1", &sLines[1].start.X, 3);
1998         services->setVertexShaderConstant("LineStarts2", &sLines[2].start.X, 3);
1999         services->setVertexShaderConstant("LineStarts3", &sLines[3].start.X, 3);
2000 
2001         services->setVertexShaderConstant("LineEnds0", &sLines[0].end.X, 3);
2002         services->setVertexShaderConstant("LineEnds1", &sLines[1].end.X, 3);
2003         services->setVertexShaderConstant("LineEnds2", &sLines[2].end.X, 3);
2004         services->setVertexShaderConstant("LineEnds3", &sLines[3].end.X, 3);
2005     }
2006 
2007     if (uniformDescriptors.size()) {
2008         irr::core::map<irr::core::stringc, SUniformDescriptor>::Iterator mapIter = uniformDescriptors.getIterator();
2009 
2010         for (; !mapIter.atEnd(); mapIter++) {
2011             if (mapIter.getNode()->getValue().fPointer == 0)
2012                 continue;
2013 
2014             services->setPixelShaderConstant(mapIter.getNode()->getKey().c_str(),
2015                                              mapIter.getNode()->getValue().fPointer,
2016                                              mapIter.getNode()->getValue().paramCount);
2017         }
2018     }
2019 }
2020 
2021 /// @} irrlicht_module
2022 
2023 }  // end namespace irrlicht
2024 }  // end namespace chrono
2025 
2026 #endif
2027