3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 Copyright (C) 2013 Kahrl <kahrl@gmx.net>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "irrlichttypes_extrabloated.h"
28 #include "util/container.h"
29 #include "util/thread.h"
31 #include <ICameraSceneNode.h>
32 #include <IGPUProgrammingServices.h>
33 #include <IMaterialRenderer.h>
34 #include <IMaterialRendererServices.h>
35 #include <IShaderConstantSetCallBack.h>
36 #include "client/renderingengine.h"
37 #include "EShaderTypes.h"
40 #include "client/tile.h"
43 #include <mt_opengl.h>
46 A cache from shader name to shader path
48 MutexedMap<std::string, std::string> g_shadername_to_path_cache;
51 Gets the path to a shader by first checking if the file
52 name_of_shader/filename
53 exists in shader_path and if not, using the data path.
55 If not found, returns "".
57 Utilizes a thread-safe cache.
59 std::string getShaderPath(const std::string &name_of_shader,
60 const std::string &filename)
62 std::string combined = name_of_shader + DIR_DELIM + filename;
67 bool incache = g_shadername_to_path_cache.get(combined, &fullpath);
72 Check from shader_path
74 std::string shader_path = g_settings->get("shader_path");
75 if (!shader_path.empty()) {
76 std::string testpath = shader_path + DIR_DELIM + combined;
77 if(fs::PathExists(testpath))
82 Check from default data directory
84 if (fullpath.empty()) {
85 std::string rel_path = std::string("client") + DIR_DELIM
86 + "shaders" + DIR_DELIM
87 + name_of_shader + DIR_DELIM
89 std::string testpath = porting::path_share + DIR_DELIM + rel_path;
90 if(fs::PathExists(testpath))
94 // Add to cache (also an empty result is cached)
95 g_shadername_to_path_cache.set(combined, fullpath);
102 SourceShaderCache: A cache used for storing source shaders.
105 class SourceShaderCache
108 void insert(const std::string &name_of_shader, const std::string &filename,
109 const std::string &program, bool prefer_local)
111 std::string combined = name_of_shader + DIR_DELIM + filename;
112 // Try to use local shader instead if asked to
114 std::string path = getShaderPath(name_of_shader, filename);
116 std::string p = readFile(path);
118 m_programs[combined] = p;
123 m_programs[combined] = program;
126 std::string get(const std::string &name_of_shader,
127 const std::string &filename)
129 std::string combined = name_of_shader + DIR_DELIM + filename;
130 StringMap::iterator n = m_programs.find(combined);
131 if (n != m_programs.end())
136 // Primarily fetches from cache, secondarily tries to read from filesystem
137 std::string getOrLoad(const std::string &name_of_shader,
138 const std::string &filename)
140 std::string combined = name_of_shader + DIR_DELIM + filename;
141 StringMap::iterator n = m_programs.find(combined);
142 if (n != m_programs.end())
144 std::string path = getShaderPath(name_of_shader, filename);
146 infostream << "SourceShaderCache::getOrLoad(): No path found for \""
147 << combined << "\"" << std::endl;
150 infostream << "SourceShaderCache::getOrLoad(): Loading path \""
151 << path << "\"" << std::endl;
152 std::string p = readFile(path);
154 m_programs[combined] = p;
160 StringMap m_programs;
162 std::string readFile(const std::string &path)
164 std::ifstream is(path.c_str(), std::ios::binary);
167 std::ostringstream tmp_os;
168 tmp_os << is.rdbuf();
175 ShaderCallback: Sets constants that can be used in shaders
178 class ShaderCallback : public video::IShaderConstantSetCallBack
180 std::vector<std::unique_ptr<IShaderConstantSetter>> m_setters;
183 template <typename Factories>
184 ShaderCallback(const Factories &factories)
186 for (auto &&factory : factories)
187 m_setters.emplace_back(factory->create());
190 virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData) override
192 video::IVideoDriver *driver = services->getVideoDriver();
193 sanity_check(driver != NULL);
195 for (auto &&setter : m_setters)
196 setter->onSetConstants(services);
199 virtual void OnSetMaterial(const video::SMaterial& material) override
201 for (auto &&setter : m_setters)
202 setter->onSetMaterial(material);
208 MainShaderConstantSetter: Set basic constants required for almost everything
211 class MainShaderConstantSetter : public IShaderConstantSetter
213 CachedVertexShaderSetting<f32, 16> m_world_view_proj;
214 CachedVertexShaderSetting<f32, 16> m_world;
217 CachedPixelShaderSetting<f32, 16> m_shadow_view_proj;
218 CachedPixelShaderSetting<f32, 3> m_light_direction;
219 CachedPixelShaderSetting<f32> m_texture_res;
220 CachedPixelShaderSetting<f32> m_shadow_strength;
221 CachedPixelShaderSetting<f32> m_time_of_day;
222 CachedPixelShaderSetting<f32> m_shadowfar;
223 CachedPixelShaderSetting<f32, 4> m_camera_pos;
224 CachedPixelShaderSetting<s32> m_shadow_texture;
225 CachedVertexShaderSetting<f32> m_perspective_bias0_vertex;
226 CachedPixelShaderSetting<f32> m_perspective_bias0_pixel;
227 CachedVertexShaderSetting<f32> m_perspective_bias1_vertex;
228 CachedPixelShaderSetting<f32> m_perspective_bias1_pixel;
229 CachedVertexShaderSetting<f32> m_perspective_zbias_vertex;
230 CachedPixelShaderSetting<f32> m_perspective_zbias_pixel;
234 CachedVertexShaderSetting<float, 16> m_world_view;
236 CachedVertexShaderSetting<float, 16> m_texture;
238 CachedVertexShaderSetting<float, 9> m_normal;
242 MainShaderConstantSetter() :
243 m_world_view_proj("mWorldViewProj")
245 , m_shadow_view_proj("m_ShadowViewProj")
246 , m_light_direction("v_LightDirection")
247 , m_texture_res("f_textureresolution")
248 , m_shadow_strength("f_shadow_strength")
249 , m_time_of_day("f_timeofday")
250 , m_shadowfar("f_shadowfar")
251 , m_camera_pos("CameraPos")
252 , m_shadow_texture("ShadowMapSampler")
253 , m_perspective_bias0_vertex("xyPerspectiveBias0")
254 , m_perspective_bias0_pixel("xyPerspectiveBias0")
255 , m_perspective_bias1_vertex("xyPerspectiveBias1")
256 , m_perspective_bias1_pixel("xyPerspectiveBias1")
257 , m_perspective_zbias_vertex("zPerspectiveBias")
258 , m_perspective_zbias_pixel("zPerspectiveBias")
260 , m_world_view("mWorldView")
261 , m_texture("mTexture")
262 , m_normal("mNormal")
265 ~MainShaderConstantSetter() = default;
267 virtual void onSetConstants(video::IMaterialRendererServices *services) override
269 video::IVideoDriver *driver = services->getVideoDriver();
270 sanity_check(driver);
273 core::matrix4 world = driver->getTransform(video::ETS_WORLD);
274 m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
277 core::matrix4 worldView;
278 worldView = driver->getTransform(video::ETS_VIEW);
281 core::matrix4 worldViewProj;
282 worldViewProj = driver->getTransform(video::ETS_PROJECTION);
283 worldViewProj *= worldView;
284 m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
287 core::matrix4 texture = driver->getTransform(video::ETS_TEXTURE_0);
288 m_world_view.set(*reinterpret_cast<float(*)[16]>(worldView.pointer()), services);
289 m_texture.set(*reinterpret_cast<float(*)[16]>(texture.pointer()), services);
291 core::matrix4 normal;
292 worldView.getTransposed(normal);
293 sanity_check(normal.makeInverse());
295 normal[0], normal[1], normal[2],
296 normal[4], normal[5], normal[6],
297 normal[8], normal[9], normal[10],
299 m_normal.set(m, services);
302 // Set uniforms for Shadow shader
303 if (ShadowRenderer *shadow = RenderingEngine::get_shadow_renderer()) {
304 const auto &light = shadow->getDirectionalLight();
306 core::matrix4 shadowViewProj = light.getProjectionMatrix();
307 shadowViewProj *= light.getViewMatrix();
308 m_shadow_view_proj.set(shadowViewProj.pointer(), services);
310 f32 v_LightDirection[3];
311 light.getDirection().getAs3Values(v_LightDirection);
312 m_light_direction.set(v_LightDirection, services);
314 f32 TextureResolution = light.getMapResolution();
315 m_texture_res.set(&TextureResolution, services);
317 f32 ShadowStrength = shadow->getShadowStrength();
318 m_shadow_strength.set(&ShadowStrength, services);
320 f32 timeOfDay = shadow->getTimeOfDay();
321 m_time_of_day.set(&timeOfDay, services);
323 f32 shadowFar = shadow->getMaxShadowFar();
324 m_shadowfar.set(&shadowFar, services);
327 shadowViewProj.transformVect(cam_pos, light.getPlayerPos());
328 m_camera_pos.set(cam_pos, services);
330 // I don't like using this hardcoded value. maybe something like
331 // MAX_TEXTURE - 1 or somthing like that??
332 s32 TextureLayerID = 3;
333 m_shadow_texture.set(&TextureLayerID, services);
335 f32 bias0 = shadow->getPerspectiveBiasXY();
336 m_perspective_bias0_vertex.set(&bias0, services);
337 m_perspective_bias0_pixel.set(&bias0, services);
338 f32 bias1 = 1.0f - bias0 + 1e-5f;
339 m_perspective_bias1_vertex.set(&bias1, services);
340 m_perspective_bias1_pixel.set(&bias1, services);
341 f32 zbias = shadow->getPerspectiveBiasZ();
342 m_perspective_zbias_vertex.set(&zbias, services);
343 m_perspective_zbias_pixel.set(&zbias, services);
349 class MainShaderConstantSetterFactory : public IShaderConstantSetterFactory
352 virtual IShaderConstantSetter* create()
353 { return new MainShaderConstantSetter(); }
361 class ShaderSource : public IWritableShaderSource
367 - If shader material specified by name is found from cache,
368 return the cached id.
369 - Otherwise generate the shader material, add to cache and return id.
371 The id 0 points to a null shader. Its material is EMT_SOLID.
373 u32 getShaderIdDirect(const std::string &name,
374 MaterialType material_type, NodeDrawType drawtype) override;
377 If shader specified by the name pointed by the id doesn't
378 exist, create it, then return id.
380 Can be called from any thread. If called from some other thread
381 and not found in cache, the call is queued to the main thread
385 u32 getShader(const std::string &name,
386 MaterialType material_type, NodeDrawType drawtype) override;
388 ShaderInfo getShaderInfo(u32 id) override;
390 // Processes queued shader requests from other threads.
391 // Shall be called from the main thread.
392 void processQueue() override;
394 // Insert a shader program into the cache without touching the
395 // filesystem. Shall be called from the main thread.
396 void insertSourceShader(const std::string &name_of_shader,
397 const std::string &filename, const std::string &program) override;
399 // Rebuild shaders from the current set of source shaders
400 // Shall be called from the main thread.
401 void rebuildShaders() override;
403 void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter) override
405 m_setter_factories.emplace_back(setter);
410 // The id of the thread that is allowed to use irrlicht directly
411 std::thread::id m_main_thread;
413 // Cache of source shaders
414 // This should be only accessed from the main thread
415 SourceShaderCache m_sourcecache;
417 // A shader id is index in this array.
418 // The first position contains a dummy shader.
419 std::vector<ShaderInfo> m_shaderinfo_cache;
420 // The former container is behind this mutex
421 std::mutex m_shaderinfo_cache_mutex;
423 // Queued shader fetches (to be processed by the main thread)
424 RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
426 // Global constant setter factories
427 std::vector<std::unique_ptr<IShaderConstantSetterFactory>> m_setter_factories;
429 // Generate shader given the shader name.
430 ShaderInfo generateShader(const std::string &name,
431 MaterialType material_type, NodeDrawType drawtype);
434 IWritableShaderSource *createShaderSource()
436 return new ShaderSource();
439 ShaderSource::ShaderSource()
441 m_main_thread = std::this_thread::get_id();
443 // Add a dummy ShaderInfo as the first index, named ""
444 m_shaderinfo_cache.emplace_back();
446 // Add main global constant setter
447 addShaderConstantSetterFactory(new MainShaderConstantSetterFactory());
450 u32 ShaderSource::getShader(const std::string &name,
451 MaterialType material_type, NodeDrawType drawtype)
457 if (std::this_thread::get_id() == m_main_thread) {
458 return getShaderIdDirect(name, material_type, drawtype);
461 /*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/
463 // We're gonna ask the result to be put into here
465 static ResultQueue<std::string, u32, u8, u8> result_queue;
467 // Throw a request in
468 m_get_shader_queue.add(name, 0, 0, &result_queue);
470 /* infostream<<"Waiting for shader from main thread, name=\""
471 <<name<<"\""<<std::endl;*/
474 GetResult<std::string, u32, u8, u8>
475 result = result_queue.pop_frontNoEx();
477 if (result.key == name) {
481 errorstream << "Got shader with invalid name: " << result.key << std::endl;
484 infostream << "getShader(): Failed" << std::endl;
490 This method generates all the shaders
492 u32 ShaderSource::getShaderIdDirect(const std::string &name,
493 MaterialType material_type, NodeDrawType drawtype)
495 //infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
497 // Empty name means shader 0
499 infostream<<"getShaderIdDirect(): name is empty"<<std::endl;
503 // Check if already have such instance
504 for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
505 ShaderInfo *info = &m_shaderinfo_cache[i];
506 if(info->name == name && info->material_type == material_type &&
507 info->drawtype == drawtype)
512 Calling only allowed from main thread
514 if (std::this_thread::get_id() != m_main_thread) {
515 errorstream<<"ShaderSource::getShaderIdDirect() "
516 "called not from main thread"<<std::endl;
520 ShaderInfo info = generateShader(name, material_type, drawtype);
523 Add shader to caches (add dummy shaders too)
526 MutexAutoLock lock(m_shaderinfo_cache_mutex);
528 u32 id = m_shaderinfo_cache.size();
529 m_shaderinfo_cache.push_back(info);
531 infostream<<"getShaderIdDirect(): "
532 <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;
538 ShaderInfo ShaderSource::getShaderInfo(u32 id)
540 MutexAutoLock lock(m_shaderinfo_cache_mutex);
542 if(id >= m_shaderinfo_cache.size())
545 return m_shaderinfo_cache[id];
548 void ShaderSource::processQueue()
554 void ShaderSource::insertSourceShader(const std::string &name_of_shader,
555 const std::string &filename, const std::string &program)
557 /*infostream<<"ShaderSource::insertSourceShader(): "
558 "name_of_shader=\""<<name_of_shader<<"\", "
559 "filename=\""<<filename<<"\""<<std::endl;*/
561 sanity_check(std::this_thread::get_id() == m_main_thread);
563 m_sourcecache.insert(name_of_shader, filename, program, true);
566 void ShaderSource::rebuildShaders()
568 MutexAutoLock lock(m_shaderinfo_cache_mutex);
570 /*// Oh well... just clear everything, they'll load sometime.
571 m_shaderinfo_cache.clear();
572 m_name_to_id.clear();*/
575 FIXME: Old shader materials can't be deleted in Irrlicht,
577 (This would be nice to do in the destructor too)
581 for (ShaderInfo &i : m_shaderinfo_cache) {
582 ShaderInfo *info = &i;
583 if (!info->name.empty()) {
584 *info = generateShader(info->name, info->material_type, info->drawtype);
590 ShaderInfo ShaderSource::generateShader(const std::string &name,
591 MaterialType material_type, NodeDrawType drawtype)
593 ShaderInfo shaderinfo;
594 shaderinfo.name = name;
595 shaderinfo.material_type = material_type;
596 shaderinfo.drawtype = drawtype;
597 switch (material_type) {
598 case TILE_MATERIAL_OPAQUE:
599 case TILE_MATERIAL_LIQUID_OPAQUE:
600 case TILE_MATERIAL_WAVING_LIQUID_OPAQUE:
601 shaderinfo.base_material = video::EMT_SOLID;
603 case TILE_MATERIAL_ALPHA:
604 case TILE_MATERIAL_PLAIN_ALPHA:
605 case TILE_MATERIAL_LIQUID_TRANSPARENT:
606 case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
607 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
609 case TILE_MATERIAL_BASIC:
610 case TILE_MATERIAL_PLAIN:
611 case TILE_MATERIAL_WAVING_LEAVES:
612 case TILE_MATERIAL_WAVING_PLANTS:
613 case TILE_MATERIAL_WAVING_LIQUID_BASIC:
614 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
617 shaderinfo.material = shaderinfo.base_material;
619 bool enable_shaders = g_settings->getBool("enable_shaders");
623 video::IVideoDriver *driver = RenderingEngine::get_video_driver();
624 if (!driver->queryFeature(video::EVDF_ARB_GLSL)) {
625 errorstream << "Shaders are enabled but GLSL is not supported by the driver\n";
628 video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
630 // Create shaders header
631 bool use_gles = false;
633 use_gles = driver->getDriverType() == video::EDT_OGLES2;
635 std::stringstream shaders_header;
638 << std::showpoint // for GLSL ES
640 std::string vertex_header, fragment_header, geometry_header;
642 shaders_header << R"(
646 precision mediump float;
648 uniform highp mat4 mWorldView;
649 uniform highp mat4 mWorldViewProj;
650 uniform mediump mat4 mTexture;
651 uniform mediump mat3 mNormal;
653 attribute highp vec4 inVertexPosition;
654 attribute lowp vec4 inVertexColor;
655 attribute mediump vec4 inTexCoord0;
656 attribute mediump vec3 inVertexNormal;
657 attribute mediump vec4 inVertexTangent;
658 attribute mediump vec4 inVertexBinormal;
660 fragment_header = R"(
661 precision mediump float;
664 shaders_header << R"(
671 #define mWorldView gl_ModelViewMatrix
672 #define mWorldViewProj gl_ModelViewProjectionMatrix
673 #define mTexture (gl_TextureMatrix[0])
674 #define mNormal gl_NormalMatrix
676 #define inVertexPosition gl_Vertex
677 #define inVertexColor gl_Color
678 #define inTexCoord0 gl_MultiTexCoord0
679 #define inVertexNormal gl_Normal
680 #define inVertexTangent gl_MultiTexCoord1
681 #define inVertexBinormal gl_MultiTexCoord2
685 // map legacy semantic texture names to texture identifiers
686 fragment_header += R"(
687 #define baseTexture texture0
688 #define normalTexture texture1
689 #define textureFlags texture2
692 // Since this is the first time we're using the GL bindings be extra careful.
693 // This should be removed before 5.6.0 or similar.
695 errorstream << "OpenGL procedures were not loaded correctly, "
696 "please open a bug report with details about your platform/OS." << std::endl;
700 bool use_discard = use_gles;
701 // For renderers that should use discard instead of GL_ALPHA_TEST
702 const char *renderer = reinterpret_cast<const char*>(GL.GetString(GL.RENDERER));
703 if (strstr(renderer, "GC7000"))
706 if (shaderinfo.base_material == video::EMT_TRANSPARENT_ALPHA_CHANNEL)
707 shaders_header << "#define USE_DISCARD 1\n";
708 else if (shaderinfo.base_material == video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF)
709 shaders_header << "#define USE_DISCARD_REF 1\n";
712 #define PROVIDE(constant) shaders_header << "#define " #constant " " << (int)constant << "\n"
715 PROVIDE(NDT_AIRLIKE);
717 PROVIDE(NDT_FLOWINGLIQUID);
718 PROVIDE(NDT_GLASSLIKE);
719 PROVIDE(NDT_ALLFACES);
720 PROVIDE(NDT_ALLFACES_OPTIONAL);
721 PROVIDE(NDT_TORCHLIKE);
722 PROVIDE(NDT_SIGNLIKE);
723 PROVIDE(NDT_PLANTLIKE);
724 PROVIDE(NDT_FENCELIKE);
725 PROVIDE(NDT_RAILLIKE);
726 PROVIDE(NDT_NODEBOX);
727 PROVIDE(NDT_GLASSLIKE_FRAMED);
728 PROVIDE(NDT_FIRELIKE);
729 PROVIDE(NDT_GLASSLIKE_FRAMED_OPTIONAL);
730 PROVIDE(NDT_PLANTLIKE_ROOTED);
732 PROVIDE(TILE_MATERIAL_BASIC);
733 PROVIDE(TILE_MATERIAL_ALPHA);
734 PROVIDE(TILE_MATERIAL_LIQUID_TRANSPARENT);
735 PROVIDE(TILE_MATERIAL_LIQUID_OPAQUE);
736 PROVIDE(TILE_MATERIAL_WAVING_LEAVES);
737 PROVIDE(TILE_MATERIAL_WAVING_PLANTS);
738 PROVIDE(TILE_MATERIAL_OPAQUE);
739 PROVIDE(TILE_MATERIAL_WAVING_LIQUID_BASIC);
740 PROVIDE(TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT);
741 PROVIDE(TILE_MATERIAL_WAVING_LIQUID_OPAQUE);
742 PROVIDE(TILE_MATERIAL_PLAIN);
743 PROVIDE(TILE_MATERIAL_PLAIN_ALPHA);
747 shaders_header << "#define MATERIAL_TYPE " << (int)material_type << "\n";
748 shaders_header << "#define DRAW_TYPE " << (int)drawtype << "\n";
750 bool enable_waving_water = g_settings->getBool("enable_waving_water");
751 shaders_header << "#define ENABLE_WAVING_WATER " << enable_waving_water << "\n";
752 if (enable_waving_water) {
753 shaders_header << "#define WATER_WAVE_HEIGHT " << g_settings->getFloat("water_wave_height") << "\n";
754 shaders_header << "#define WATER_WAVE_LENGTH " << g_settings->getFloat("water_wave_length") << "\n";
755 shaders_header << "#define WATER_WAVE_SPEED " << g_settings->getFloat("water_wave_speed") << "\n";
758 shaders_header << "#define ENABLE_WAVING_LEAVES " << g_settings->getBool("enable_waving_leaves") << "\n";
759 shaders_header << "#define ENABLE_WAVING_PLANTS " << g_settings->getBool("enable_waving_plants") << "\n";
760 shaders_header << "#define ENABLE_TONE_MAPPING " << g_settings->getBool("tone_mapping") << "\n";
762 shaders_header << "#define FOG_START " << core::clamp(g_settings->getFloat("fog_start"), 0.0f, 0.99f) << "\n";
764 if (g_settings->getBool("enable_dynamic_shadows")) {
765 shaders_header << "#define ENABLE_DYNAMIC_SHADOWS 1\n";
766 if (g_settings->getBool("shadow_map_color"))
767 shaders_header << "#define COLORED_SHADOWS 1\n";
769 if (g_settings->getBool("shadow_poisson_filter"))
770 shaders_header << "#define POISSON_FILTER 1\n";
772 s32 shadow_filter = g_settings->getS32("shadow_filters");
773 shaders_header << "#define SHADOW_FILTER " << shadow_filter << "\n";
775 float shadow_soft_radius = g_settings->getFloat("shadow_soft_radius");
776 if (shadow_soft_radius < 1.0f)
777 shadow_soft_radius = 1.0f;
778 shaders_header << "#define SOFTSHADOWRADIUS " << shadow_soft_radius << "\n";
781 if (g_settings->getBool("enable_bloom")) {
782 shaders_header << "#define ENABLE_BLOOM 1\n";
783 if (g_settings->getBool("enable_bloom_debug"))
784 shaders_header << "#define ENABLE_BLOOM_DEBUG 1\n";
787 shaders_header << "#line 0\n"; // reset the line counter for meaningful diagnostics
789 std::string common_header = shaders_header.str();
791 std::string vertex_shader = m_sourcecache.getOrLoad(name, "opengl_vertex.glsl");
792 std::string fragment_shader = m_sourcecache.getOrLoad(name, "opengl_fragment.glsl");
793 std::string geometry_shader = m_sourcecache.getOrLoad(name, "opengl_geometry.glsl");
795 vertex_shader = common_header + vertex_header + vertex_shader;
796 fragment_shader = common_header + fragment_header + fragment_shader;
797 const char *geometry_shader_ptr = nullptr; // optional
798 if (!geometry_shader.empty()) {
799 geometry_shader = common_header + geometry_header + geometry_shader;
800 geometry_shader_ptr = geometry_shader.c_str();
803 irr_ptr<ShaderCallback> cb{new ShaderCallback(m_setter_factories)};
804 infostream<<"Compiling high level shaders for "<<name<<std::endl;
805 s32 shadermat = gpu->addHighLevelShaderMaterial(
806 vertex_shader.c_str(), nullptr, video::EVST_VS_1_1,
807 fragment_shader.c_str(), nullptr, video::EPST_PS_1_1,
808 geometry_shader_ptr, nullptr, video::EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLES, 0,
809 cb.get(), shaderinfo.base_material, 1);
810 if (shadermat == -1) {
811 errorstream<<"generate_shader(): "
812 "failed to generate \""<<name<<"\", "
813 "addHighLevelShaderMaterial failed."
815 dumpShaderProgram(warningstream, "Vertex", vertex_shader);
816 dumpShaderProgram(warningstream, "Fragment", fragment_shader);
817 dumpShaderProgram(warningstream, "Geometry", geometry_shader);
821 // Apply the newly created material type
822 shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
826 void dumpShaderProgram(std::ostream &output_stream,
827 const std::string &program_type, const std::string &program)
829 output_stream << program_type << " shader program:" << std::endl <<
830 "----------------------------------" << std::endl;
834 while ((pos = program.find('\n', prev)) != std::string::npos) {
835 output_stream << line++ << ": "<< program.substr(prev, pos - prev) <<
839 output_stream << line << ": " << program.substr(prev) << std::endl <<
840 "End of " << program_type << " shader program." << std::endl <<