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 A cache from shader name to shader path
44 MutexedMap<std::string, std::string> g_shadername_to_path_cache;
47 Gets the path to a shader by first checking if the file
48 name_of_shader/filename
49 exists in shader_path and if not, using the data path.
51 If not found, returns "".
53 Utilizes a thread-safe cache.
55 std::string getShaderPath(const std::string &name_of_shader, const std::string &filename)
57 std::string combined = name_of_shader + DIR_DELIM + filename;
62 bool incache = g_shadername_to_path_cache.get(combined, &fullpath);
67 Check from shader_path
69 std::string shader_path = g_settings->get("shader_path");
70 if (!shader_path.empty()) {
71 std::string testpath = shader_path + DIR_DELIM + combined;
72 if (fs::PathExists(testpath))
77 Check from default data directory
79 if (fullpath.empty()) {
80 std::string rel_path = std::string("client") + DIR_DELIM + "shaders" +
81 DIR_DELIM + name_of_shader + DIR_DELIM + filename;
82 std::string testpath = porting::path_share + DIR_DELIM + rel_path;
83 if (fs::PathExists(testpath))
87 // Add to cache (also an empty result is cached)
88 g_shadername_to_path_cache.set(combined, fullpath);
95 SourceShaderCache: A cache used for storing source shaders.
98 class SourceShaderCache
101 void insert(const std::string &name_of_shader, const std::string &filename,
102 const std::string &program, bool prefer_local)
104 std::string combined = name_of_shader + DIR_DELIM + filename;
105 // Try to use local shader instead if asked to
107 std::string path = getShaderPath(name_of_shader, filename);
109 std::string p = readFile(path);
111 m_programs[combined] = p;
116 m_programs[combined] = program;
119 std::string get(const std::string &name_of_shader, const std::string &filename)
121 std::string combined = name_of_shader + DIR_DELIM + filename;
122 StringMap::iterator n = m_programs.find(combined);
123 if (n != m_programs.end())
128 // Primarily fetches from cache, secondarily tries to read from filesystem
129 std::string getOrLoad(
130 const std::string &name_of_shader, const std::string &filename)
132 std::string combined = name_of_shader + DIR_DELIM + filename;
133 StringMap::iterator n = m_programs.find(combined);
134 if (n != m_programs.end())
136 std::string path = getShaderPath(name_of_shader, filename);
138 infostream << "SourceShaderCache::getOrLoad(): No path found for "
140 << combined << "\"" << std::endl;
143 infostream << "SourceShaderCache::getOrLoad(): Loading path \"" << path
144 << "\"" << std::endl;
145 std::string p = readFile(path);
147 m_programs[combined] = p;
154 StringMap m_programs;
156 std::string readFile(const std::string &path)
158 std::ifstream is(path.c_str(), std::ios::binary);
161 std::ostringstream tmp_os;
162 tmp_os << is.rdbuf();
168 ShaderCallback: Sets constants that can be used in shaders
171 class ShaderCallback : public video::IShaderConstantSetCallBack
173 std::vector<IShaderConstantSetter *> m_setters;
176 ShaderCallback(const std::vector<IShaderConstantSetterFactory *> &factories)
178 for (IShaderConstantSetterFactory *factory : factories)
179 m_setters.push_back(factory->create());
184 for (IShaderConstantSetter *setter : m_setters)
188 virtual void OnSetConstants(
189 video::IMaterialRendererServices *services, s32 userData) override
191 video::IVideoDriver *driver = services->getVideoDriver();
192 sanity_check(driver != NULL);
194 bool is_highlevel = userData;
196 for (IShaderConstantSetter *setter : m_setters)
197 setter->onSetConstants(services, is_highlevel);
200 virtual void OnSetMaterial(const video::SMaterial &material) override
202 for (IShaderConstantSetter *setter : m_setters)
203 setter->onSetMaterial(material);
208 MainShaderConstantSetter: Set basic constants required for almost everything
211 class MainShaderConstantSetter : public IShaderConstantSetter
213 CachedVertexShaderSetting<float, 16> m_world_view_proj;
214 CachedVertexShaderSetting<float, 16> m_world;
217 MainShaderConstantSetter() :
218 m_world_view_proj("mWorldViewProj"), m_world("mWorld")
221 ~MainShaderConstantSetter() = default;
223 virtual void onSetConstants(
224 video::IMaterialRendererServices *services, bool is_highlevel)
226 video::IVideoDriver *driver = services->getVideoDriver();
227 sanity_check(driver);
230 core::matrix4 worldViewProj;
231 worldViewProj = driver->getTransform(video::ETS_PROJECTION);
232 worldViewProj *= driver->getTransform(video::ETS_VIEW);
233 worldViewProj *= driver->getTransform(video::ETS_WORLD);
235 m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(
236 worldViewProj.pointer()),
239 services->setVertexShaderConstant(worldViewProj.pointer(), 0, 4);
242 core::matrix4 world = driver->getTransform(video::ETS_WORLD);
244 m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()),
247 services->setVertexShaderConstant(world.pointer(), 4, 4);
251 class MainShaderConstantSetterFactory : public IShaderConstantSetterFactory
254 virtual IShaderConstantSetter *create() { return new MainShaderConstantSetter(); }
261 class ShaderSource : public IWritableShaderSource
268 - If shader material specified by name is found from cache,
269 return the cached id.
270 - Otherwise generate the shader material, add to cache and return id.
272 The id 0 points to a null shader. Its material is EMT_SOLID.
274 u32 getShaderIdDirect(const std::string &name, const u8 material_type,
278 If shader specified by the name pointed by the id doesn't
279 exist, create it, then return id.
281 Can be called from any thread. If called from some other thread
282 and not found in cache, the call is queued to the main thread
286 u32 getShader(const std::string &name, const u8 material_type, const u8 drawtype);
288 ShaderInfo getShaderInfo(u32 id);
290 // Processes queued shader requests from other threads.
291 // Shall be called from the main thread.
294 // Insert a shader program into the cache without touching the
295 // filesystem. Shall be called from the main thread.
296 void insertSourceShader(const std::string &name_of_shader,
297 const std::string &filename, const std::string &program);
299 // Rebuild shaders from the current set of source shaders
300 // Shall be called from the main thread.
301 void rebuildShaders();
303 void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter)
305 m_setter_factories.push_back(setter);
309 // The id of the thread that is allowed to use irrlicht directly
310 std::thread::id m_main_thread;
312 // Cache of source shaders
313 // This should be only accessed from the main thread
314 SourceShaderCache m_sourcecache;
316 // A shader id is index in this array.
317 // The first position contains a dummy shader.
318 std::vector<ShaderInfo> m_shaderinfo_cache;
319 // The former container is behind this mutex
320 std::mutex m_shaderinfo_cache_mutex;
322 // Queued shader fetches (to be processed by the main thread)
323 RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
325 // Global constant setter factories
326 std::vector<IShaderConstantSetterFactory *> m_setter_factories;
329 std::vector<ShaderCallback *> m_callbacks;
332 IWritableShaderSource *createShaderSource()
334 return new ShaderSource();
338 Generate shader given the shader name.
340 ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtype,
341 std::vector<ShaderCallback *> &callbacks,
342 const std::vector<IShaderConstantSetterFactory *> &setter_factories,
343 SourceShaderCache *sourcecache);
348 void load_shaders(const std::string &name, SourceShaderCache *sourcecache,
349 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
350 std::string &vertex_program, std::string &pixel_program,
351 std::string &geometry_program, bool &is_highlevel);
353 ShaderSource::ShaderSource()
355 m_main_thread = std::this_thread::get_id();
357 // Add a dummy ShaderInfo as the first index, named ""
358 m_shaderinfo_cache.emplace_back();
360 // Add main global constant setter
361 addShaderConstantSetterFactory(new MainShaderConstantSetterFactory());
364 ShaderSource::~ShaderSource()
366 for (ShaderCallback *callback : m_callbacks) {
369 for (IShaderConstantSetterFactory *setter_factorie : m_setter_factories) {
370 delete setter_factorie;
374 u32 ShaderSource::getShader(
375 const std::string &name, const u8 material_type, const u8 drawtype)
381 if (std::this_thread::get_id() == m_main_thread) {
382 return getShaderIdDirect(name, material_type, drawtype);
385 /*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/
387 // We're gonna ask the result to be put into here
389 static ResultQueue<std::string, u32, u8, u8> result_queue;
391 // Throw a request in
392 m_get_shader_queue.add(name, 0, 0, &result_queue);
394 /* infostream<<"Waiting for shader from main thread, name=\""
395 <<name<<"\""<<std::endl;*/
398 GetResult<std::string, u32, u8, u8> result = result_queue.pop_frontNoEx();
400 if (result.key == name) {
404 errorstream << "Got shader with invalid name: " << result.key
408 infostream << "getShader(): Failed" << std::endl;
414 This method generates all the shaders
416 u32 ShaderSource::getShaderIdDirect(
417 const std::string &name, const u8 material_type, const u8 drawtype)
419 // infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
421 // Empty name means shader 0
423 infostream << "getShaderIdDirect(): name is empty" << std::endl;
427 // Check if already have such instance
428 for (u32 i = 0; i < m_shaderinfo_cache.size(); i++) {
429 ShaderInfo *info = &m_shaderinfo_cache[i];
430 if (info->name == name && info->material_type == material_type &&
431 info->drawtype == drawtype)
436 Calling only allowed from main thread
438 if (std::this_thread::get_id() != m_main_thread) {
439 errorstream << "ShaderSource::getShaderIdDirect() "
440 "called not from main thread"
445 ShaderInfo info = generate_shader(name, material_type, drawtype, m_callbacks,
446 m_setter_factories, &m_sourcecache);
449 Add shader to caches (add dummy shaders too)
452 MutexAutoLock lock(m_shaderinfo_cache_mutex);
454 u32 id = m_shaderinfo_cache.size();
455 m_shaderinfo_cache.push_back(info);
457 infostream << "getShaderIdDirect(): "
458 << "Returning id=" << id << " for name \"" << name << "\""
464 ShaderInfo ShaderSource::getShaderInfo(u32 id)
466 MutexAutoLock lock(m_shaderinfo_cache_mutex);
468 if (id >= m_shaderinfo_cache.size())
471 return m_shaderinfo_cache[id];
474 void ShaderSource::processQueue()
478 void ShaderSource::insertSourceShader(const std::string &name_of_shader,
479 const std::string &filename, const std::string &program)
481 /*infostream<<"ShaderSource::insertSourceShader(): "
482 "name_of_shader=\""<<name_of_shader<<"\", "
483 "filename=\""<<filename<<"\""<<std::endl;*/
485 sanity_check(std::this_thread::get_id() == m_main_thread);
487 m_sourcecache.insert(name_of_shader, filename, program, true);
490 void ShaderSource::rebuildShaders()
492 MutexAutoLock lock(m_shaderinfo_cache_mutex);
494 /*// Oh well... just clear everything, they'll load sometime.
495 m_shaderinfo_cache.clear();
496 m_name_to_id.clear();*/
499 FIXME: Old shader materials can't be deleted in Irrlicht,
501 (This would be nice to do in the destructor too)
505 for (ShaderInfo &i : m_shaderinfo_cache) {
506 ShaderInfo *info = &i;
507 if (!info->name.empty()) {
508 *info = generate_shader(info->name, info->material_type,
509 info->drawtype, m_callbacks, m_setter_factories,
515 ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtype,
516 std::vector<ShaderCallback *> &callbacks,
517 const std::vector<IShaderConstantSetterFactory *> &setter_factories,
518 SourceShaderCache *sourcecache)
520 ShaderInfo shaderinfo;
521 shaderinfo.name = name;
522 shaderinfo.material_type = material_type;
523 shaderinfo.drawtype = drawtype;
524 shaderinfo.material = video::EMT_SOLID;
525 switch (material_type) {
526 case TILE_MATERIAL_OPAQUE:
527 case TILE_MATERIAL_LIQUID_OPAQUE:
528 case TILE_MATERIAL_WAVING_LIQUID_OPAQUE:
529 shaderinfo.base_material = video::EMT_SOLID;
531 case TILE_MATERIAL_ALPHA:
532 case TILE_MATERIAL_PLAIN_ALPHA:
533 case TILE_MATERIAL_LIQUID_TRANSPARENT:
534 case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
535 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
537 case TILE_MATERIAL_BASIC:
538 case TILE_MATERIAL_PLAIN:
539 case TILE_MATERIAL_WAVING_LEAVES:
540 case TILE_MATERIAL_WAVING_PLANTS:
541 case TILE_MATERIAL_WAVING_LIQUID_BASIC:
542 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
546 bool enable_shaders = g_settings->getBool("enable_shaders");
550 video::IVideoDriver *driver = RenderingEngine::get_video_driver();
552 video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
554 errorstream << "generate_shader(): "
555 "failed to generate \""
558 "GPU programming not supported."
563 // Choose shader language depending on driver type and settings
565 std::string vertex_program;
566 std::string pixel_program;
567 std::string geometry_program;
569 load_shaders(name, sourcecache, driver->getDriverType(), enable_shaders,
570 vertex_program, pixel_program, geometry_program, is_highlevel);
571 // Check hardware/driver support
572 if (!vertex_program.empty() &&
573 !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
574 !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)) {
575 infostream << "generate_shader(): vertex shaders disabled "
576 "because of missing driver/hardware support."
580 if (!pixel_program.empty() &&
581 !driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
582 !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)) {
583 infostream << "generate_shader(): pixel shaders disabled "
584 "because of missing driver/hardware support."
588 if (!geometry_program.empty() &&
589 !driver->queryFeature(video::EVDF_GEOMETRY_SHADER)) {
590 infostream << "generate_shader(): geometry shaders disabled "
591 "because of missing driver/hardware support."
593 geometry_program = "";
596 // If no shaders are used, don't make a separate material type
597 if (vertex_program.empty() && pixel_program.empty() && geometry_program.empty())
600 // Create shaders header
601 std::string shaders_header = "#version 120\n";
603 static const char *drawTypes[] = {
610 "NDT_ALLFACES_OPTIONAL",
617 "NDT_GLASSLIKE_FRAMED",
619 "NDT_GLASSLIKE_FRAMED_OPTIONAL",
620 "NDT_PLANTLIKE_ROOTED",
623 for (int i = 0; i < 14; i++) {
624 shaders_header += "#define ";
625 shaders_header += drawTypes[i];
626 shaders_header += " ";
627 shaders_header += itos(i);
628 shaders_header += "\n";
631 static const char *materialTypes[] = {
632 "TILE_MATERIAL_BASIC",
633 "TILE_MATERIAL_ALPHA",
634 "TILE_MATERIAL_LIQUID_TRANSPARENT",
635 "TILE_MATERIAL_LIQUID_OPAQUE",
636 "TILE_MATERIAL_WAVING_LEAVES",
637 "TILE_MATERIAL_WAVING_PLANTS",
638 "TILE_MATERIAL_OPAQUE",
639 "TILE_MATERIAL_WAVING_LIQUID_BASIC",
640 "TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT",
641 "TILE_MATERIAL_WAVING_LIQUID_OPAQUE",
642 "TILE_MATERIAL_PLAIN",
643 "TILE_MATERIAL_PLAIN_ALPHA",
646 for (int i = 0; i < 12; i++) {
647 shaders_header += "#define ";
648 shaders_header += materialTypes[i];
649 shaders_header += " ";
650 shaders_header += itos(i);
651 shaders_header += "\n";
654 shaders_header += "#define MATERIAL_TYPE ";
655 shaders_header += itos(material_type);
656 shaders_header += "\n";
657 shaders_header += "#define DRAW_TYPE ";
658 shaders_header += itos(drawtype);
659 shaders_header += "\n";
661 if (g_settings->getBool("generate_normalmaps")) {
662 shaders_header += "#define GENERATE_NORMALMAPS 1\n";
664 shaders_header += "#define GENERATE_NORMALMAPS 0\n";
666 shaders_header += "#define NORMALMAPS_STRENGTH ";
667 shaders_header += ftos(g_settings->getFloat("normalmaps_strength"));
668 shaders_header += "\n";
670 int smooth = (int)g_settings->getFloat("normalmaps_smooth");
673 sample_step = 0.0078125; // 1.0 / 128.0
676 sample_step = 0.00390625; // 1.0 / 256.0
679 sample_step = 0.001953125; // 1.0 / 512.0
682 sample_step = 0.0078125;
685 shaders_header += "#define SAMPLE_STEP ";
686 shaders_header += ftos(sample_step);
687 shaders_header += "\n";
689 if (g_settings->getBool("enable_bumpmapping"))
690 shaders_header += "#define ENABLE_BUMPMAPPING\n";
692 if (g_settings->getBool("enable_parallax_occlusion")) {
693 int mode = g_settings->getFloat("parallax_occlusion_mode");
694 float scale = g_settings->getFloat("parallax_occlusion_scale");
695 float bias = g_settings->getFloat("parallax_occlusion_bias");
696 int iterations = g_settings->getFloat("parallax_occlusion_iterations");
697 shaders_header += "#define ENABLE_PARALLAX_OCCLUSION\n";
698 shaders_header += "#define PARALLAX_OCCLUSION_MODE ";
699 shaders_header += itos(mode);
700 shaders_header += "\n";
701 shaders_header += "#define PARALLAX_OCCLUSION_SCALE ";
702 shaders_header += ftos(scale);
703 shaders_header += "\n";
704 shaders_header += "#define PARALLAX_OCCLUSION_BIAS ";
705 shaders_header += ftos(bias);
706 shaders_header += "\n";
707 shaders_header += "#define PARALLAX_OCCLUSION_ITERATIONS ";
708 shaders_header += itos(iterations);
709 shaders_header += "\n";
712 shaders_header += "#define USE_NORMALMAPS ";
713 if (g_settings->getBool("enable_bumpmapping") ||
714 g_settings->getBool("enable_parallax_occlusion"))
715 shaders_header += "1\n";
717 shaders_header += "0\n";
719 if (g_settings->getBool("enable_waving_water")) {
720 shaders_header += "#define ENABLE_WAVING_WATER 1\n";
721 shaders_header += "#define WATER_WAVE_HEIGHT ";
722 shaders_header += ftos(g_settings->getFloat("water_wave_height"));
723 shaders_header += "\n";
724 shaders_header += "#define WATER_WAVE_LENGTH ";
725 shaders_header += ftos(g_settings->getFloat("water_wave_length"));
726 shaders_header += "\n";
727 shaders_header += "#define WATER_WAVE_SPEED ";
728 shaders_header += ftos(g_settings->getFloat("water_wave_speed"));
729 shaders_header += "\n";
731 shaders_header += "#define ENABLE_WAVING_WATER 0\n";
734 shaders_header += "#define ENABLE_WAVING_LEAVES ";
735 if (g_settings->getBool("enable_waving_leaves"))
736 shaders_header += "1\n";
738 shaders_header += "0\n";
740 shaders_header += "#define ENABLE_WAVING_PLANTS ";
741 if (g_settings->getBool("enable_waving_plants"))
742 shaders_header += "1\n";
744 shaders_header += "0\n";
746 if (g_settings->getBool("tone_mapping"))
747 shaders_header += "#define ENABLE_TONE_MAPPING\n";
749 shaders_header += "#define FOG_START ";
750 shaders_header += ftos(rangelim(g_settings->getFloat("fog_start"), 0.0f, 0.99f));
751 shaders_header += "\n";
753 // Call addHighLevelShaderMaterial() or addShaderMaterial()
754 const c8 *vertex_program_ptr = 0;
755 const c8 *pixel_program_ptr = 0;
756 const c8 *geometry_program_ptr = 0;
757 if (!vertex_program.empty()) {
758 vertex_program = shaders_header + vertex_program;
759 vertex_program_ptr = vertex_program.c_str();
761 if (!pixel_program.empty()) {
762 pixel_program = shaders_header + pixel_program;
763 pixel_program_ptr = pixel_program.c_str();
765 if (!geometry_program.empty()) {
766 geometry_program = shaders_header + geometry_program;
767 geometry_program_ptr = geometry_program.c_str();
769 ShaderCallback *cb = new ShaderCallback(setter_factories);
772 infostream << "Compiling high level shaders for " << name << std::endl;
773 shadermat = gpu->addHighLevelShaderMaterial(
774 vertex_program_ptr, // Vertex shader program
775 "vertexMain", // Vertex shader entry point
776 video::EVST_VS_1_1, // Vertex shader version
777 pixel_program_ptr, // Pixel shader program
778 "pixelMain", // Pixel shader entry point
779 video::EPST_PS_1_2, // Pixel shader version
780 geometry_program_ptr, // Geometry shader program
781 "geometryMain", // Geometry shader entry point
782 video::EGST_GS_4_0, // Geometry shader version
783 scene::EPT_TRIANGLES, // Geometry shader input
784 scene::EPT_TRIANGLE_STRIP, // Geometry shader output
785 0, // Support maximum number of vertices
786 cb, // Set-constant callback
787 shaderinfo.base_material, // Base material
788 1 // Userdata passed to callback
790 if (shadermat == -1) {
791 errorstream << "generate_shader(): "
792 "failed to generate \""
795 "addHighLevelShaderMaterial failed."
797 dumpShaderProgram(warningstream, "Vertex", vertex_program);
798 dumpShaderProgram(warningstream, "Pixel", pixel_program);
799 dumpShaderProgram(warningstream, "Geometry", geometry_program);
804 infostream << "Compiling assembly shaders for " << name << std::endl;
805 shadermat = gpu->addShaderMaterial(
806 vertex_program_ptr, // Vertex shader program
807 pixel_program_ptr, // Pixel shader program
808 cb, // Set-constant callback
809 shaderinfo.base_material, // Base material
810 0 // Userdata passed to callback
813 if (shadermat == -1) {
814 errorstream << "generate_shader(): "
815 "failed to generate \""
818 "addShaderMaterial failed."
820 dumpShaderProgram(warningstream, "Vertex", vertex_program);
821 dumpShaderProgram(warningstream, "Pixel", pixel_program);
826 callbacks.push_back(cb);
828 // HACK, TODO: investigate this better
829 // Grab the material renderer once more so minetest doesn't crash on exit
830 driver->getMaterialRenderer(shadermat)->grab();
832 // Apply the newly created material type
833 shaderinfo.material = (video::E_MATERIAL_TYPE)shadermat;
837 void load_shaders(const std::string &name, SourceShaderCache *sourcecache,
838 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
839 std::string &vertex_program, std::string &pixel_program,
840 std::string &geometry_program, bool &is_highlevel)
844 geometry_program = "";
845 is_highlevel = false;
847 if (enable_shaders) {
848 // Look for high level shaders
849 if (drivertype == video::EDT_DIRECT3D9) {
851 // (All shaders in one file)
852 vertex_program = sourcecache->getOrLoad(name, "d3d9.hlsl");
853 pixel_program = vertex_program;
854 geometry_program = vertex_program;
855 } else if (drivertype == video::EDT_OPENGL) {
857 vertex_program = sourcecache->getOrLoad(
858 name, "opengl_vertex.glsl");
859 pixel_program = sourcecache->getOrLoad(
860 name, "opengl_fragment.glsl");
861 geometry_program = sourcecache->getOrLoad(
862 name, "opengl_geometry.glsl");
864 if (!vertex_program.empty() || !pixel_program.empty() ||
865 !geometry_program.empty()) {
872 void dumpShaderProgram(std::ostream &output_stream, const std::string &program_type,
873 const std::string &program)
875 output_stream << program_type << " shader program:" << std::endl
876 << "----------------------------------" << std::endl;
880 while ((pos = program.find('\n', prev)) != std::string::npos) {
881 output_stream << line++ << ": " << program.substr(prev, pos - prev)
885 output_stream << line << ": " << program.substr(prev) << std::endl
886 << "End of " << program_type << " shader program." << std::endl