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