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>
52 A cache from shader name to shader path
54 MutexedMap<std::string, std::string> g_shadername_to_path_cache;
57 Gets the path to a shader by first checking if the file
58 name_of_shader/filename
59 exists in shader_path and if not, using the data path.
61 If not found, returns "".
63 Utilizes a thread-safe cache.
65 std::string getShaderPath(const std::string &name_of_shader,
66 const std::string &filename)
68 std::string combined = name_of_shader + DIR_DELIM + filename;
73 bool incache = g_shadername_to_path_cache.get(combined, &fullpath);
78 Check from shader_path
80 std::string shader_path = g_settings->get("shader_path");
81 if (!shader_path.empty()) {
82 std::string testpath = shader_path + DIR_DELIM + combined;
83 if(fs::PathExists(testpath))
88 Check from default data directory
90 if (fullpath.empty()) {
91 std::string rel_path = std::string("client") + DIR_DELIM
92 + "shaders" + DIR_DELIM
93 + name_of_shader + DIR_DELIM
95 std::string testpath = porting::path_share + DIR_DELIM + rel_path;
96 if(fs::PathExists(testpath))
100 // Add to cache (also an empty result is cached)
101 g_shadername_to_path_cache.set(combined, fullpath);
108 SourceShaderCache: A cache used for storing source shaders.
111 class SourceShaderCache
114 void insert(const std::string &name_of_shader, const std::string &filename,
115 const std::string &program, bool prefer_local)
117 std::string combined = name_of_shader + DIR_DELIM + filename;
118 // Try to use local shader instead if asked to
120 std::string path = getShaderPath(name_of_shader, filename);
122 std::string p = readFile(path);
124 m_programs[combined] = p;
129 m_programs[combined] = program;
132 std::string get(const std::string &name_of_shader,
133 const std::string &filename)
135 std::string combined = name_of_shader + DIR_DELIM + filename;
136 StringMap::iterator n = m_programs.find(combined);
137 if (n != m_programs.end())
142 // Primarily fetches from cache, secondarily tries to read from filesystem
143 std::string getOrLoad(const std::string &name_of_shader,
144 const std::string &filename)
146 std::string combined = name_of_shader + DIR_DELIM + filename;
147 StringMap::iterator n = m_programs.find(combined);
148 if (n != m_programs.end())
150 std::string path = getShaderPath(name_of_shader, filename);
152 infostream << "SourceShaderCache::getOrLoad(): No path found for \""
153 << combined << "\"" << std::endl;
156 infostream << "SourceShaderCache::getOrLoad(): Loading path \""
157 << path << "\"" << std::endl;
158 std::string p = readFile(path);
160 m_programs[combined] = p;
166 StringMap m_programs;
168 std::string readFile(const std::string &path)
170 std::ifstream is(path.c_str(), std::ios::binary);
173 std::ostringstream tmp_os;
174 tmp_os << is.rdbuf();
181 ShaderCallback: Sets constants that can be used in shaders
184 class ShaderCallback : public video::IShaderConstantSetCallBack
186 std::vector<IShaderConstantSetter*> m_setters;
189 ShaderCallback(const std::vector<IShaderConstantSetterFactory *> &factories)
191 for (IShaderConstantSetterFactory *factory : factories)
192 m_setters.push_back(factory->create());
197 for (IShaderConstantSetter *setter : m_setters)
201 virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData) override
203 video::IVideoDriver *driver = services->getVideoDriver();
204 sanity_check(driver != NULL);
206 bool is_highlevel = userData;
208 for (IShaderConstantSetter *setter : m_setters)
209 setter->onSetConstants(services, is_highlevel);
212 virtual void OnSetMaterial(const video::SMaterial& material) override
214 for (IShaderConstantSetter *setter : m_setters)
215 setter->onSetMaterial(material);
221 MainShaderConstantSetter: Set basic constants required for almost everything
224 class MainShaderConstantSetter : public IShaderConstantSetter
226 CachedVertexShaderSetting<float, 16> m_world_view_proj;
227 CachedVertexShaderSetting<float, 16> m_world;
230 MainShaderConstantSetter() :
231 m_world_view_proj("mWorldViewProj"),
234 ~MainShaderConstantSetter() = default;
236 virtual void onSetConstants(video::IMaterialRendererServices *services,
239 video::IVideoDriver *driver = services->getVideoDriver();
240 sanity_check(driver);
243 core::matrix4 worldViewProj;
244 worldViewProj = driver->getTransform(video::ETS_PROJECTION);
245 worldViewProj *= driver->getTransform(video::ETS_VIEW);
246 worldViewProj *= driver->getTransform(video::ETS_WORLD);
248 m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
250 services->setVertexShaderConstant(worldViewProj.pointer(), 0, 4);
253 core::matrix4 world = driver->getTransform(video::ETS_WORLD);
255 m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
257 services->setVertexShaderConstant(world.pointer(), 4, 4);
263 class MainShaderConstantSetterFactory : public IShaderConstantSetterFactory
266 virtual IShaderConstantSetter* create()
267 { return new MainShaderConstantSetter(); }
275 class ShaderSource : public IWritableShaderSource
282 - If shader material specified by name is found from cache,
283 return the cached id.
284 - Otherwise generate the shader material, add to cache and return id.
286 The id 0 points to a null shader. Its material is EMT_SOLID.
288 u32 getShaderIdDirect(const std::string &name,
289 const u8 material_type, const u8 drawtype);
292 If shader specified by the name pointed by the id doesn't
293 exist, create it, then return id.
295 Can be called from any thread. If called from some other thread
296 and not found in cache, the call is queued to the main thread
300 u32 getShader(const std::string &name,
301 const u8 material_type, const u8 drawtype);
303 ShaderInfo getShaderInfo(u32 id);
305 // Processes queued shader requests from other threads.
306 // Shall be called from the main thread.
309 // Insert a shader program into the cache without touching the
310 // filesystem. Shall be called from the main thread.
311 void insertSourceShader(const std::string &name_of_shader,
312 const std::string &filename, const std::string &program);
314 // Rebuild shaders from the current set of source shaders
315 // Shall be called from the main thread.
316 void rebuildShaders();
318 void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter)
320 m_setter_factories.push_back(setter);
325 // The id of the thread that is allowed to use irrlicht directly
326 std::thread::id m_main_thread;
328 // Cache of source shaders
329 // This should be only accessed from the main thread
330 SourceShaderCache m_sourcecache;
332 // A shader id is index in this array.
333 // The first position contains a dummy shader.
334 std::vector<ShaderInfo> m_shaderinfo_cache;
335 // The former container is behind this mutex
336 std::mutex m_shaderinfo_cache_mutex;
338 // Queued shader fetches (to be processed by the main thread)
339 RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
341 // Global constant setter factories
342 std::vector<IShaderConstantSetterFactory *> m_setter_factories;
345 std::vector<ShaderCallback *> m_callbacks;
348 IWritableShaderSource *createShaderSource()
350 return new ShaderSource();
354 Generate shader given the shader name.
356 ShaderInfo generate_shader(const std::string &name,
357 u8 material_type, u8 drawtype, std::vector<ShaderCallback *> &callbacks,
358 const std::vector<IShaderConstantSetterFactory *> &setter_factories,
359 SourceShaderCache *sourcecache);
364 void load_shaders(const std::string &name, SourceShaderCache *sourcecache,
365 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
366 std::string &vertex_program, std::string &pixel_program,
367 std::string &geometry_program, bool &is_highlevel);
369 ShaderSource::ShaderSource()
371 m_main_thread = std::this_thread::get_id();
373 // Add a dummy ShaderInfo as the first index, named ""
374 m_shaderinfo_cache.emplace_back();
376 // Add main global constant setter
377 addShaderConstantSetterFactory(new MainShaderConstantSetterFactory());
380 ShaderSource::~ShaderSource()
382 for (ShaderCallback *callback : m_callbacks) {
385 for (IShaderConstantSetterFactory *setter_factorie : m_setter_factories) {
386 delete setter_factorie;
390 u32 ShaderSource::getShader(const std::string &name,
391 const u8 material_type, const u8 drawtype)
397 if (std::this_thread::get_id() == m_main_thread) {
398 return getShaderIdDirect(name, material_type, drawtype);
401 /*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/
403 // We're gonna ask the result to be put into here
405 static ResultQueue<std::string, u32, u8, u8> result_queue;
407 // Throw a request in
408 m_get_shader_queue.add(name, 0, 0, &result_queue);
410 /* infostream<<"Waiting for shader from main thread, name=\""
411 <<name<<"\""<<std::endl;*/
414 GetResult<std::string, u32, u8, u8>
415 result = result_queue.pop_frontNoEx();
417 if (result.key == name) {
421 errorstream << "Got shader with invalid name: " << result.key << std::endl;
424 infostream << "getShader(): Failed" << std::endl;
430 This method generates all the shaders
432 u32 ShaderSource::getShaderIdDirect(const std::string &name,
433 const u8 material_type, const u8 drawtype)
435 //infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
437 // Empty name means shader 0
439 infostream<<"getShaderIdDirect(): name is empty"<<std::endl;
443 // Check if already have such instance
444 for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
445 ShaderInfo *info = &m_shaderinfo_cache[i];
446 if(info->name == name && info->material_type == material_type &&
447 info->drawtype == drawtype)
452 Calling only allowed from main thread
454 if (std::this_thread::get_id() != m_main_thread) {
455 errorstream<<"ShaderSource::getShaderIdDirect() "
456 "called not from main thread"<<std::endl;
460 ShaderInfo info = generate_shader(name, material_type, drawtype,
461 m_callbacks, m_setter_factories, &m_sourcecache);
464 Add shader to caches (add dummy shaders too)
467 MutexAutoLock lock(m_shaderinfo_cache_mutex);
469 u32 id = m_shaderinfo_cache.size();
470 m_shaderinfo_cache.push_back(info);
472 infostream<<"getShaderIdDirect(): "
473 <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;
479 ShaderInfo ShaderSource::getShaderInfo(u32 id)
481 MutexAutoLock lock(m_shaderinfo_cache_mutex);
483 if(id >= m_shaderinfo_cache.size())
486 return m_shaderinfo_cache[id];
489 void ShaderSource::processQueue()
495 void ShaderSource::insertSourceShader(const std::string &name_of_shader,
496 const std::string &filename, const std::string &program)
498 /*infostream<<"ShaderSource::insertSourceShader(): "
499 "name_of_shader=\""<<name_of_shader<<"\", "
500 "filename=\""<<filename<<"\""<<std::endl;*/
502 sanity_check(std::this_thread::get_id() == m_main_thread);
504 m_sourcecache.insert(name_of_shader, filename, program, true);
507 void ShaderSource::rebuildShaders()
509 MutexAutoLock lock(m_shaderinfo_cache_mutex);
511 /*// Oh well... just clear everything, they'll load sometime.
512 m_shaderinfo_cache.clear();
513 m_name_to_id.clear();*/
516 FIXME: Old shader materials can't be deleted in Irrlicht,
518 (This would be nice to do in the destructor too)
522 for (ShaderInfo &i : m_shaderinfo_cache) {
523 ShaderInfo *info = &i;
524 if (!info->name.empty()) {
525 *info = generate_shader(info->name, info->material_type,
526 info->drawtype, m_callbacks,
527 m_setter_factories, &m_sourcecache);
533 ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtype,
534 std::vector<ShaderCallback *> &callbacks,
535 const std::vector<IShaderConstantSetterFactory *> &setter_factories,
536 SourceShaderCache *sourcecache)
538 ShaderInfo shaderinfo;
539 shaderinfo.name = name;
540 shaderinfo.material_type = material_type;
541 shaderinfo.drawtype = drawtype;
542 shaderinfo.material = video::EMT_SOLID;
543 switch (material_type) {
544 case TILE_MATERIAL_OPAQUE:
545 case TILE_MATERIAL_LIQUID_OPAQUE:
546 case TILE_MATERIAL_WAVING_LIQUID_OPAQUE:
547 shaderinfo.base_material = video::EMT_SOLID;
549 case TILE_MATERIAL_ALPHA:
550 case TILE_MATERIAL_PLAIN_ALPHA:
551 case TILE_MATERIAL_LIQUID_TRANSPARENT:
552 case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
553 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
555 case TILE_MATERIAL_BASIC:
556 case TILE_MATERIAL_PLAIN:
557 case TILE_MATERIAL_WAVING_LEAVES:
558 case TILE_MATERIAL_WAVING_PLANTS:
559 case TILE_MATERIAL_WAVING_LIQUID_BASIC:
560 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
564 bool enable_shaders = g_settings->getBool("enable_shaders");
568 video::IVideoDriver *driver = RenderingEngine::get_video_driver();
570 video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
572 errorstream<<"generate_shader(): "
573 "failed to generate \""<<name<<"\", "
574 "GPU programming not supported."
579 // Choose shader language depending on driver type and settings
581 std::string vertex_program;
582 std::string pixel_program;
583 std::string geometry_program;
585 load_shaders(name, sourcecache, driver->getDriverType(),
586 enable_shaders, vertex_program, pixel_program,
587 geometry_program, is_highlevel);
588 // Check hardware/driver support
589 if (!vertex_program.empty() &&
590 !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
591 !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
592 infostream<<"generate_shader(): vertex shaders disabled "
593 "because of missing driver/hardware support."
597 if (!pixel_program.empty() &&
598 !driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
599 !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
600 infostream<<"generate_shader(): pixel shaders disabled "
601 "because of missing driver/hardware support."
605 if (!geometry_program.empty() &&
606 !driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
607 infostream<<"generate_shader(): geometry shaders disabled "
608 "because of missing driver/hardware support."
610 geometry_program = "";
613 // If no shaders are used, don't make a separate material type
614 if (vertex_program.empty() && pixel_program.empty() && geometry_program.empty())
617 // Create shaders header
618 std::string shaders_header = "#version 120\n";
621 // For renderers that should use discard instead of GL_ALPHA_TEST
622 const char* gl_renderer = (const char*)glGetString(GL_RENDERER);
623 if (strstr(gl_renderer, "GC7000")) {
624 shaders_header += "#define USE_DISCARD\n";
628 static const char* drawTypes[] = {
635 "NDT_ALLFACES_OPTIONAL",
642 "NDT_GLASSLIKE_FRAMED",
644 "NDT_GLASSLIKE_FRAMED_OPTIONAL",
645 "NDT_PLANTLIKE_ROOTED",
648 for (int i = 0; i < 14; i++){
649 shaders_header += "#define ";
650 shaders_header += drawTypes[i];
651 shaders_header += " ";
652 shaders_header += itos(i);
653 shaders_header += "\n";
656 static const char* materialTypes[] = {
657 "TILE_MATERIAL_BASIC",
658 "TILE_MATERIAL_ALPHA",
659 "TILE_MATERIAL_LIQUID_TRANSPARENT",
660 "TILE_MATERIAL_LIQUID_OPAQUE",
661 "TILE_MATERIAL_WAVING_LEAVES",
662 "TILE_MATERIAL_WAVING_PLANTS",
663 "TILE_MATERIAL_OPAQUE",
664 "TILE_MATERIAL_WAVING_LIQUID_BASIC",
665 "TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT",
666 "TILE_MATERIAL_WAVING_LIQUID_OPAQUE",
667 "TILE_MATERIAL_PLAIN",
668 "TILE_MATERIAL_PLAIN_ALPHA",
671 for (int i = 0; i < 12; i++){
672 shaders_header += "#define ";
673 shaders_header += materialTypes[i];
674 shaders_header += " ";
675 shaders_header += itos(i);
676 shaders_header += "\n";
679 shaders_header += "#define MATERIAL_TYPE ";
680 shaders_header += itos(material_type);
681 shaders_header += "\n";
682 shaders_header += "#define DRAW_TYPE ";
683 shaders_header += itos(drawtype);
684 shaders_header += "\n";
686 if (g_settings->getBool("generate_normalmaps")) {
687 shaders_header += "#define GENERATE_NORMALMAPS 1\n";
689 shaders_header += "#define GENERATE_NORMALMAPS 0\n";
691 shaders_header += "#define NORMALMAPS_STRENGTH ";
692 shaders_header += ftos(g_settings->getFloat("normalmaps_strength"));
693 shaders_header += "\n";
695 int smooth = (int)g_settings->getFloat("normalmaps_smooth");
698 sample_step = 0.0078125; // 1.0 / 128.0
701 sample_step = 0.00390625; // 1.0 / 256.0
704 sample_step = 0.001953125; // 1.0 / 512.0
707 sample_step = 0.0078125;
710 shaders_header += "#define SAMPLE_STEP ";
711 shaders_header += ftos(sample_step);
712 shaders_header += "\n";
714 if (g_settings->getBool("enable_bumpmapping"))
715 shaders_header += "#define ENABLE_BUMPMAPPING\n";
717 if (g_settings->getBool("enable_parallax_occlusion")){
718 int mode = g_settings->getFloat("parallax_occlusion_mode");
719 float scale = g_settings->getFloat("parallax_occlusion_scale");
720 float bias = g_settings->getFloat("parallax_occlusion_bias");
721 int iterations = g_settings->getFloat("parallax_occlusion_iterations");
722 shaders_header += "#define ENABLE_PARALLAX_OCCLUSION\n";
723 shaders_header += "#define PARALLAX_OCCLUSION_MODE ";
724 shaders_header += itos(mode);
725 shaders_header += "\n";
726 shaders_header += "#define PARALLAX_OCCLUSION_SCALE ";
727 shaders_header += ftos(scale);
728 shaders_header += "\n";
729 shaders_header += "#define PARALLAX_OCCLUSION_BIAS ";
730 shaders_header += ftos(bias);
731 shaders_header += "\n";
732 shaders_header += "#define PARALLAX_OCCLUSION_ITERATIONS ";
733 shaders_header += itos(iterations);
734 shaders_header += "\n";
737 shaders_header += "#define USE_NORMALMAPS ";
738 if (g_settings->getBool("enable_bumpmapping") || g_settings->getBool("enable_parallax_occlusion"))
739 shaders_header += "1\n";
741 shaders_header += "0\n";
743 if (g_settings->getBool("enable_waving_water")){
744 shaders_header += "#define ENABLE_WAVING_WATER 1\n";
745 shaders_header += "#define WATER_WAVE_HEIGHT ";
746 shaders_header += ftos(g_settings->getFloat("water_wave_height"));
747 shaders_header += "\n";
748 shaders_header += "#define WATER_WAVE_LENGTH ";
749 shaders_header += ftos(g_settings->getFloat("water_wave_length"));
750 shaders_header += "\n";
751 shaders_header += "#define WATER_WAVE_SPEED ";
752 shaders_header += ftos(g_settings->getFloat("water_wave_speed"));
753 shaders_header += "\n";
755 shaders_header += "#define ENABLE_WAVING_WATER 0\n";
758 shaders_header += "#define ENABLE_WAVING_LEAVES ";
759 if (g_settings->getBool("enable_waving_leaves"))
760 shaders_header += "1\n";
762 shaders_header += "0\n";
764 shaders_header += "#define ENABLE_WAVING_PLANTS ";
765 if (g_settings->getBool("enable_waving_plants"))
766 shaders_header += "1\n";
768 shaders_header += "0\n";
770 if (g_settings->getBool("tone_mapping"))
771 shaders_header += "#define ENABLE_TONE_MAPPING\n";
773 shaders_header += "#define FOG_START ";
774 shaders_header += ftos(rangelim(g_settings->getFloat("fog_start"), 0.0f, 0.99f));
775 shaders_header += "\n";
777 // Call addHighLevelShaderMaterial() or addShaderMaterial()
778 const c8* vertex_program_ptr = 0;
779 const c8* pixel_program_ptr = 0;
780 const c8* geometry_program_ptr = 0;
781 if (!vertex_program.empty()) {
782 vertex_program = shaders_header + vertex_program;
783 vertex_program_ptr = vertex_program.c_str();
785 if (!pixel_program.empty()) {
786 pixel_program = shaders_header + pixel_program;
787 pixel_program_ptr = pixel_program.c_str();
789 if (!geometry_program.empty()) {
790 geometry_program = shaders_header + geometry_program;
791 geometry_program_ptr = geometry_program.c_str();
793 ShaderCallback *cb = new ShaderCallback(setter_factories);
796 infostream<<"Compiling high level shaders for "<<name<<std::endl;
797 shadermat = gpu->addHighLevelShaderMaterial(
798 vertex_program_ptr, // Vertex shader program
799 "vertexMain", // Vertex shader entry point
800 video::EVST_VS_1_1, // Vertex shader version
801 pixel_program_ptr, // Pixel shader program
802 "pixelMain", // Pixel shader entry point
803 video::EPST_PS_1_2, // Pixel shader version
804 geometry_program_ptr, // Geometry shader program
805 "geometryMain", // Geometry shader entry point
806 video::EGST_GS_4_0, // Geometry shader version
807 scene::EPT_TRIANGLES, // Geometry shader input
808 scene::EPT_TRIANGLE_STRIP, // Geometry shader output
809 0, // Support maximum number of vertices
810 cb, // Set-constant callback
811 shaderinfo.base_material, // Base material
812 1 // Userdata passed to callback
815 errorstream<<"generate_shader(): "
816 "failed to generate \""<<name<<"\", "
817 "addHighLevelShaderMaterial failed."
819 dumpShaderProgram(warningstream, "Vertex", vertex_program);
820 dumpShaderProgram(warningstream, "Pixel", pixel_program);
821 dumpShaderProgram(warningstream, "Geometry", geometry_program);
827 infostream<<"Compiling assembly shaders for "<<name<<std::endl;
828 shadermat = gpu->addShaderMaterial(
829 vertex_program_ptr, // Vertex shader program
830 pixel_program_ptr, // Pixel shader program
831 cb, // Set-constant callback
832 shaderinfo.base_material, // Base material
833 0 // Userdata passed to callback
837 errorstream<<"generate_shader(): "
838 "failed to generate \""<<name<<"\", "
839 "addShaderMaterial failed."
841 dumpShaderProgram(warningstream, "Vertex", vertex_program);
842 dumpShaderProgram(warningstream,"Pixel", pixel_program);
847 callbacks.push_back(cb);
849 // HACK, TODO: investigate this better
850 // Grab the material renderer once more so minetest doesn't crash on exit
851 driver->getMaterialRenderer(shadermat)->grab();
853 // Apply the newly created material type
854 shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
858 void load_shaders(const std::string &name, SourceShaderCache *sourcecache,
859 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
860 std::string &vertex_program, std::string &pixel_program,
861 std::string &geometry_program, bool &is_highlevel)
865 geometry_program = "";
866 is_highlevel = false;
869 // Look for high level shaders
870 if(drivertype == video::EDT_DIRECT3D9){
872 // (All shaders in one file)
873 vertex_program = sourcecache->getOrLoad(name, "d3d9.hlsl");
874 pixel_program = vertex_program;
875 geometry_program = vertex_program;
877 else if(drivertype == video::EDT_OPENGL){
879 vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.glsl");
880 pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.glsl");
881 geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl");
883 if (!vertex_program.empty() || !pixel_program.empty() || !geometry_program.empty()){
891 void dumpShaderProgram(std::ostream &output_stream,
892 const std::string &program_type, const std::string &program)
894 output_stream << program_type << " shader program:" << std::endl <<
895 "----------------------------------" << std::endl;
899 while ((pos = program.find('\n', prev)) != std::string::npos) {
900 output_stream << line++ << ": "<< program.substr(prev, pos - prev) <<
904 output_stream << line << ": " << program.substr(prev) << std::endl <<
905 "End of " << program_type << " shader program." << std::endl <<