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"
42 #ifdef _IRR_COMPILE_WITH_OGLES1_
45 #include <GLES2/gl2.h>
51 #define GL_SILENCE_DEPRECATION
52 #include <OpenGL/gl.h>
57 A cache from shader name to shader path
59 MutexedMap<std::string, std::string> g_shadername_to_path_cache;
62 Gets the path to a shader by first checking if the file
63 name_of_shader/filename
64 exists in shader_path and if not, using the data path.
66 If not found, returns "".
68 Utilizes a thread-safe cache.
70 std::string getShaderPath(const std::string &name_of_shader,
71 const std::string &filename)
73 std::string combined = name_of_shader + DIR_DELIM + filename;
78 bool incache = g_shadername_to_path_cache.get(combined, &fullpath);
83 Check from shader_path
85 std::string shader_path = g_settings->get("shader_path");
86 if (!shader_path.empty()) {
87 std::string testpath = shader_path + DIR_DELIM + combined;
88 if(fs::PathExists(testpath))
93 Check from default data directory
95 if (fullpath.empty()) {
96 std::string rel_path = std::string("client") + DIR_DELIM
97 + "shaders" + DIR_DELIM
98 + name_of_shader + DIR_DELIM
100 std::string testpath = porting::path_share + DIR_DELIM + rel_path;
101 if(fs::PathExists(testpath))
105 // Add to cache (also an empty result is cached)
106 g_shadername_to_path_cache.set(combined, fullpath);
113 SourceShaderCache: A cache used for storing source shaders.
116 class SourceShaderCache
119 void insert(const std::string &name_of_shader, const std::string &filename,
120 const std::string &program, bool prefer_local)
122 std::string combined = name_of_shader + DIR_DELIM + filename;
123 // Try to use local shader instead if asked to
125 std::string path = getShaderPath(name_of_shader, filename);
127 std::string p = readFile(path);
129 m_programs[combined] = p;
134 m_programs[combined] = program;
137 std::string get(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())
147 // Primarily fetches from cache, secondarily tries to read from filesystem
148 std::string getOrLoad(const std::string &name_of_shader,
149 const std::string &filename)
151 std::string combined = name_of_shader + DIR_DELIM + filename;
152 StringMap::iterator n = m_programs.find(combined);
153 if (n != m_programs.end())
155 std::string path = getShaderPath(name_of_shader, filename);
157 infostream << "SourceShaderCache::getOrLoad(): No path found for \""
158 << combined << "\"" << std::endl;
161 infostream << "SourceShaderCache::getOrLoad(): Loading path \""
162 << path << "\"" << std::endl;
163 std::string p = readFile(path);
165 m_programs[combined] = p;
171 StringMap m_programs;
173 std::string readFile(const std::string &path)
175 std::ifstream is(path.c_str(), std::ios::binary);
178 std::ostringstream tmp_os;
179 tmp_os << is.rdbuf();
186 ShaderCallback: Sets constants that can be used in shaders
189 class ShaderCallback : public video::IShaderConstantSetCallBack
191 std::vector<IShaderConstantSetter*> m_setters;
194 ShaderCallback(const std::vector<IShaderConstantSetterFactory *> &factories)
196 for (IShaderConstantSetterFactory *factory : factories)
197 m_setters.push_back(factory->create());
202 for (IShaderConstantSetter *setter : m_setters)
206 virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData) override
208 video::IVideoDriver *driver = services->getVideoDriver();
209 sanity_check(driver != NULL);
211 bool is_highlevel = userData;
213 for (IShaderConstantSetter *setter : m_setters)
214 setter->onSetConstants(services, is_highlevel);
217 virtual void OnSetMaterial(const video::SMaterial& material) override
219 for (IShaderConstantSetter *setter : m_setters)
220 setter->onSetMaterial(material);
226 MainShaderConstantSetter: Set basic constants required for almost everything
229 class MainShaderConstantSetter : public IShaderConstantSetter
231 CachedVertexShaderSetting<float, 16> m_world_view_proj;
232 CachedVertexShaderSetting<float, 16> m_world;
235 MainShaderConstantSetter() :
236 m_world_view_proj("mWorldViewProj"),
239 ~MainShaderConstantSetter() = default;
241 virtual void onSetConstants(video::IMaterialRendererServices *services,
244 video::IVideoDriver *driver = services->getVideoDriver();
245 sanity_check(driver);
248 core::matrix4 worldViewProj;
249 worldViewProj = driver->getTransform(video::ETS_PROJECTION);
250 worldViewProj *= driver->getTransform(video::ETS_VIEW);
251 worldViewProj *= driver->getTransform(video::ETS_WORLD);
253 m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
255 services->setVertexShaderConstant(worldViewProj.pointer(), 0, 4);
258 core::matrix4 world = driver->getTransform(video::ETS_WORLD);
260 m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
262 services->setVertexShaderConstant(world.pointer(), 4, 4);
268 class MainShaderConstantSetterFactory : public IShaderConstantSetterFactory
271 virtual IShaderConstantSetter* create()
272 { return new MainShaderConstantSetter(); }
280 class ShaderSource : public IWritableShaderSource
287 - If shader material specified by name is found from cache,
288 return the cached id.
289 - Otherwise generate the shader material, add to cache and return id.
291 The id 0 points to a null shader. Its material is EMT_SOLID.
293 u32 getShaderIdDirect(const std::string &name,
294 const u8 material_type, const u8 drawtype);
297 If shader specified by the name pointed by the id doesn't
298 exist, create it, then return id.
300 Can be called from any thread. If called from some other thread
301 and not found in cache, the call is queued to the main thread
305 u32 getShader(const std::string &name,
306 const u8 material_type, const u8 drawtype);
308 ShaderInfo getShaderInfo(u32 id);
310 // Processes queued shader requests from other threads.
311 // Shall be called from the main thread.
314 // Insert a shader program into the cache without touching the
315 // filesystem. Shall be called from the main thread.
316 void insertSourceShader(const std::string &name_of_shader,
317 const std::string &filename, const std::string &program);
319 // Rebuild shaders from the current set of source shaders
320 // Shall be called from the main thread.
321 void rebuildShaders();
323 void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter)
325 m_setter_factories.push_back(setter);
330 // The id of the thread that is allowed to use irrlicht directly
331 std::thread::id m_main_thread;
333 // Cache of source shaders
334 // This should be only accessed from the main thread
335 SourceShaderCache m_sourcecache;
337 // A shader id is index in this array.
338 // The first position contains a dummy shader.
339 std::vector<ShaderInfo> m_shaderinfo_cache;
340 // The former container is behind this mutex
341 std::mutex m_shaderinfo_cache_mutex;
343 // Queued shader fetches (to be processed by the main thread)
344 RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
346 // Global constant setter factories
347 std::vector<IShaderConstantSetterFactory *> m_setter_factories;
350 std::vector<ShaderCallback *> m_callbacks;
353 IWritableShaderSource *createShaderSource()
355 return new ShaderSource();
359 Generate shader given the shader name.
361 ShaderInfo generate_shader(const std::string &name,
362 u8 material_type, u8 drawtype, std::vector<ShaderCallback *> &callbacks,
363 const std::vector<IShaderConstantSetterFactory *> &setter_factories,
364 SourceShaderCache *sourcecache);
369 void load_shaders(const std::string &name, SourceShaderCache *sourcecache,
370 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
371 std::string &vertex_program, std::string &pixel_program,
372 std::string &geometry_program, bool &is_highlevel);
374 ShaderSource::ShaderSource()
376 m_main_thread = std::this_thread::get_id();
378 // Add a dummy ShaderInfo as the first index, named ""
379 m_shaderinfo_cache.emplace_back();
381 // Add main global constant setter
382 addShaderConstantSetterFactory(new MainShaderConstantSetterFactory());
385 ShaderSource::~ShaderSource()
387 for (ShaderCallback *callback : m_callbacks) {
390 for (IShaderConstantSetterFactory *setter_factorie : m_setter_factories) {
391 delete setter_factorie;
395 u32 ShaderSource::getShader(const std::string &name,
396 const u8 material_type, const u8 drawtype)
402 if (std::this_thread::get_id() == m_main_thread) {
403 return getShaderIdDirect(name, material_type, drawtype);
406 /*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/
408 // We're gonna ask the result to be put into here
410 static ResultQueue<std::string, u32, u8, u8> result_queue;
412 // Throw a request in
413 m_get_shader_queue.add(name, 0, 0, &result_queue);
415 /* infostream<<"Waiting for shader from main thread, name=\""
416 <<name<<"\""<<std::endl;*/
419 GetResult<std::string, u32, u8, u8>
420 result = result_queue.pop_frontNoEx();
422 if (result.key == name) {
426 errorstream << "Got shader with invalid name: " << result.key << std::endl;
429 infostream << "getShader(): Failed" << std::endl;
435 This method generates all the shaders
437 u32 ShaderSource::getShaderIdDirect(const std::string &name,
438 const u8 material_type, const u8 drawtype)
440 //infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
442 // Empty name means shader 0
444 infostream<<"getShaderIdDirect(): name is empty"<<std::endl;
448 // Check if already have such instance
449 for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
450 ShaderInfo *info = &m_shaderinfo_cache[i];
451 if(info->name == name && info->material_type == material_type &&
452 info->drawtype == drawtype)
457 Calling only allowed from main thread
459 if (std::this_thread::get_id() != m_main_thread) {
460 errorstream<<"ShaderSource::getShaderIdDirect() "
461 "called not from main thread"<<std::endl;
465 ShaderInfo info = generate_shader(name, material_type, drawtype,
466 m_callbacks, m_setter_factories, &m_sourcecache);
469 Add shader to caches (add dummy shaders too)
472 MutexAutoLock lock(m_shaderinfo_cache_mutex);
474 u32 id = m_shaderinfo_cache.size();
475 m_shaderinfo_cache.push_back(info);
477 infostream<<"getShaderIdDirect(): "
478 <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;
484 ShaderInfo ShaderSource::getShaderInfo(u32 id)
486 MutexAutoLock lock(m_shaderinfo_cache_mutex);
488 if(id >= m_shaderinfo_cache.size())
491 return m_shaderinfo_cache[id];
494 void ShaderSource::processQueue()
500 void ShaderSource::insertSourceShader(const std::string &name_of_shader,
501 const std::string &filename, const std::string &program)
503 /*infostream<<"ShaderSource::insertSourceShader(): "
504 "name_of_shader=\""<<name_of_shader<<"\", "
505 "filename=\""<<filename<<"\""<<std::endl;*/
507 sanity_check(std::this_thread::get_id() == m_main_thread);
509 m_sourcecache.insert(name_of_shader, filename, program, true);
512 void ShaderSource::rebuildShaders()
514 MutexAutoLock lock(m_shaderinfo_cache_mutex);
516 /*// Oh well... just clear everything, they'll load sometime.
517 m_shaderinfo_cache.clear();
518 m_name_to_id.clear();*/
521 FIXME: Old shader materials can't be deleted in Irrlicht,
523 (This would be nice to do in the destructor too)
527 for (ShaderInfo &i : m_shaderinfo_cache) {
528 ShaderInfo *info = &i;
529 if (!info->name.empty()) {
530 *info = generate_shader(info->name, info->material_type,
531 info->drawtype, m_callbacks,
532 m_setter_factories, &m_sourcecache);
538 ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtype,
539 std::vector<ShaderCallback *> &callbacks,
540 const std::vector<IShaderConstantSetterFactory *> &setter_factories,
541 SourceShaderCache *sourcecache)
543 ShaderInfo shaderinfo;
544 shaderinfo.name = name;
545 shaderinfo.material_type = material_type;
546 shaderinfo.drawtype = drawtype;
547 shaderinfo.material = video::EMT_SOLID;
548 switch (material_type) {
549 case TILE_MATERIAL_OPAQUE:
550 case TILE_MATERIAL_LIQUID_OPAQUE:
551 case TILE_MATERIAL_WAVING_LIQUID_OPAQUE:
552 shaderinfo.base_material = video::EMT_SOLID;
554 case TILE_MATERIAL_ALPHA:
555 case TILE_MATERIAL_PLAIN_ALPHA:
556 case TILE_MATERIAL_LIQUID_TRANSPARENT:
557 case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
558 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
560 case TILE_MATERIAL_BASIC:
561 case TILE_MATERIAL_PLAIN:
562 case TILE_MATERIAL_WAVING_LEAVES:
563 case TILE_MATERIAL_WAVING_PLANTS:
564 case TILE_MATERIAL_WAVING_LIQUID_BASIC:
565 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
569 bool enable_shaders = g_settings->getBool("enable_shaders");
573 video::IVideoDriver *driver = RenderingEngine::get_video_driver();
575 video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
577 errorstream<<"generate_shader(): "
578 "failed to generate \""<<name<<"\", "
579 "GPU programming not supported."
584 // Choose shader language depending on driver type and settings
586 std::string vertex_program;
587 std::string pixel_program;
588 std::string geometry_program;
590 load_shaders(name, sourcecache, driver->getDriverType(),
591 enable_shaders, vertex_program, pixel_program,
592 geometry_program, is_highlevel);
593 // Check hardware/driver support
594 if (!vertex_program.empty() &&
595 !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
596 !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
597 infostream<<"generate_shader(): vertex shaders disabled "
598 "because of missing driver/hardware support."
602 if (!pixel_program.empty() &&
603 !driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
604 !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
605 infostream<<"generate_shader(): pixel shaders disabled "
606 "because of missing driver/hardware support."
610 if (!geometry_program.empty() &&
611 !driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
612 infostream<<"generate_shader(): geometry shaders disabled "
613 "because of missing driver/hardware support."
615 geometry_program = "";
618 // If no shaders are used, don't make a separate material type
619 if (vertex_program.empty() && pixel_program.empty() && geometry_program.empty())
622 // Create shaders header
623 std::string shaders_header = "#version 120\n";
626 // For renderers that should use discard instead of GL_ALPHA_TEST
627 const char* gl_renderer = (const char*)glGetString(GL_RENDERER);
628 if (strstr(gl_renderer, "GC7000")) {
629 shaders_header += "#define USE_DISCARD\n";
633 static const char* drawTypes[] = {
640 "NDT_ALLFACES_OPTIONAL",
647 "NDT_GLASSLIKE_FRAMED",
649 "NDT_GLASSLIKE_FRAMED_OPTIONAL",
650 "NDT_PLANTLIKE_ROOTED",
653 for (int i = 0; i < 14; i++){
654 shaders_header += "#define ";
655 shaders_header += drawTypes[i];
656 shaders_header += " ";
657 shaders_header += itos(i);
658 shaders_header += "\n";
661 static const char* materialTypes[] = {
662 "TILE_MATERIAL_BASIC",
663 "TILE_MATERIAL_ALPHA",
664 "TILE_MATERIAL_LIQUID_TRANSPARENT",
665 "TILE_MATERIAL_LIQUID_OPAQUE",
666 "TILE_MATERIAL_WAVING_LEAVES",
667 "TILE_MATERIAL_WAVING_PLANTS",
668 "TILE_MATERIAL_OPAQUE",
669 "TILE_MATERIAL_WAVING_LIQUID_BASIC",
670 "TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT",
671 "TILE_MATERIAL_WAVING_LIQUID_OPAQUE",
672 "TILE_MATERIAL_PLAIN",
673 "TILE_MATERIAL_PLAIN_ALPHA",
676 for (int i = 0; i < 12; i++){
677 shaders_header += "#define ";
678 shaders_header += materialTypes[i];
679 shaders_header += " ";
680 shaders_header += itos(i);
681 shaders_header += "\n";
684 shaders_header += "#define MATERIAL_TYPE ";
685 shaders_header += itos(material_type);
686 shaders_header += "\n";
687 shaders_header += "#define DRAW_TYPE ";
688 shaders_header += itos(drawtype);
689 shaders_header += "\n";
691 if (g_settings->getBool("generate_normalmaps")) {
692 shaders_header += "#define GENERATE_NORMALMAPS 1\n";
694 shaders_header += "#define GENERATE_NORMALMAPS 0\n";
696 shaders_header += "#define NORMALMAPS_STRENGTH ";
697 shaders_header += ftos(g_settings->getFloat("normalmaps_strength"));
698 shaders_header += "\n";
700 int smooth = (int)g_settings->getFloat("normalmaps_smooth");
703 sample_step = 0.0078125; // 1.0 / 128.0
706 sample_step = 0.00390625; // 1.0 / 256.0
709 sample_step = 0.001953125; // 1.0 / 512.0
712 sample_step = 0.0078125;
715 shaders_header += "#define SAMPLE_STEP ";
716 shaders_header += ftos(sample_step);
717 shaders_header += "\n";
719 if (g_settings->getBool("enable_bumpmapping"))
720 shaders_header += "#define ENABLE_BUMPMAPPING\n";
722 if (g_settings->getBool("enable_parallax_occlusion")){
723 int mode = g_settings->getFloat("parallax_occlusion_mode");
724 float scale = g_settings->getFloat("parallax_occlusion_scale");
725 float bias = g_settings->getFloat("parallax_occlusion_bias");
726 int iterations = g_settings->getFloat("parallax_occlusion_iterations");
727 shaders_header += "#define ENABLE_PARALLAX_OCCLUSION\n";
728 shaders_header += "#define PARALLAX_OCCLUSION_MODE ";
729 shaders_header += itos(mode);
730 shaders_header += "\n";
731 shaders_header += "#define PARALLAX_OCCLUSION_SCALE ";
732 shaders_header += ftos(scale);
733 shaders_header += "\n";
734 shaders_header += "#define PARALLAX_OCCLUSION_BIAS ";
735 shaders_header += ftos(bias);
736 shaders_header += "\n";
737 shaders_header += "#define PARALLAX_OCCLUSION_ITERATIONS ";
738 shaders_header += itos(iterations);
739 shaders_header += "\n";
742 shaders_header += "#define USE_NORMALMAPS ";
743 if (g_settings->getBool("enable_bumpmapping") || g_settings->getBool("enable_parallax_occlusion"))
744 shaders_header += "1\n";
746 shaders_header += "0\n";
748 if (g_settings->getBool("enable_waving_water")){
749 shaders_header += "#define ENABLE_WAVING_WATER 1\n";
750 shaders_header += "#define WATER_WAVE_HEIGHT ";
751 shaders_header += ftos(g_settings->getFloat("water_wave_height"));
752 shaders_header += "\n";
753 shaders_header += "#define WATER_WAVE_LENGTH ";
754 shaders_header += ftos(g_settings->getFloat("water_wave_length"));
755 shaders_header += "\n";
756 shaders_header += "#define WATER_WAVE_SPEED ";
757 shaders_header += ftos(g_settings->getFloat("water_wave_speed"));
758 shaders_header += "\n";
760 shaders_header += "#define ENABLE_WAVING_WATER 0\n";
763 shaders_header += "#define ENABLE_WAVING_LEAVES ";
764 if (g_settings->getBool("enable_waving_leaves"))
765 shaders_header += "1\n";
767 shaders_header += "0\n";
769 shaders_header += "#define ENABLE_WAVING_PLANTS ";
770 if (g_settings->getBool("enable_waving_plants"))
771 shaders_header += "1\n";
773 shaders_header += "0\n";
775 if (g_settings->getBool("tone_mapping"))
776 shaders_header += "#define ENABLE_TONE_MAPPING\n";
778 shaders_header += "#define FOG_START ";
779 shaders_header += ftos(rangelim(g_settings->getFloat("fog_start"), 0.0f, 0.99f));
780 shaders_header += "\n";
782 // Call addHighLevelShaderMaterial() or addShaderMaterial()
783 const c8* vertex_program_ptr = 0;
784 const c8* pixel_program_ptr = 0;
785 const c8* geometry_program_ptr = 0;
786 if (!vertex_program.empty()) {
787 vertex_program = shaders_header + vertex_program;
788 vertex_program_ptr = vertex_program.c_str();
790 if (!pixel_program.empty()) {
791 pixel_program = shaders_header + pixel_program;
792 pixel_program_ptr = pixel_program.c_str();
794 if (!geometry_program.empty()) {
795 geometry_program = shaders_header + geometry_program;
796 geometry_program_ptr = geometry_program.c_str();
798 ShaderCallback *cb = new ShaderCallback(setter_factories);
801 infostream<<"Compiling high level shaders for "<<name<<std::endl;
802 shadermat = gpu->addHighLevelShaderMaterial(
803 vertex_program_ptr, // Vertex shader program
804 "vertexMain", // Vertex shader entry point
805 video::EVST_VS_1_1, // Vertex shader version
806 pixel_program_ptr, // Pixel shader program
807 "pixelMain", // Pixel shader entry point
808 video::EPST_PS_1_2, // Pixel shader version
809 geometry_program_ptr, // Geometry shader program
810 "geometryMain", // Geometry shader entry point
811 video::EGST_GS_4_0, // Geometry shader version
812 scene::EPT_TRIANGLES, // Geometry shader input
813 scene::EPT_TRIANGLE_STRIP, // Geometry shader output
814 0, // Support maximum number of vertices
815 cb, // Set-constant callback
816 shaderinfo.base_material, // Base material
817 1 // Userdata passed to callback
820 errorstream<<"generate_shader(): "
821 "failed to generate \""<<name<<"\", "
822 "addHighLevelShaderMaterial failed."
824 dumpShaderProgram(warningstream, "Vertex", vertex_program);
825 dumpShaderProgram(warningstream, "Pixel", pixel_program);
826 dumpShaderProgram(warningstream, "Geometry", geometry_program);
832 infostream<<"Compiling assembly shaders for "<<name<<std::endl;
833 shadermat = gpu->addShaderMaterial(
834 vertex_program_ptr, // Vertex shader program
835 pixel_program_ptr, // Pixel shader program
836 cb, // Set-constant callback
837 shaderinfo.base_material, // Base material
838 0 // Userdata passed to callback
842 errorstream<<"generate_shader(): "
843 "failed to generate \""<<name<<"\", "
844 "addShaderMaterial failed."
846 dumpShaderProgram(warningstream, "Vertex", vertex_program);
847 dumpShaderProgram(warningstream,"Pixel", pixel_program);
852 callbacks.push_back(cb);
854 // HACK, TODO: investigate this better
855 // Grab the material renderer once more so minetest doesn't crash on exit
856 driver->getMaterialRenderer(shadermat)->grab();
858 // Apply the newly created material type
859 shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
863 void load_shaders(const std::string &name, SourceShaderCache *sourcecache,
864 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
865 std::string &vertex_program, std::string &pixel_program,
866 std::string &geometry_program, bool &is_highlevel)
870 geometry_program = "";
871 is_highlevel = false;
874 // Look for high level shaders
875 if(drivertype == video::EDT_DIRECT3D9){
877 // (All shaders in one file)
878 vertex_program = sourcecache->getOrLoad(name, "d3d9.hlsl");
879 pixel_program = vertex_program;
880 geometry_program = vertex_program;
882 else if(drivertype == video::EDT_OPENGL){
884 vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.glsl");
885 pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.glsl");
886 geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl");
888 if (!vertex_program.empty() || !pixel_program.empty() || !geometry_program.empty()){
896 void dumpShaderProgram(std::ostream &output_stream,
897 const std::string &program_type, const std::string &program)
899 output_stream << program_type << " shader program:" << std::endl <<
900 "----------------------------------" << std::endl;
904 while ((pos = program.find('\n', prev)) != std::string::npos) {
905 output_stream << line++ << ": "<< program.substr(prev, pos - prev) <<
909 output_stream << line << ": " << program.substr(prev) << std::endl <<
910 "End of " << program_type << " shader program." << std::endl <<