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 "EShaderTypes.h"
38 #include "client/tile.h"
41 A cache from shader name to shader path
43 MutexedMap<std::string, std::string> g_shadername_to_path_cache;
46 Gets the path to a shader by first checking if the file
47 name_of_shader/filename
48 exists in shader_path and if not, using the data path.
50 If not found, returns "".
52 Utilizes a thread-safe cache.
54 std::string getShaderPath(const std::string &name_of_shader,
55 const std::string &filename)
57 std::string combined = name_of_shader + DIR_DELIM + filename;
58 std::string fullpath = "";
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");
72 std::string testpath = shader_path + DIR_DELIM + combined;
73 if(fs::PathExists(testpath))
78 Check from default data directory
82 std::string rel_path = std::string("client") + DIR_DELIM
83 + "shaders" + DIR_DELIM
84 + name_of_shader + DIR_DELIM
86 std::string testpath = porting::path_share + DIR_DELIM + rel_path;
87 if(fs::PathExists(testpath))
91 // Add to cache (also an empty result is cached)
92 g_shadername_to_path_cache.set(combined, fullpath);
99 SourceShaderCache: A cache used for storing source shaders.
102 class SourceShaderCache
105 void insert(const std::string &name_of_shader, const std::string &filename,
106 const std::string &program, bool prefer_local)
108 std::string combined = name_of_shader + DIR_DELIM + filename;
109 // Try to use local shader instead if asked to
111 std::string path = getShaderPath(name_of_shader, filename);
113 std::string p = readFile(path);
115 m_programs[combined] = p;
120 m_programs[combined] = program;
123 std::string get(const std::string &name_of_shader,
124 const std::string &filename)
126 std::string combined = name_of_shader + DIR_DELIM + filename;
127 StringMap::iterator n = m_programs.find(combined);
128 if (n != m_programs.end())
133 // Primarily fetches from cache, secondarily tries to read from filesystem
134 std::string getOrLoad(const std::string &name_of_shader,
135 const std::string &filename)
137 std::string combined = name_of_shader + DIR_DELIM + filename;
138 StringMap::iterator n = m_programs.find(combined);
139 if (n != m_programs.end())
141 std::string path = getShaderPath(name_of_shader, filename);
143 infostream << "SourceShaderCache::getOrLoad(): No path found for \""
144 << combined << "\"" << std::endl;
147 infostream << "SourceShaderCache::getOrLoad(): Loading path \""
148 << path << "\"" << std::endl;
149 std::string p = readFile(path);
151 m_programs[combined] = p;
157 StringMap m_programs;
159 std::string readFile(const std::string &path)
161 std::ifstream is(path.c_str(), std::ios::binary);
164 std::ostringstream tmp_os;
165 tmp_os << is.rdbuf();
172 ShaderCallback: Sets constants that can be used in shaders
175 class ShaderCallback : public video::IShaderConstantSetCallBack
177 std::vector<IShaderConstantSetter*> m_setters;
180 ShaderCallback(const std::vector<IShaderConstantSetterFactory*> &factories)
182 for (u32 i = 0; i < factories.size(); ++i)
183 m_setters.push_back(factories[i]->create());
188 for (u32 i = 0; i < m_setters.size(); ++i)
192 virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData)
194 video::IVideoDriver *driver = services->getVideoDriver();
195 sanity_check(driver != NULL);
197 bool is_highlevel = userData;
199 for (u32 i = 0; i < m_setters.size(); ++i)
200 m_setters[i]->onSetConstants(services, is_highlevel);
206 MainShaderConstantSetter: Set basic constants required for almost everything
209 class MainShaderConstantSetter : public IShaderConstantSetter
211 CachedVertexShaderSetting<float, 16> m_world_view_proj;
212 CachedVertexShaderSetting<float, 16> m_world;
215 MainShaderConstantSetter() :
216 m_world_view_proj("mWorldViewProj"),
219 ~MainShaderConstantSetter() {}
221 virtual void onSetConstants(video::IMaterialRendererServices *services,
224 video::IVideoDriver *driver = services->getVideoDriver();
225 sanity_check(driver);
228 core::matrix4 worldViewProj;
229 worldViewProj = driver->getTransform(video::ETS_PROJECTION);
230 worldViewProj *= driver->getTransform(video::ETS_VIEW);
231 worldViewProj *= driver->getTransform(video::ETS_WORLD);
233 m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
235 services->setVertexShaderConstant(worldViewProj.pointer(), 0, 4);
238 core::matrix4 world = driver->getTransform(video::ETS_WORLD);
240 m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
242 services->setVertexShaderConstant(world.pointer(), 4, 4);
248 class MainShaderConstantSetterFactory : public IShaderConstantSetterFactory
251 virtual IShaderConstantSetter* create()
252 { return new MainShaderConstantSetter(); }
260 class ShaderSource : public IWritableShaderSource
263 ShaderSource(IrrlichtDevice *device);
267 - If shader material specified by name is found from cache,
268 return the cached id.
269 - Otherwise generate the shader material, add to cache and return id.
271 The id 0 points to a null shader. Its material is EMT_SOLID.
273 u32 getShaderIdDirect(const std::string &name,
274 const u8 material_type, const u8 drawtype);
277 If shader specified by the name pointed by the id doesn't
278 exist, create it, then return id.
280 Can be called from any thread. If called from some other thread
281 and not found in cache, the call is queued to the main thread
285 u32 getShader(const std::string &name,
286 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);
310 // The id of the thread that is allowed to use irrlicht directly
311 std::thread::id m_main_thread;
312 // The irrlicht device
313 IrrlichtDevice *m_device;
315 // Cache of source shaders
316 // This should be only accessed from the main thread
317 SourceShaderCache m_sourcecache;
319 // A shader id is index in this array.
320 // The first position contains a dummy shader.
321 std::vector<ShaderInfo> m_shaderinfo_cache;
322 // The former container is behind this mutex
323 std::mutex m_shaderinfo_cache_mutex;
325 // Queued shader fetches (to be processed by the main thread)
326 RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
328 // Global constant setter factories
329 std::vector<IShaderConstantSetterFactory *> m_setter_factories;
332 std::vector<ShaderCallback *> m_callbacks;
335 IWritableShaderSource* createShaderSource(IrrlichtDevice *device)
337 return new ShaderSource(device);
341 Generate shader given the shader name.
343 ShaderInfo generate_shader(const std::string &name,
344 u8 material_type, u8 drawtype,
345 IrrlichtDevice *device, std::vector<ShaderCallback *> &callbacks,
346 const std::vector<IShaderConstantSetterFactory*> &setter_factories,
347 SourceShaderCache *sourcecache);
352 void load_shaders(std::string name, SourceShaderCache *sourcecache,
353 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
354 std::string &vertex_program, std::string &pixel_program,
355 std::string &geometry_program, bool &is_highlevel);
357 ShaderSource::ShaderSource(IrrlichtDevice *device):
360 assert(m_device); // Pre-condition
362 m_main_thread = std::this_thread::get_id();
364 // Add a dummy ShaderInfo as the first index, named ""
365 m_shaderinfo_cache.push_back(ShaderInfo());
367 // Add main global constant setter
368 addShaderConstantSetterFactory(new MainShaderConstantSetterFactory());
371 ShaderSource::~ShaderSource()
373 for (std::vector<ShaderCallback *>::iterator iter = m_callbacks.begin();
374 iter != m_callbacks.end(); ++iter) {
377 for (std::vector<IShaderConstantSetterFactory *>::iterator iter = m_setter_factories.begin();
378 iter != m_setter_factories.end(); ++iter) {
383 u32 ShaderSource::getShader(const std::string &name,
384 const u8 material_type, const u8 drawtype)
390 if (std::this_thread::get_id() == m_main_thread) {
391 return getShaderIdDirect(name, material_type, drawtype);
393 /*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/
395 // We're gonna ask the result to be put into here
397 static ResultQueue<std::string, u32, u8, u8> result_queue;
399 // Throw a request in
400 m_get_shader_queue.add(name, 0, 0, &result_queue);
402 /* infostream<<"Waiting for shader from main thread, name=\""
403 <<name<<"\""<<std::endl;*/
406 GetResult<std::string, u32, u8, u8>
407 result = result_queue.pop_frontNoEx();
409 if (result.key == name) {
413 errorstream << "Got shader with invalid name: " << result.key << std::endl;
419 infostream<<"getShader(): Failed"<<std::endl;
425 This method generates all the shaders
427 u32 ShaderSource::getShaderIdDirect(const std::string &name,
428 const u8 material_type, const u8 drawtype)
430 //infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
432 // Empty name means shader 0
434 infostream<<"getShaderIdDirect(): name is empty"<<std::endl;
438 // Check if already have such instance
439 for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
440 ShaderInfo *info = &m_shaderinfo_cache[i];
441 if(info->name == name && info->material_type == material_type &&
442 info->drawtype == drawtype)
447 Calling only allowed from main thread
449 if (std::this_thread::get_id() != m_main_thread) {
450 errorstream<<"ShaderSource::getShaderIdDirect() "
451 "called not from main thread"<<std::endl;
455 ShaderInfo info = generate_shader(name, material_type, drawtype,
456 m_device, m_callbacks, m_setter_factories, &m_sourcecache);
459 Add shader to caches (add dummy shaders too)
462 MutexAutoLock lock(m_shaderinfo_cache_mutex);
464 u32 id = m_shaderinfo_cache.size();
465 m_shaderinfo_cache.push_back(info);
467 infostream<<"getShaderIdDirect(): "
468 <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;
474 ShaderInfo ShaderSource::getShaderInfo(u32 id)
476 MutexAutoLock lock(m_shaderinfo_cache_mutex);
478 if(id >= m_shaderinfo_cache.size())
481 return m_shaderinfo_cache[id];
484 void ShaderSource::processQueue()
490 void ShaderSource::insertSourceShader(const std::string &name_of_shader,
491 const std::string &filename, const std::string &program)
493 /*infostream<<"ShaderSource::insertSourceShader(): "
494 "name_of_shader=\""<<name_of_shader<<"\", "
495 "filename=\""<<filename<<"\""<<std::endl;*/
497 sanity_check(std::this_thread::get_id() == m_main_thread);
499 m_sourcecache.insert(name_of_shader, filename, program, true);
502 void ShaderSource::rebuildShaders()
504 MutexAutoLock lock(m_shaderinfo_cache_mutex);
506 /*// Oh well... just clear everything, they'll load sometime.
507 m_shaderinfo_cache.clear();
508 m_name_to_id.clear();*/
511 FIXME: Old shader materials can't be deleted in Irrlicht,
513 (This would be nice to do in the destructor too)
517 for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
518 ShaderInfo *info = &m_shaderinfo_cache[i];
519 if(info->name != ""){
520 *info = generate_shader(info->name, info->material_type,
521 info->drawtype, m_device, m_callbacks,
522 m_setter_factories, &m_sourcecache);
528 ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtype,
529 IrrlichtDevice *device, std::vector<ShaderCallback *> &callbacks,
530 const std::vector<IShaderConstantSetterFactory*> &setter_factories,
531 SourceShaderCache *sourcecache)
533 ShaderInfo shaderinfo;
534 shaderinfo.name = name;
535 shaderinfo.material_type = material_type;
536 shaderinfo.drawtype = drawtype;
537 shaderinfo.material = video::EMT_SOLID;
538 switch(material_type){
539 case TILE_MATERIAL_BASIC:
540 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
542 case TILE_MATERIAL_ALPHA:
543 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
545 case TILE_MATERIAL_LIQUID_TRANSPARENT:
546 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
548 case TILE_MATERIAL_LIQUID_OPAQUE:
549 shaderinfo.base_material = video::EMT_SOLID;
551 case TILE_MATERIAL_WAVING_LEAVES:
552 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
554 case TILE_MATERIAL_WAVING_PLANTS:
555 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
559 bool enable_shaders = g_settings->getBool("enable_shaders");
563 video::IVideoDriver* driver = device->getVideoDriver();
564 sanity_check(driver);
566 video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
568 errorstream<<"generate_shader(): "
569 "failed to generate \""<<name<<"\", "
570 "GPU programming not supported."
575 // Choose shader language depending on driver type and settings
577 std::string vertex_program;
578 std::string pixel_program;
579 std::string geometry_program;
581 load_shaders(name, sourcecache, driver->getDriverType(),
582 enable_shaders, vertex_program, pixel_program,
583 geometry_program, is_highlevel);
584 // Check hardware/driver support
585 if(vertex_program != "" &&
586 !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
587 !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
588 infostream<<"generate_shader(): vertex shaders disabled "
589 "because of missing driver/hardware support."
593 if(pixel_program != "" &&
594 !driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
595 !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
596 infostream<<"generate_shader(): pixel shaders disabled "
597 "because of missing driver/hardware support."
601 if(geometry_program != "" &&
602 !driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
603 infostream<<"generate_shader(): geometry shaders disabled "
604 "because of missing driver/hardware support."
606 geometry_program = "";
609 // If no shaders are used, don't make a separate material type
610 if(vertex_program == "" && pixel_program == "" && geometry_program == "")
613 // Create shaders header
614 std::string shaders_header = "#version 120\n";
616 static const char* drawTypes[] = {
623 "NDT_ALLFACES_OPTIONAL",
630 "NDT_GLASSLIKE_FRAMED",
632 "NDT_GLASSLIKE_FRAMED_OPTIONAL"
635 for (int i = 0; i < 14; i++){
636 shaders_header += "#define ";
637 shaders_header += drawTypes[i];
638 shaders_header += " ";
639 shaders_header += itos(i);
640 shaders_header += "\n";
643 static const char* materialTypes[] = {
644 "TILE_MATERIAL_BASIC",
645 "TILE_MATERIAL_ALPHA",
646 "TILE_MATERIAL_LIQUID_TRANSPARENT",
647 "TILE_MATERIAL_LIQUID_OPAQUE",
648 "TILE_MATERIAL_WAVING_LEAVES",
649 "TILE_MATERIAL_WAVING_PLANTS"
652 for (int i = 0; i < 6; i++){
653 shaders_header += "#define ";
654 shaders_header += materialTypes[i];
655 shaders_header += " ";
656 shaders_header += itos(i);
657 shaders_header += "\n";
660 shaders_header += "#define MATERIAL_TYPE ";
661 shaders_header += itos(material_type);
662 shaders_header += "\n";
663 shaders_header += "#define DRAW_TYPE ";
664 shaders_header += itos(drawtype);
665 shaders_header += "\n";
667 if (g_settings->getBool("generate_normalmaps")) {
668 shaders_header += "#define GENERATE_NORMALMAPS 1\n";
670 shaders_header += "#define GENERATE_NORMALMAPS 0\n";
672 shaders_header += "#define NORMALMAPS_STRENGTH ";
673 shaders_header += ftos(g_settings->getFloat("normalmaps_strength"));
674 shaders_header += "\n";
676 int smooth = (int)g_settings->getFloat("normalmaps_smooth");
679 sample_step = 0.0078125; // 1.0 / 128.0
682 sample_step = 0.00390625; // 1.0 / 256.0
685 sample_step = 0.001953125; // 1.0 / 512.0
688 sample_step = 0.0078125;
691 shaders_header += "#define SAMPLE_STEP ";
692 shaders_header += ftos(sample_step);
693 shaders_header += "\n";
695 if (g_settings->getBool("enable_bumpmapping"))
696 shaders_header += "#define ENABLE_BUMPMAPPING\n";
698 if (g_settings->getBool("enable_parallax_occlusion")){
699 int mode = g_settings->getFloat("parallax_occlusion_mode");
700 float scale = g_settings->getFloat("parallax_occlusion_scale");
701 float bias = g_settings->getFloat("parallax_occlusion_bias");
702 int iterations = g_settings->getFloat("parallax_occlusion_iterations");
703 shaders_header += "#define ENABLE_PARALLAX_OCCLUSION\n";
704 shaders_header += "#define PARALLAX_OCCLUSION_MODE ";
705 shaders_header += itos(mode);
706 shaders_header += "\n";
707 shaders_header += "#define PARALLAX_OCCLUSION_SCALE ";
708 shaders_header += ftos(scale);
709 shaders_header += "\n";
710 shaders_header += "#define PARALLAX_OCCLUSION_BIAS ";
711 shaders_header += ftos(bias);
712 shaders_header += "\n";
713 shaders_header += "#define PARALLAX_OCCLUSION_ITERATIONS ";
714 shaders_header += itos(iterations);
715 shaders_header += "\n";
718 shaders_header += "#define USE_NORMALMAPS ";
719 if (g_settings->getBool("enable_bumpmapping") || g_settings->getBool("enable_parallax_occlusion"))
720 shaders_header += "1\n";
722 shaders_header += "0\n";
724 if (g_settings->getBool("enable_waving_water")){
725 shaders_header += "#define ENABLE_WAVING_WATER 1\n";
726 shaders_header += "#define WATER_WAVE_HEIGHT ";
727 shaders_header += ftos(g_settings->getFloat("water_wave_height"));
728 shaders_header += "\n";
729 shaders_header += "#define WATER_WAVE_LENGTH ";
730 shaders_header += ftos(g_settings->getFloat("water_wave_length"));
731 shaders_header += "\n";
732 shaders_header += "#define WATER_WAVE_SPEED ";
733 shaders_header += ftos(g_settings->getFloat("water_wave_speed"));
734 shaders_header += "\n";
736 shaders_header += "#define ENABLE_WAVING_WATER 0\n";
739 shaders_header += "#define ENABLE_WAVING_LEAVES ";
740 if (g_settings->getBool("enable_waving_leaves"))
741 shaders_header += "1\n";
743 shaders_header += "0\n";
745 shaders_header += "#define ENABLE_WAVING_PLANTS ";
746 if (g_settings->getBool("enable_waving_plants"))
747 shaders_header += "1\n";
749 shaders_header += "0\n";
751 if (g_settings->getBool("tone_mapping"))
752 shaders_header += "#define ENABLE_TONE_MAPPING\n";
754 shaders_header += "#define FOG_START ";
755 shaders_header += ftos(rangelim(g_settings->getFloat("fog_start"), 0.0f, 0.99f));
756 shaders_header += "\n";
758 // Call addHighLevelShaderMaterial() or addShaderMaterial()
759 const c8* vertex_program_ptr = 0;
760 const c8* pixel_program_ptr = 0;
761 const c8* geometry_program_ptr = 0;
762 if (!vertex_program.empty()) {
763 vertex_program = shaders_header + vertex_program;
764 vertex_program_ptr = vertex_program.c_str();
766 if (!pixel_program.empty()) {
767 pixel_program = shaders_header + pixel_program;
768 pixel_program_ptr = pixel_program.c_str();
770 if (!geometry_program.empty()) {
771 geometry_program = shaders_header + geometry_program;
772 geometry_program_ptr = geometry_program.c_str();
774 ShaderCallback *cb = new ShaderCallback(setter_factories);
777 infostream<<"Compiling high level shaders for "<<name<<std::endl;
778 shadermat = gpu->addHighLevelShaderMaterial(
779 vertex_program_ptr, // Vertex shader program
780 "vertexMain", // Vertex shader entry point
781 video::EVST_VS_1_1, // Vertex shader version
782 pixel_program_ptr, // Pixel shader program
783 "pixelMain", // Pixel shader entry point
784 video::EPST_PS_1_2, // Pixel shader version
785 geometry_program_ptr, // Geometry shader program
786 "geometryMain", // Geometry shader entry point
787 video::EGST_GS_4_0, // Geometry shader version
788 scene::EPT_TRIANGLES, // Geometry shader input
789 scene::EPT_TRIANGLE_STRIP, // Geometry shader output
790 0, // Support maximum number of vertices
791 cb, // Set-constant callback
792 shaderinfo.base_material, // Base material
793 1 // Userdata passed to callback
796 errorstream<<"generate_shader(): "
797 "failed to generate \""<<name<<"\", "
798 "addHighLevelShaderMaterial failed."
800 dumpShaderProgram(warningstream, "Vertex", vertex_program);
801 dumpShaderProgram(warningstream, "Pixel", pixel_program);
802 dumpShaderProgram(warningstream, "Geometry", geometry_program);
808 infostream<<"Compiling assembly shaders for "<<name<<std::endl;
809 shadermat = gpu->addShaderMaterial(
810 vertex_program_ptr, // Vertex shader program
811 pixel_program_ptr, // Pixel shader program
812 cb, // Set-constant callback
813 shaderinfo.base_material, // Base material
814 0 // Userdata passed to callback
818 errorstream<<"generate_shader(): "
819 "failed to generate \""<<name<<"\", "
820 "addShaderMaterial failed."
822 dumpShaderProgram(warningstream, "Vertex", vertex_program);
823 dumpShaderProgram(warningstream,"Pixel", pixel_program);
828 callbacks.push_back(cb);
830 // HACK, TODO: investigate this better
831 // Grab the material renderer once more so minetest doesn't crash on exit
832 driver->getMaterialRenderer(shadermat)->grab();
834 // Apply the newly created material type
835 shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
839 void load_shaders(std::string name, SourceShaderCache *sourcecache,
840 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
841 std::string &vertex_program, std::string &pixel_program,
842 std::string &geometry_program, bool &is_highlevel)
846 geometry_program = "";
847 is_highlevel = false;
850 // Look for high level shaders
851 if(drivertype == video::EDT_DIRECT3D9){
853 // (All shaders in one file)
854 vertex_program = sourcecache->getOrLoad(name, "d3d9.hlsl");
855 pixel_program = vertex_program;
856 geometry_program = vertex_program;
858 else if(drivertype == video::EDT_OPENGL){
860 vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.glsl");
861 pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.glsl");
862 geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl");
864 if(vertex_program != "" || pixel_program != "" || geometry_program != ""){
872 void dumpShaderProgram(std::ostream &output_stream,
873 const std::string &program_type, 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 <<