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"
27 #include "util/container.h"
28 #include "util/thread.h"
30 #include <ICameraSceneNode.h>
31 #include <IGPUProgrammingServices.h>
32 #include <IMaterialRenderer.h>
33 #include <IMaterialRendererServices.h>
34 #include <IShaderConstantSetCallBack.h>
35 #include "client/renderingengine.h"
36 #include "EShaderTypes.h"
39 #include "client/tile.h"
43 #ifdef _IRR_COMPILE_WITH_OGLES1_
46 #include <GLES2/gl2.h>
52 #define GL_SILENCE_DEPRECATION
53 #include <OpenGL/gl.h>
58 A cache from shader name to shader path
60 MutexedMap<std::string, std::string> g_shadername_to_path_cache;
63 Gets the path to a shader by first checking if the file
64 name_of_shader/filename
65 exists in shader_path and if not, using the data path.
67 If not found, returns "".
69 Utilizes a thread-safe cache.
71 std::string getShaderPath(const std::string &name_of_shader,
72 const std::string &filename)
74 std::string combined = name_of_shader + DIR_DELIM + filename;
79 bool incache = g_shadername_to_path_cache.get(combined, &fullpath);
84 Check from shader_path
86 std::string shader_path = g_settings->get("shader_path");
87 if (!shader_path.empty()) {
88 std::string testpath = shader_path + DIR_DELIM + combined;
89 if(fs::PathExists(testpath))
94 Check from default data directory
96 if (fullpath.empty()) {
97 std::string rel_path = std::string("client") + DIR_DELIM
98 + "shaders" + DIR_DELIM
99 + name_of_shader + DIR_DELIM
101 std::string testpath = porting::path_share + DIR_DELIM + rel_path;
102 if(fs::PathExists(testpath))
106 // Add to cache (also an empty result is cached)
107 g_shadername_to_path_cache.set(combined, fullpath);
114 SourceShaderCache: A cache used for storing source shaders.
117 class SourceShaderCache
120 void insert(const std::string &name_of_shader, const std::string &filename,
121 const std::string &program, bool prefer_local)
123 std::string combined = name_of_shader + DIR_DELIM + filename;
124 // Try to use local shader instead if asked to
126 std::string path = getShaderPath(name_of_shader, filename);
128 std::string p = readFile(path);
130 m_programs[combined] = p;
135 m_programs[combined] = program;
138 std::string get(const std::string &name_of_shader,
139 const std::string &filename)
141 std::string combined = name_of_shader + DIR_DELIM + filename;
142 StringMap::iterator n = m_programs.find(combined);
143 if (n != m_programs.end())
148 // Primarily fetches from cache, secondarily tries to read from filesystem
149 std::string getOrLoad(const std::string &name_of_shader,
150 const std::string &filename)
152 std::string combined = name_of_shader + DIR_DELIM + filename;
153 StringMap::iterator n = m_programs.find(combined);
154 if (n != m_programs.end())
156 std::string path = getShaderPath(name_of_shader, filename);
158 infostream << "SourceShaderCache::getOrLoad(): No path found for \""
159 << combined << "\"" << std::endl;
162 infostream << "SourceShaderCache::getOrLoad(): Loading path \""
163 << path << "\"" << std::endl;
164 std::string p = readFile(path);
166 m_programs[combined] = p;
172 StringMap m_programs;
174 std::string readFile(const std::string &path)
176 std::ifstream is(path.c_str(), std::ios::binary);
179 std::ostringstream tmp_os;
180 tmp_os << is.rdbuf();
187 ShaderCallback: Sets constants that can be used in shaders
190 class ShaderCallback : public video::IShaderConstantSetCallBack
192 std::vector<IShaderConstantSetter*> m_setters;
195 ShaderCallback(const std::vector<IShaderConstantSetterFactory *> &factories)
197 for (IShaderConstantSetterFactory *factory : factories)
198 m_setters.push_back(factory->create());
203 for (IShaderConstantSetter *setter : m_setters)
207 virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData) override
209 video::IVideoDriver *driver = services->getVideoDriver();
210 sanity_check(driver != NULL);
212 bool is_highlevel = userData;
214 for (IShaderConstantSetter *setter : m_setters)
215 setter->onSetConstants(services, is_highlevel);
218 virtual void OnSetMaterial(const video::SMaterial& material) override
220 for (IShaderConstantSetter *setter : m_setters)
221 setter->onSetMaterial(material);
227 MainShaderConstantSetter: Set basic constants required for almost everything
230 class MainShaderConstantSetter : public IShaderConstantSetter
232 CachedVertexShaderSetting<float, 16> m_world_view_proj;
233 CachedVertexShaderSetting<float, 16> m_world;
236 CachedVertexShaderSetting<float, 16> m_world_view;
238 CachedVertexShaderSetting<float, 16> m_texture;
240 CachedVertexShaderSetting<float, 9> m_normal;
244 MainShaderConstantSetter() :
245 m_world_view_proj("mWorldViewProj")
248 , m_world_view("mWorldView")
249 , m_texture("mTexture")
250 , m_normal("mNormal")
253 ~MainShaderConstantSetter() = default;
255 virtual void onSetConstants(video::IMaterialRendererServices *services,
258 video::IVideoDriver *driver = services->getVideoDriver();
259 sanity_check(driver);
262 core::matrix4 world = driver->getTransform(video::ETS_WORLD);
264 m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
266 services->setVertexShaderConstant(world.pointer(), 4, 4);
269 core::matrix4 worldView;
270 worldView = driver->getTransform(video::ETS_VIEW);
272 core::matrix4 worldViewProj;
273 worldViewProj = driver->getTransform(video::ETS_PROJECTION);
274 worldViewProj *= worldView;
276 m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
278 services->setVertexShaderConstant(worldViewProj.pointer(), 0, 4);
282 core::matrix4 texture = driver->getTransform(video::ETS_TEXTURE_0);
283 m_world_view.set(*reinterpret_cast<float(*)[16]>(worldView.pointer()), services);
284 m_texture.set(*reinterpret_cast<float(*)[16]>(texture.pointer()), services);
286 core::matrix4 normal;
287 worldView.getTransposed(normal);
288 sanity_check(normal.makeInverse());
290 normal[0], normal[1], normal[2],
291 normal[4], normal[5], normal[6],
292 normal[8], normal[9], normal[10],
294 m_normal.set(m, services);
301 class MainShaderConstantSetterFactory : public IShaderConstantSetterFactory
304 virtual IShaderConstantSetter* create()
305 { return new MainShaderConstantSetter(); }
313 class ShaderSource : public IWritableShaderSource
320 - If shader material specified by name is found from cache,
321 return the cached id.
322 - Otherwise generate the shader material, add to cache and return id.
324 The id 0 points to a null shader. Its material is EMT_SOLID.
326 u32 getShaderIdDirect(const std::string &name,
327 const u8 material_type, const u8 drawtype);
330 If shader specified by the name pointed by the id doesn't
331 exist, create it, then return id.
333 Can be called from any thread. If called from some other thread
334 and not found in cache, the call is queued to the main thread
338 u32 getShader(const std::string &name,
339 const u8 material_type, const u8 drawtype);
341 ShaderInfo getShaderInfo(u32 id);
343 // Processes queued shader requests from other threads.
344 // Shall be called from the main thread.
347 // Insert a shader program into the cache without touching the
348 // filesystem. Shall be called from the main thread.
349 void insertSourceShader(const std::string &name_of_shader,
350 const std::string &filename, const std::string &program);
352 // Rebuild shaders from the current set of source shaders
353 // Shall be called from the main thread.
354 void rebuildShaders();
356 void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter)
358 m_setter_factories.push_back(setter);
363 // The id of the thread that is allowed to use irrlicht directly
364 std::thread::id m_main_thread;
366 // Cache of source shaders
367 // This should be only accessed from the main thread
368 SourceShaderCache m_sourcecache;
370 // A shader id is index in this array.
371 // The first position contains a dummy shader.
372 std::vector<ShaderInfo> m_shaderinfo_cache;
373 // The former container is behind this mutex
374 std::mutex m_shaderinfo_cache_mutex;
376 // Queued shader fetches (to be processed by the main thread)
377 RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
379 // Global constant setter factories
380 std::vector<IShaderConstantSetterFactory *> m_setter_factories;
383 std::vector<ShaderCallback *> m_callbacks;
386 IWritableShaderSource *createShaderSource()
388 return new ShaderSource();
392 Generate shader given the shader name.
394 ShaderInfo generate_shader(const std::string &name,
395 u8 material_type, u8 drawtype, std::vector<ShaderCallback *> &callbacks,
396 const std::vector<IShaderConstantSetterFactory *> &setter_factories,
397 SourceShaderCache *sourcecache);
402 void load_shaders(const std::string &name, SourceShaderCache *sourcecache,
403 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
404 std::string &vertex_program, std::string &pixel_program,
405 std::string &geometry_program, bool &is_highlevel);
407 ShaderSource::ShaderSource()
409 m_main_thread = std::this_thread::get_id();
411 // Add a dummy ShaderInfo as the first index, named ""
412 m_shaderinfo_cache.emplace_back();
414 // Add main global constant setter
415 addShaderConstantSetterFactory(new MainShaderConstantSetterFactory());
418 ShaderSource::~ShaderSource()
420 for (ShaderCallback *callback : m_callbacks) {
423 for (IShaderConstantSetterFactory *setter_factorie : m_setter_factories) {
424 delete setter_factorie;
428 u32 ShaderSource::getShader(const std::string &name,
429 const u8 material_type, const u8 drawtype)
435 if (std::this_thread::get_id() == m_main_thread) {
436 return getShaderIdDirect(name, material_type, drawtype);
439 /*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/
441 // We're gonna ask the result to be put into here
443 static ResultQueue<std::string, u32, u8, u8> result_queue;
445 // Throw a request in
446 m_get_shader_queue.add(name, 0, 0, &result_queue);
448 /* infostream<<"Waiting for shader from main thread, name=\""
449 <<name<<"\""<<std::endl;*/
452 GetResult<std::string, u32, u8, u8>
453 result = result_queue.pop_frontNoEx();
455 if (result.key == name) {
459 errorstream << "Got shader with invalid name: " << result.key << std::endl;
462 infostream << "getShader(): Failed" << std::endl;
468 This method generates all the shaders
470 u32 ShaderSource::getShaderIdDirect(const std::string &name,
471 const u8 material_type, const u8 drawtype)
473 //infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
475 // Empty name means shader 0
477 infostream<<"getShaderIdDirect(): name is empty"<<std::endl;
481 // Check if already have such instance
482 for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
483 ShaderInfo *info = &m_shaderinfo_cache[i];
484 if(info->name == name && info->material_type == material_type &&
485 info->drawtype == drawtype)
490 Calling only allowed from main thread
492 if (std::this_thread::get_id() != m_main_thread) {
493 errorstream<<"ShaderSource::getShaderIdDirect() "
494 "called not from main thread"<<std::endl;
498 ShaderInfo info = generate_shader(name, material_type, drawtype,
499 m_callbacks, m_setter_factories, &m_sourcecache);
502 Add shader to caches (add dummy shaders too)
505 MutexAutoLock lock(m_shaderinfo_cache_mutex);
507 u32 id = m_shaderinfo_cache.size();
508 m_shaderinfo_cache.push_back(info);
510 infostream<<"getShaderIdDirect(): "
511 <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;
517 ShaderInfo ShaderSource::getShaderInfo(u32 id)
519 MutexAutoLock lock(m_shaderinfo_cache_mutex);
521 if(id >= m_shaderinfo_cache.size())
524 return m_shaderinfo_cache[id];
527 void ShaderSource::processQueue()
533 void ShaderSource::insertSourceShader(const std::string &name_of_shader,
534 const std::string &filename, const std::string &program)
536 /*infostream<<"ShaderSource::insertSourceShader(): "
537 "name_of_shader=\""<<name_of_shader<<"\", "
538 "filename=\""<<filename<<"\""<<std::endl;*/
540 sanity_check(std::this_thread::get_id() == m_main_thread);
542 m_sourcecache.insert(name_of_shader, filename, program, true);
545 void ShaderSource::rebuildShaders()
547 MutexAutoLock lock(m_shaderinfo_cache_mutex);
549 /*// Oh well... just clear everything, they'll load sometime.
550 m_shaderinfo_cache.clear();
551 m_name_to_id.clear();*/
554 FIXME: Old shader materials can't be deleted in Irrlicht,
556 (This would be nice to do in the destructor too)
560 for (ShaderInfo &i : m_shaderinfo_cache) {
561 ShaderInfo *info = &i;
562 if (!info->name.empty()) {
563 *info = generate_shader(info->name, info->material_type,
564 info->drawtype, m_callbacks,
565 m_setter_factories, &m_sourcecache);
571 ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtype,
572 std::vector<ShaderCallback *> &callbacks,
573 const std::vector<IShaderConstantSetterFactory *> &setter_factories,
574 SourceShaderCache *sourcecache)
576 ShaderInfo shaderinfo;
577 shaderinfo.name = name;
578 shaderinfo.material_type = material_type;
579 shaderinfo.drawtype = drawtype;
580 shaderinfo.material = video::EMT_SOLID;
581 switch (material_type) {
582 case TILE_MATERIAL_OPAQUE:
583 case TILE_MATERIAL_LIQUID_OPAQUE:
584 case TILE_MATERIAL_WAVING_LIQUID_OPAQUE:
585 shaderinfo.base_material = video::EMT_SOLID;
587 case TILE_MATERIAL_ALPHA:
588 case TILE_MATERIAL_PLAIN_ALPHA:
589 case TILE_MATERIAL_LIQUID_TRANSPARENT:
590 case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
591 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
593 case TILE_MATERIAL_BASIC:
594 case TILE_MATERIAL_PLAIN:
595 case TILE_MATERIAL_WAVING_LEAVES:
596 case TILE_MATERIAL_WAVING_PLANTS:
597 case TILE_MATERIAL_WAVING_LIQUID_BASIC:
598 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
602 bool enable_shaders = g_settings->getBool("enable_shaders");
606 video::IVideoDriver *driver = RenderingEngine::get_video_driver();
608 video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
610 errorstream<<"generate_shader(): "
611 "failed to generate \""<<name<<"\", "
612 "GPU programming not supported."
617 // Choose shader language depending on driver type and settings
619 std::string vertex_program;
620 std::string pixel_program;
621 std::string geometry_program;
623 load_shaders(name, sourcecache, driver->getDriverType(),
624 enable_shaders, vertex_program, pixel_program,
625 geometry_program, is_highlevel);
626 // Check hardware/driver support
627 if (!vertex_program.empty() &&
628 !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
629 !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
630 infostream<<"generate_shader(): vertex shaders disabled "
631 "because of missing driver/hardware support."
635 if (!pixel_program.empty() &&
636 !driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
637 !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
638 infostream<<"generate_shader(): pixel shaders disabled "
639 "because of missing driver/hardware support."
643 if (!geometry_program.empty() &&
644 !driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
645 infostream<<"generate_shader(): geometry shaders disabled "
646 "because of missing driver/hardware support."
648 geometry_program = "";
651 // If no shaders are used, don't make a separate material type
652 if (vertex_program.empty() && pixel_program.empty() && geometry_program.empty())
655 // Create shaders header
656 bool use_gles = false;
658 use_gles = driver->getDriverType() == video::EDT_OGLES2;
660 std::string shaders_header, vertex_header, pixel_header; // geometry shaders aren’t supported in GLES<3
666 uniform highp mat4 mWorldView;
667 uniform highp mat4 mWorldViewProj;
668 uniform mediump mat4 mTexture;
669 uniform mediump mat3 mNormal;
671 attribute highp vec4 inVertexPosition;
672 attribute lowp vec4 inVertexColor;
673 attribute mediump vec4 inTexCoord0;
674 attribute mediump vec3 inVertexNormal;
675 attribute mediump vec4 inVertexTangent;
676 attribute mediump vec4 inVertexBinormal;
679 precision mediump float;
689 #define mWorldView gl_ModelViewMatrix
690 #define mWorldViewProj gl_ModelViewProjectionMatrix
691 #define mTexture (gl_TextureMatrix[0])
692 #define mNormal gl_NormalMatrix
694 #define inVertexPosition gl_Vertex
695 #define inVertexColor gl_Color
696 #define inTexCoord0 gl_MultiTexCoord0
697 #define inVertexNormal gl_Normal
698 #define inVertexTangent gl_MultiTexCoord1
699 #define inVertexBinormal gl_MultiTexCoord2
703 bool use_discard = use_gles;
705 // For renderers that should use discard instead of GL_ALPHA_TEST
706 const char* gl_renderer = (const char*)glGetString(GL_RENDERER);
707 if (strstr(gl_renderer, "GC7000"))
710 if (use_discard && shaderinfo.base_material != video::EMT_SOLID)
711 shaders_header += "#define USE_DISCARD\n";
713 static const char* drawTypes[] = {
720 "NDT_ALLFACES_OPTIONAL",
727 "NDT_GLASSLIKE_FRAMED",
729 "NDT_GLASSLIKE_FRAMED_OPTIONAL",
730 "NDT_PLANTLIKE_ROOTED",
733 for (int i = 0; i < 14; i++){
734 shaders_header += "#define ";
735 shaders_header += drawTypes[i];
736 shaders_header += " ";
737 shaders_header += itos(i);
738 shaders_header += "\n";
741 static const char* materialTypes[] = {
742 "TILE_MATERIAL_BASIC",
743 "TILE_MATERIAL_ALPHA",
744 "TILE_MATERIAL_LIQUID_TRANSPARENT",
745 "TILE_MATERIAL_LIQUID_OPAQUE",
746 "TILE_MATERIAL_WAVING_LEAVES",
747 "TILE_MATERIAL_WAVING_PLANTS",
748 "TILE_MATERIAL_OPAQUE",
749 "TILE_MATERIAL_WAVING_LIQUID_BASIC",
750 "TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT",
751 "TILE_MATERIAL_WAVING_LIQUID_OPAQUE",
752 "TILE_MATERIAL_PLAIN",
753 "TILE_MATERIAL_PLAIN_ALPHA",
756 for (int i = 0; i < 12; i++){
757 shaders_header += "#define ";
758 shaders_header += materialTypes[i];
759 shaders_header += " ";
760 shaders_header += itos(i);
761 shaders_header += "\n";
764 shaders_header += "#define MATERIAL_TYPE ";
765 shaders_header += itos(material_type);
766 shaders_header += "\n";
767 shaders_header += "#define DRAW_TYPE ";
768 shaders_header += itos(drawtype);
769 shaders_header += "\n";
771 if (g_settings->getBool("enable_waving_water")){
772 shaders_header += "#define ENABLE_WAVING_WATER 1\n";
773 shaders_header += "#define WATER_WAVE_HEIGHT ";
774 shaders_header += std::to_string(g_settings->getFloat("water_wave_height"));
775 shaders_header += "\n";
776 shaders_header += "#define WATER_WAVE_LENGTH ";
777 shaders_header += std::to_string(g_settings->getFloat("water_wave_length"));
778 shaders_header += "\n";
779 shaders_header += "#define WATER_WAVE_SPEED ";
780 shaders_header += std::to_string(g_settings->getFloat("water_wave_speed"));
781 shaders_header += "\n";
783 shaders_header += "#define ENABLE_WAVING_WATER 0\n";
786 shaders_header += "#define ENABLE_WAVING_LEAVES ";
787 if (g_settings->getBool("enable_waving_leaves"))
788 shaders_header += "1\n";
790 shaders_header += "0\n";
792 shaders_header += "#define ENABLE_WAVING_PLANTS ";
793 if (g_settings->getBool("enable_waving_plants"))
794 shaders_header += "1\n";
796 shaders_header += "0\n";
798 if (g_settings->getBool("tone_mapping"))
799 shaders_header += "#define ENABLE_TONE_MAPPING\n";
801 shaders_header += "#define FOG_START ";
802 shaders_header += std::to_string(rangelim(g_settings->getFloat("fog_start"), 0.0f, 0.99f));
803 shaders_header += "\n";
805 // Call addHighLevelShaderMaterial() or addShaderMaterial()
806 const c8* vertex_program_ptr = 0;
807 const c8* pixel_program_ptr = 0;
808 const c8* geometry_program_ptr = 0;
809 if (!vertex_program.empty()) {
810 vertex_program = shaders_header + vertex_header + vertex_program;
811 vertex_program_ptr = vertex_program.c_str();
813 if (!pixel_program.empty()) {
814 pixel_program = shaders_header + pixel_header + pixel_program;
815 pixel_program_ptr = pixel_program.c_str();
817 if (!geometry_program.empty()) {
818 geometry_program = shaders_header + geometry_program;
819 geometry_program_ptr = geometry_program.c_str();
821 ShaderCallback *cb = new ShaderCallback(setter_factories);
824 infostream<<"Compiling high level shaders for "<<name<<std::endl;
825 shadermat = gpu->addHighLevelShaderMaterial(
826 vertex_program_ptr, // Vertex shader program
827 "vertexMain", // Vertex shader entry point
828 video::EVST_VS_1_1, // Vertex shader version
829 pixel_program_ptr, // Pixel shader program
830 "pixelMain", // Pixel shader entry point
831 video::EPST_PS_1_2, // Pixel shader version
832 geometry_program_ptr, // Geometry shader program
833 "geometryMain", // Geometry shader entry point
834 video::EGST_GS_4_0, // Geometry shader version
835 scene::EPT_TRIANGLES, // Geometry shader input
836 scene::EPT_TRIANGLE_STRIP, // Geometry shader output
837 0, // Support maximum number of vertices
838 cb, // Set-constant callback
839 shaderinfo.base_material, // Base material
840 1 // Userdata passed to callback
843 errorstream<<"generate_shader(): "
844 "failed to generate \""<<name<<"\", "
845 "addHighLevelShaderMaterial failed."
847 dumpShaderProgram(warningstream, "Vertex", vertex_program);
848 dumpShaderProgram(warningstream, "Pixel", pixel_program);
849 dumpShaderProgram(warningstream, "Geometry", geometry_program);
855 infostream<<"Compiling assembly shaders for "<<name<<std::endl;
856 shadermat = gpu->addShaderMaterial(
857 vertex_program_ptr, // Vertex shader program
858 pixel_program_ptr, // Pixel shader program
859 cb, // Set-constant callback
860 shaderinfo.base_material, // Base material
861 0 // Userdata passed to callback
865 errorstream<<"generate_shader(): "
866 "failed to generate \""<<name<<"\", "
867 "addShaderMaterial failed."
869 dumpShaderProgram(warningstream, "Vertex", vertex_program);
870 dumpShaderProgram(warningstream,"Pixel", pixel_program);
875 callbacks.push_back(cb);
877 // HACK, TODO: investigate this better
878 // Grab the material renderer once more so minetest doesn't crash on exit
879 driver->getMaterialRenderer(shadermat)->grab();
881 // Apply the newly created material type
882 shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
886 void load_shaders(const std::string &name, SourceShaderCache *sourcecache,
887 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
888 std::string &vertex_program, std::string &pixel_program,
889 std::string &geometry_program, bool &is_highlevel)
893 geometry_program = "";
894 is_highlevel = false;
899 // Look for high level shaders
900 switch (drivertype) {
901 case video::EDT_DIRECT3D9:
903 // (All shaders in one file)
904 vertex_program = sourcecache->getOrLoad(name, "d3d9.hlsl");
905 pixel_program = vertex_program;
906 geometry_program = vertex_program;
909 case video::EDT_OPENGL:
911 case video::EDT_OGLES2:
914 vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.glsl");
915 pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.glsl");
916 geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl");
920 // e.g. OpenGL ES 1 (with no shader support)
923 if (!vertex_program.empty() || !pixel_program.empty() || !geometry_program.empty()){
929 void dumpShaderProgram(std::ostream &output_stream,
930 const std::string &program_type, const std::string &program)
932 output_stream << program_type << " shader program:" << std::endl <<
933 "----------------------------------" << std::endl;
937 while ((pos = program.find('\n', prev)) != std::string::npos) {
938 output_stream << line++ << ": "<< program.substr(prev, pos - prev) <<
942 output_stream << line << ": " << program.substr(prev) << std::endl <<
943 "End of " << program_type << " shader program." << std::endl <<