]> git.lizzy.rs Git - dragonfireclient.git/blob - src/client/shadows/dynamicshadowsrender.cpp
Force-update shadows when the world is changed (#12364)
[dragonfireclient.git] / src / client / shadows / dynamicshadowsrender.cpp
1 /*
2 Minetest
3 Copyright (C) 2021 Liso <anlismon@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <cstring>
21 #include <cmath>
22 #include "client/shadows/dynamicshadowsrender.h"
23 #include "client/shadows/shadowsScreenQuad.h"
24 #include "client/shadows/shadowsshadercallbacks.h"
25 #include "settings.h"
26 #include "filesys.h"
27 #include "util/string.h"
28 #include "client/shader.h"
29 #include "client/client.h"
30 #include "client/clientmap.h"
31 #include "profiler.h"
32
33 ShadowRenderer::ShadowRenderer(IrrlichtDevice *device, Client *client) :
34                 m_smgr(device->getSceneManager()), m_driver(device->getVideoDriver()),
35                 m_client(client), m_current_frame(0),
36                 m_perspective_bias_xy(0.8), m_perspective_bias_z(0.5)
37 {
38         (void) m_client;
39
40         m_shadows_supported = true; // assume shadows supported. We will check actual support in initialize
41         m_shadows_enabled = true;
42
43         m_shadow_strength_gamma = g_settings->getFloat("shadow_strength_gamma");
44         if (std::isnan(m_shadow_strength_gamma))
45                 m_shadow_strength_gamma = 1.0f;
46         m_shadow_strength_gamma = core::clamp(m_shadow_strength_gamma, 0.1f, 10.0f);
47
48         m_shadow_map_max_distance = g_settings->getFloat("shadow_map_max_distance");
49
50         m_shadow_map_texture_size = g_settings->getFloat("shadow_map_texture_size");
51
52         m_shadow_map_texture_32bit = g_settings->getBool("shadow_map_texture_32bit");
53         m_shadow_map_colored = g_settings->getBool("shadow_map_color");
54         m_shadow_samples = g_settings->getS32("shadow_filters");
55         m_map_shadow_update_frames = g_settings->getS16("shadow_update_frames");
56 }
57
58 ShadowRenderer::~ShadowRenderer()
59 {
60         // call to disable releases dynamically allocated resources
61         disable();
62
63         if (m_shadow_depth_cb)
64                 delete m_shadow_depth_cb;
65         if (m_shadow_depth_entity_cb)
66                 delete m_shadow_depth_entity_cb;
67         if (m_shadow_depth_trans_cb)
68                 delete m_shadow_depth_trans_cb;
69         if (m_shadow_mix_cb)
70                 delete m_shadow_mix_cb;
71         m_shadow_node_array.clear();
72         m_light_list.clear();
73
74         if (shadowMapTextureDynamicObjects)
75                 m_driver->removeTexture(shadowMapTextureDynamicObjects);
76
77         if (shadowMapTextureFinal)
78                 m_driver->removeTexture(shadowMapTextureFinal);
79
80         if (shadowMapTextureColors)
81                 m_driver->removeTexture(shadowMapTextureColors);
82
83         if (shadowMapClientMap)
84                 m_driver->removeTexture(shadowMapClientMap);
85
86         if (shadowMapClientMapFuture)
87                 m_driver->removeTexture(shadowMapClientMapFuture);
88 }
89
90 void ShadowRenderer::disable()
91 {
92         m_shadows_enabled = false;
93         if (shadowMapTextureFinal) {
94                 m_driver->setRenderTarget(shadowMapTextureFinal, true, true,
95                         video::SColor(255, 255, 255, 255));
96                 m_driver->setRenderTarget(0, true, true);
97         }
98 }
99
100 void ShadowRenderer::initialize()
101 {
102         auto *gpu = m_driver->getGPUProgrammingServices();
103
104         // we need glsl
105         if (m_shadows_supported && gpu && m_driver->queryFeature(video::EVDF_ARB_GLSL)) {
106                 createShaders();
107         } else {
108                 m_shadows_supported = false;
109
110                 warningstream << "Shadows: GLSL Shader not supported on this system."
111                         << std::endl;
112                 return;
113         }
114
115         m_texture_format = m_shadow_map_texture_32bit
116                                            ? video::ECOLOR_FORMAT::ECF_R32F
117                                            : video::ECOLOR_FORMAT::ECF_R16F;
118
119         m_texture_format_color = m_shadow_map_texture_32bit
120                                                  ? video::ECOLOR_FORMAT::ECF_G32R32F
121                                                  : video::ECOLOR_FORMAT::ECF_G16R16F;
122         
123         m_shadows_enabled &= m_shadows_supported;
124 }
125
126
127 size_t ShadowRenderer::addDirectionalLight()
128 {
129         m_light_list.emplace_back(m_shadow_map_texture_size,
130                         v3f(0.f, 0.f, 0.f),
131                         video::SColor(255, 255, 255, 255), m_shadow_map_max_distance);
132         return m_light_list.size() - 1;
133 }
134
135 DirectionalLight &ShadowRenderer::getDirectionalLight(u32 index)
136 {
137         return m_light_list[index];
138 }
139
140 size_t ShadowRenderer::getDirectionalLightCount() const
141 {
142         return m_light_list.size();
143 }
144
145 f32 ShadowRenderer::getMaxShadowFar() const
146 {
147         if (!m_light_list.empty()) {
148                 float zMax = m_light_list[0].getFarValue();
149                 return zMax;
150         }
151         return 0.0f;
152 }
153
154 void ShadowRenderer::setShadowIntensity(float shadow_intensity)
155 {
156         m_shadow_strength = pow(shadow_intensity, 1.0f / m_shadow_strength_gamma);
157         if (m_shadow_strength > 1E-2)
158                 enable();
159         else
160                 disable();
161 }
162
163 void ShadowRenderer::addNodeToShadowList(
164                 scene::ISceneNode *node, E_SHADOW_MODE shadowMode)
165 {
166         m_shadow_node_array.emplace_back(NodeToApply(node, shadowMode));
167 }
168
169 void ShadowRenderer::removeNodeFromShadowList(scene::ISceneNode *node)
170 {
171         for (auto it = m_shadow_node_array.begin(); it != m_shadow_node_array.end();) {
172                 if (it->node == node) {
173                         it = m_shadow_node_array.erase(it);
174                         break;
175                 } else {
176                         ++it;
177                 }
178         }
179 }
180
181 void ShadowRenderer::updateSMTextures()
182 {
183         if (!m_shadows_enabled || m_smgr->getActiveCamera() == nullptr) {
184                 return;
185         }
186
187         if (!shadowMapTextureDynamicObjects) {
188
189                 shadowMapTextureDynamicObjects = getSMTexture(
190                         std::string("shadow_dynamic_") + itos(m_shadow_map_texture_size),
191                         m_texture_format, true);
192                 assert(shadowMapTextureDynamicObjects != nullptr);
193         }
194
195         if (!shadowMapClientMap) {
196
197                 shadowMapClientMap = getSMTexture(
198                         std::string("shadow_clientmap_") + itos(m_shadow_map_texture_size),
199                         m_shadow_map_colored ? m_texture_format_color : m_texture_format,
200                         true);
201                 assert(shadowMapClientMap != nullptr);
202         }
203
204         if (!shadowMapClientMapFuture && m_map_shadow_update_frames > 1) {
205                 shadowMapClientMapFuture = getSMTexture(
206                         std::string("shadow_clientmap_bb_") + itos(m_shadow_map_texture_size),
207                         m_shadow_map_colored ? m_texture_format_color : m_texture_format,
208                         true);
209                 assert(shadowMapClientMapFuture != nullptr);
210         }
211
212         if (m_shadow_map_colored && !shadowMapTextureColors) {
213                 shadowMapTextureColors = getSMTexture(
214                         std::string("shadow_colored_") + itos(m_shadow_map_texture_size),
215                         m_shadow_map_colored ? m_texture_format_color : m_texture_format,
216                         true);
217                 assert(shadowMapTextureColors != nullptr);
218         }
219
220         // The merge all shadowmaps texture
221         if (!shadowMapTextureFinal) {
222                 video::ECOLOR_FORMAT frt;
223                 if (m_shadow_map_texture_32bit) {
224                         if (m_shadow_map_colored)
225                                 frt = video::ECOLOR_FORMAT::ECF_A32B32G32R32F;
226                         else
227                                 frt = video::ECOLOR_FORMAT::ECF_R32F;
228                 } else {
229                         if (m_shadow_map_colored)
230                                 frt = video::ECOLOR_FORMAT::ECF_A16B16G16R16F;
231                         else
232                                 frt = video::ECOLOR_FORMAT::ECF_R16F;
233                 }
234                 shadowMapTextureFinal = getSMTexture(
235                         std::string("shadowmap_final_") + itos(m_shadow_map_texture_size),
236                         frt, true);
237                 assert(shadowMapTextureFinal != nullptr);
238         }
239
240         if (!m_shadow_node_array.empty() && !m_light_list.empty()) {
241                 bool reset_sm_texture = false;
242
243                 // detect if SM should be regenerated
244                 for (DirectionalLight &light : m_light_list) {
245                         if (light.should_update_map_shadow || m_force_update_shadow_map) {
246                                 light.should_update_map_shadow = false;
247                                 m_current_frame = 0;
248                                 reset_sm_texture = true;
249                         }
250                 }
251
252                 video::ITexture* shadowMapTargetTexture = shadowMapClientMapFuture;
253                 if (shadowMapTargetTexture == nullptr)
254                         shadowMapTargetTexture = shadowMapClientMap;
255
256                 // Update SM incrementally:
257                 for (DirectionalLight &light : m_light_list) {
258                         // Static shader values.
259                         for (auto cb : {m_shadow_depth_cb, m_shadow_depth_entity_cb, m_shadow_depth_trans_cb})
260                                 if (cb) {
261                                         cb->MapRes = (f32)m_shadow_map_texture_size;
262                                         cb->MaxFar = (f32)m_shadow_map_max_distance * BS;
263                                         cb->PerspectiveBiasXY = getPerspectiveBiasXY();
264                                         cb->PerspectiveBiasZ = getPerspectiveBiasZ();
265                                         cb->CameraPos = light.getFuturePlayerPos();
266                                 }
267                         
268                         // set the Render Target
269                         // right now we can only render in usual RTT, not
270                         // Depth texture is available in irrlicth maybe we
271                         // should put some gl* fn here
272
273
274                         if (m_current_frame < m_map_shadow_update_frames || m_force_update_shadow_map) {
275                                 m_driver->setRenderTarget(shadowMapTargetTexture, reset_sm_texture, true,
276                                                 video::SColor(255, 255, 255, 255));
277                                 renderShadowMap(shadowMapTargetTexture, light);
278
279                                 // Render transparent part in one pass.
280                                 // This is also handled in ClientMap.
281                                 if (m_current_frame == m_map_shadow_update_frames - 1 || m_force_update_shadow_map) {
282                                         if (m_shadow_map_colored) {
283                                                 m_driver->setRenderTarget(0, false, false);
284                                                 m_driver->setRenderTarget(shadowMapTextureColors,
285                                                                 true, false, video::SColor(255, 255, 255, 255));
286                                         }
287                                         renderShadowMap(shadowMapTextureColors, light,
288                                                         scene::ESNRP_TRANSPARENT);
289                                 }
290                                 m_driver->setRenderTarget(0, false, false);
291                         }
292
293                         reset_sm_texture = false;
294                 } // end for lights
295
296                 // move to the next section
297                 if (m_current_frame <= m_map_shadow_update_frames)
298                         ++m_current_frame;
299
300                 // pass finished, swap textures and commit light changes
301                 if (m_current_frame == m_map_shadow_update_frames || m_force_update_shadow_map) {
302                         if (shadowMapClientMapFuture != nullptr)
303                                 std::swap(shadowMapClientMapFuture, shadowMapClientMap);
304
305                         // Let all lights know that maps are updated
306                         for (DirectionalLight &light : m_light_list)
307                                 light.commitFrustum();
308                 }
309                 m_force_update_shadow_map = false;
310         }
311 }
312
313 void ShadowRenderer::update(video::ITexture *outputTarget)
314 {
315         if (!m_shadows_enabled || m_smgr->getActiveCamera() == nullptr) {
316                 return;
317         }
318
319         updateSMTextures();
320
321         if (shadowMapTextureFinal == nullptr) {
322                 return;
323         }
324
325         if (!m_shadow_node_array.empty() && !m_light_list.empty()) {
326
327                 for (DirectionalLight &light : m_light_list) {
328                         // Static shader values for entities are set in updateSMTextures
329                         // SM texture for entities is not updated incrementally and 
330                         // must by updated using current player position.
331                         m_shadow_depth_entity_cb->CameraPos = light.getPlayerPos();
332
333                         // render shadows for the n0n-map objects.
334                         m_driver->setRenderTarget(shadowMapTextureDynamicObjects, true,
335                                         true, video::SColor(255, 255, 255, 255));
336                         renderShadowObjects(shadowMapTextureDynamicObjects, light);
337                         // clear the Render Target
338                         m_driver->setRenderTarget(0, false, false);
339
340                         // in order to avoid too many map shadow renders,
341                         // we should make a second pass to mix clientmap shadows and
342                         // entities shadows :(
343                         m_screen_quad->getMaterial().setTexture(0, shadowMapClientMap);
344                         // dynamic objs shadow texture.
345                         if (m_shadow_map_colored)
346                                 m_screen_quad->getMaterial().setTexture(1, shadowMapTextureColors);
347                         m_screen_quad->getMaterial().setTexture(2, shadowMapTextureDynamicObjects);
348
349                         m_driver->setRenderTarget(shadowMapTextureFinal, false, false,
350                                         video::SColor(255, 255, 255, 255));
351                         m_screen_quad->render(m_driver);
352                         m_driver->setRenderTarget(0, false, false);
353
354                 } // end for lights
355         }
356 }
357
358 void ShadowRenderer::drawDebug()
359 {
360         /* this code just shows shadows textures in screen and in ONLY for debugging*/
361         #if 0
362         // this is debug, ignore for now.
363         if (shadowMapTextureFinal)
364                 m_driver->draw2DImage(shadowMapTextureFinal,
365                                 core::rect<s32>(0, 50, 128, 128 + 50),
366                                 core::rect<s32>({0, 0}, shadowMapTextureFinal->getSize()));
367
368         if (shadowMapClientMap)
369                 m_driver->draw2DImage(shadowMapClientMap,
370                                 core::rect<s32>(0, 50 + 128, 128, 128 + 50 + 128),
371                                 core::rect<s32>({0, 0}, shadowMapTextureFinal->getSize()));
372         
373         if (shadowMapTextureDynamicObjects)
374                 m_driver->draw2DImage(shadowMapTextureDynamicObjects,
375                                 core::rect<s32>(0, 128 + 50 + 128, 128,
376                                                 128 + 50 + 128 + 128),
377                                 core::rect<s32>({0, 0}, shadowMapTextureDynamicObjects->getSize()));
378
379         if (m_shadow_map_colored && shadowMapTextureColors) {
380
381                 m_driver->draw2DImage(shadowMapTextureColors,
382                                 core::rect<s32>(128,128 + 50 + 128 + 128,
383                                                 128 + 128, 128 + 50 + 128 + 128 + 128),
384                                 core::rect<s32>({0, 0}, shadowMapTextureColors->getSize()));
385         }
386         #endif
387 }
388
389
390 video::ITexture *ShadowRenderer::getSMTexture(const std::string &shadow_map_name,
391                 video::ECOLOR_FORMAT texture_format, bool force_creation)
392 {
393         if (force_creation) {
394                 return m_driver->addRenderTargetTexture(
395                                 core::dimension2du(m_shadow_map_texture_size,
396                                                 m_shadow_map_texture_size),
397                                 shadow_map_name.c_str(), texture_format);
398         }
399
400         return m_driver->getTexture(shadow_map_name.c_str());
401 }
402
403 void ShadowRenderer::renderShadowMap(video::ITexture *target,
404                 DirectionalLight &light, scene::E_SCENE_NODE_RENDER_PASS pass)
405 {
406         m_driver->setTransform(video::ETS_VIEW, light.getFutureViewMatrix());
407         m_driver->setTransform(video::ETS_PROJECTION, light.getFutureProjectionMatrix());
408
409         // Operate on the client map
410         for (const auto &shadow_node : m_shadow_node_array) {
411                 if (strcmp(shadow_node.node->getName(), "ClientMap") != 0)
412                         continue;
413
414                 ClientMap *map_node = static_cast<ClientMap *>(shadow_node.node);
415
416                 video::SMaterial material;
417                 if (map_node->getMaterialCount() > 0) {
418                         // we only want the first material, which is the one with the albedo info
419                         material = map_node->getMaterial(0);
420                 }
421
422                 material.BackfaceCulling = false;
423                 material.FrontfaceCulling = true;
424
425                 if (m_shadow_map_colored && pass != scene::ESNRP_SOLID) {
426                         material.MaterialType = (video::E_MATERIAL_TYPE) depth_shader_trans;
427                 }
428                 else {
429                         material.MaterialType = (video::E_MATERIAL_TYPE) depth_shader;
430                         material.BlendOperation = video::EBO_MIN;
431                 }
432
433                 m_driver->setTransform(video::ETS_WORLD,
434                                 map_node->getAbsoluteTransformation());
435
436                 int frame = m_force_update_shadow_map ? 0 : m_current_frame;
437                 int total_frames = m_force_update_shadow_map ? 1 : m_map_shadow_update_frames;
438
439                 map_node->renderMapShadows(m_driver, material, pass, frame, total_frames);
440                 break;
441         }
442 }
443
444 void ShadowRenderer::renderShadowObjects(
445                 video::ITexture *target, DirectionalLight &light)
446 {
447         m_driver->setTransform(video::ETS_VIEW, light.getViewMatrix());
448         m_driver->setTransform(video::ETS_PROJECTION, light.getProjectionMatrix());
449
450         for (const auto &shadow_node : m_shadow_node_array) {
451                 // we only take care of the shadow casters
452                 if (shadow_node.shadowMode == ESM_RECEIVE ||
453                                 strcmp(shadow_node.node->getName(), "ClientMap") == 0)
454                         continue;
455
456                 // render other objects
457                 u32 n_node_materials = shadow_node.node->getMaterialCount();
458                 std::vector<s32> BufferMaterialList;
459                 std::vector<std::pair<bool, bool>> BufferMaterialCullingList;
460                 std::vector<video::E_BLEND_OPERATION> BufferBlendOperationList;
461                 BufferMaterialList.reserve(n_node_materials);
462                 BufferMaterialCullingList.reserve(n_node_materials);
463                 BufferBlendOperationList.reserve(n_node_materials);
464
465                 // backup materialtype for each material
466                 // (aka shader)
467                 // and replace it by our "depth" shader
468                 for (u32 m = 0; m < n_node_materials; m++) {
469                         auto &current_mat = shadow_node.node->getMaterial(m);
470
471                         BufferMaterialList.push_back(current_mat.MaterialType);
472                         current_mat.MaterialType =
473                                         (video::E_MATERIAL_TYPE)depth_shader_entities;
474
475                         BufferMaterialCullingList.emplace_back(
476                                 (bool)current_mat.BackfaceCulling, (bool)current_mat.FrontfaceCulling);
477                         BufferBlendOperationList.push_back(current_mat.BlendOperation);
478
479                         current_mat.BackfaceCulling = true;
480                         current_mat.FrontfaceCulling = false;
481                 }
482
483                 m_driver->setTransform(video::ETS_WORLD,
484                                 shadow_node.node->getAbsoluteTransformation());
485                 shadow_node.node->render();
486
487                 // restore the material.
488
489                 for (u32 m = 0; m < n_node_materials; m++) {
490                         auto &current_mat = shadow_node.node->getMaterial(m);
491
492                         current_mat.MaterialType = (video::E_MATERIAL_TYPE) BufferMaterialList[m];
493
494                         current_mat.BackfaceCulling = BufferMaterialCullingList[m].first;
495                         current_mat.FrontfaceCulling = BufferMaterialCullingList[m].second;
496                         current_mat.BlendOperation = BufferBlendOperationList[m];
497                 }
498
499         } // end for caster shadow nodes
500 }
501
502 void ShadowRenderer::mixShadowsQuad()
503 {
504 }
505
506 /*
507  * @Liso's disclaimer ;) This function loads the Shadow Mapping Shaders.
508  * I used a custom loader because I couldn't figure out how to use the base
509  * Shaders system with custom IShaderConstantSetCallBack without messing up the
510  * code too much. If anyone knows how to integrate this with the standard MT
511  * shaders, please feel free to change it.
512  */
513
514 void ShadowRenderer::createShaders()
515 {
516         video::IGPUProgrammingServices *gpu = m_driver->getGPUProgrammingServices();
517
518         if (depth_shader == -1) {
519                 std::string depth_shader_vs = getShaderPath("shadow_shaders", "pass1_vertex.glsl");
520                 if (depth_shader_vs.empty()) {
521                         m_shadows_supported = false;
522                         errorstream << "Error shadow mapping vs shader not found." << std::endl;
523                         return;
524                 }
525                 std::string depth_shader_fs = getShaderPath("shadow_shaders", "pass1_fragment.glsl");
526                 if (depth_shader_fs.empty()) {
527                         m_shadows_supported = false;
528                         errorstream << "Error shadow mapping fs shader not found." << std::endl;
529                         return;
530                 }
531                 m_shadow_depth_cb = new ShadowDepthShaderCB();
532
533                 depth_shader = gpu->addHighLevelShaderMaterial(
534                                 readShaderFile(depth_shader_vs).c_str(), "vertexMain",
535                                 video::EVST_VS_1_1,
536                                 readShaderFile(depth_shader_fs).c_str(), "pixelMain",
537                                 video::EPST_PS_1_2, m_shadow_depth_cb, video::EMT_ONETEXTURE_BLEND);
538
539                 if (depth_shader == -1) {
540                         // upsi, something went wrong loading shader.
541                         delete m_shadow_depth_cb;
542                         m_shadow_depth_cb = nullptr;
543                         m_shadows_enabled = false;
544                         m_shadows_supported = false;
545                         errorstream << "Error compiling shadow mapping shader." << std::endl;
546                         return;
547                 }
548
549                 // HACK, TODO: investigate this better
550                 // Grab the material renderer once more so minetest doesn't crash
551                 // on exit
552                 m_driver->getMaterialRenderer(depth_shader)->grab();
553         }
554
555         // This creates a clone of depth_shader with base material set to EMT_SOLID,
556         // because entities won't render shadows with base material EMP_ONETEXTURE_BLEND
557         if (depth_shader_entities == -1) {
558                 std::string depth_shader_vs = getShaderPath("shadow_shaders", "pass1_vertex.glsl");
559                 if (depth_shader_vs.empty()) {
560                         m_shadows_supported = false;
561                         errorstream << "Error shadow mapping vs shader not found." << std::endl;
562                         return;
563                 }
564                 std::string depth_shader_fs = getShaderPath("shadow_shaders", "pass1_fragment.glsl");
565                 if (depth_shader_fs.empty()) {
566                         m_shadows_supported = false;
567                         errorstream << "Error shadow mapping fs shader not found." << std::endl;
568                         return;
569                 }
570                 m_shadow_depth_entity_cb = new ShadowDepthShaderCB();
571
572                 depth_shader_entities = gpu->addHighLevelShaderMaterial(
573                                 readShaderFile(depth_shader_vs).c_str(), "vertexMain",
574                                 video::EVST_VS_1_1,
575                                 readShaderFile(depth_shader_fs).c_str(), "pixelMain",
576                                 video::EPST_PS_1_2, m_shadow_depth_entity_cb);
577
578                 if (depth_shader_entities == -1) {
579                         // upsi, something went wrong loading shader.
580                         delete m_shadow_depth_entity_cb;
581                         m_shadow_depth_entity_cb = nullptr;
582                         m_shadows_enabled = false;
583                         m_shadows_supported = false;
584                         errorstream << "Error compiling shadow mapping shader (dynamic)." << std::endl;
585                         return;
586                 }
587
588                 // HACK, TODO: investigate this better
589                 // Grab the material renderer once more so minetest doesn't crash
590                 // on exit
591                 m_driver->getMaterialRenderer(depth_shader_entities)->grab();
592         }
593
594         if (mixcsm_shader == -1) {
595                 std::string depth_shader_vs = getShaderPath("shadow_shaders", "pass2_vertex.glsl");
596                 if (depth_shader_vs.empty()) {
597                         m_shadows_supported = false;
598                         errorstream << "Error cascade shadow mapping fs shader not found." << std::endl;
599                         return;
600                 }
601
602                 std::string depth_shader_fs = getShaderPath("shadow_shaders", "pass2_fragment.glsl");
603                 if (depth_shader_fs.empty()) {
604                         m_shadows_supported = false;
605                         errorstream << "Error cascade shadow mapping fs shader not found." << std::endl;
606                         return;
607                 }
608                 m_shadow_mix_cb = new shadowScreenQuadCB();
609                 m_screen_quad = new shadowScreenQuad();
610                 mixcsm_shader = gpu->addHighLevelShaderMaterial(
611                                 readShaderFile(depth_shader_vs).c_str(), "vertexMain",
612                                 video::EVST_VS_1_1,
613                                 readShaderFile(depth_shader_fs).c_str(), "pixelMain",
614                                 video::EPST_PS_1_2, m_shadow_mix_cb);
615
616                 m_screen_quad->getMaterial().MaterialType =
617                                 (video::E_MATERIAL_TYPE)mixcsm_shader;
618
619                 if (mixcsm_shader == -1) {
620                         // upsi, something went wrong loading shader.
621                         delete m_shadow_mix_cb;
622                         delete m_screen_quad;
623                         m_shadows_supported = false;
624                         errorstream << "Error compiling cascade shadow mapping shader." << std::endl;
625                         return;
626                 }
627
628                 // HACK, TODO: investigate this better
629                 // Grab the material renderer once more so minetest doesn't crash
630                 // on exit
631                 m_driver->getMaterialRenderer(mixcsm_shader)->grab();
632         }
633
634         if (m_shadow_map_colored && depth_shader_trans == -1) {
635                 std::string depth_shader_vs = getShaderPath("shadow_shaders", "pass1_trans_vertex.glsl");
636                 if (depth_shader_vs.empty()) {
637                         m_shadows_supported = false;
638                         errorstream << "Error shadow mapping vs shader not found." << std::endl;
639                         return;
640                 }
641                 std::string depth_shader_fs = getShaderPath("shadow_shaders", "pass1_trans_fragment.glsl");
642                 if (depth_shader_fs.empty()) {
643                         m_shadows_supported = false;
644                         errorstream << "Error shadow mapping fs shader not found." << std::endl;
645                         return;
646                 }
647                 m_shadow_depth_trans_cb = new ShadowDepthShaderCB();
648
649                 depth_shader_trans = gpu->addHighLevelShaderMaterial(
650                                 readShaderFile(depth_shader_vs).c_str(), "vertexMain",
651                                 video::EVST_VS_1_1,
652                                 readShaderFile(depth_shader_fs).c_str(), "pixelMain",
653                                 video::EPST_PS_1_2, m_shadow_depth_trans_cb);
654
655                 if (depth_shader_trans == -1) {
656                         // upsi, something went wrong loading shader.
657                         delete m_shadow_depth_trans_cb;
658                         m_shadow_depth_trans_cb = nullptr;
659                         m_shadow_map_colored = false;
660                         m_shadows_supported = false;
661                         errorstream << "Error compiling colored shadow mapping shader." << std::endl;
662                         return;
663                 }
664
665                 // HACK, TODO: investigate this better
666                 // Grab the material renderer once more so minetest doesn't crash
667                 // on exit
668                 m_driver->getMaterialRenderer(depth_shader_trans)->grab();
669         }
670 }
671
672 std::string ShadowRenderer::readShaderFile(const std::string &path)
673 {
674         std::string prefix;
675         if (m_shadow_map_colored)
676                 prefix.append("#define COLORED_SHADOWS 1\n");
677         prefix.append("#line 0\n");
678
679         std::string content;
680         fs::ReadFile(path, content);
681
682         return prefix + content;
683 }