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,
56 const std::string &filename)
58 std::string combined = name_of_shader + DIR_DELIM + filename;
63 bool incache = g_shadername_to_path_cache.get(combined, &fullpath);
68 Check from shader_path
70 std::string shader_path = g_settings->get("shader_path");
71 if (!shader_path.empty()) {
72 std::string testpath = shader_path + DIR_DELIM + combined;
73 if(fs::PathExists(testpath))
78 Check from default data directory
80 if (fullpath.empty()) {
81 std::string rel_path = std::string("client") + DIR_DELIM
82 + "shaders" + DIR_DELIM
83 + name_of_shader + DIR_DELIM
85 std::string testpath = porting::path_share + DIR_DELIM + rel_path;
86 if(fs::PathExists(testpath))
90 // Add to cache (also an empty result is cached)
91 g_shadername_to_path_cache.set(combined, fullpath);
98 SourceShaderCache: A cache used for storing source shaders.
101 class SourceShaderCache
104 void insert(const std::string &name_of_shader, const std::string &filename,
105 const std::string &program, bool prefer_local)
107 std::string combined = name_of_shader + DIR_DELIM + filename;
108 // Try to use local shader instead if asked to
110 std::string path = getShaderPath(name_of_shader, filename);
112 std::string p = readFile(path);
114 m_programs[combined] = p;
119 m_programs[combined] = program;
122 std::string get(const std::string &name_of_shader,
123 const std::string &filename)
125 std::string combined = name_of_shader + DIR_DELIM + filename;
126 StringMap::iterator n = m_programs.find(combined);
127 if (n != m_programs.end())
132 // Primarily fetches from cache, secondarily tries to read from filesystem
133 std::string getOrLoad(const std::string &name_of_shader,
134 const std::string &filename)
136 std::string combined = name_of_shader + DIR_DELIM + filename;
137 StringMap::iterator n = m_programs.find(combined);
138 if (n != m_programs.end())
140 std::string path = getShaderPath(name_of_shader, filename);
142 infostream << "SourceShaderCache::getOrLoad(): No path found for \""
143 << combined << "\"" << std::endl;
146 infostream << "SourceShaderCache::getOrLoad(): Loading path \""
147 << path << "\"" << std::endl;
148 std::string p = readFile(path);
150 m_programs[combined] = p;
156 StringMap m_programs;
158 std::string readFile(const std::string &path)
160 std::ifstream is(path.c_str(), std::ios::binary);
163 std::ostringstream tmp_os;
164 tmp_os << is.rdbuf();
171 ShaderCallback: Sets constants that can be used in shaders
174 class ShaderCallback : public video::IShaderConstantSetCallBack
176 std::vector<IShaderConstantSetter*> m_setters;
179 ShaderCallback(const std::vector<IShaderConstantSetterFactory *> &factories)
181 for (IShaderConstantSetterFactory *factory : factories)
182 m_setters.push_back(factory->create());
187 for (IShaderConstantSetter *setter : m_setters)
191 virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData)
193 video::IVideoDriver *driver = services->getVideoDriver();
194 sanity_check(driver != NULL);
196 bool is_highlevel = userData;
198 for (IShaderConstantSetter *setter : m_setters)
199 setter->onSetConstants(services, is_highlevel);
205 MainShaderConstantSetter: Set basic constants required for almost everything
208 class MainShaderConstantSetter : public IShaderConstantSetter
210 CachedVertexShaderSetting<float, 16> m_world_view_proj;
211 CachedVertexShaderSetting<float, 16> m_world;
214 MainShaderConstantSetter() :
215 m_world_view_proj("mWorldViewProj"),
218 ~MainShaderConstantSetter() = default;
220 virtual void onSetConstants(video::IMaterialRendererServices *services,
223 video::IVideoDriver *driver = services->getVideoDriver();
224 sanity_check(driver);
227 core::matrix4 worldViewProj;
228 worldViewProj = driver->getTransform(video::ETS_PROJECTION);
229 worldViewProj *= driver->getTransform(video::ETS_VIEW);
230 worldViewProj *= driver->getTransform(video::ETS_WORLD);
232 m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
234 services->setVertexShaderConstant(worldViewProj.pointer(), 0, 4);
237 core::matrix4 world = driver->getTransform(video::ETS_WORLD);
239 m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
241 services->setVertexShaderConstant(world.pointer(), 4, 4);
247 class MainShaderConstantSetterFactory : public IShaderConstantSetterFactory
250 virtual IShaderConstantSetter* create()
251 { return new MainShaderConstantSetter(); }
259 class ShaderSource : public IWritableShaderSource
266 - If shader material specified by name is found from cache,
267 return the cached id.
268 - Otherwise generate the shader material, add to cache and return id.
270 The id 0 points to a null shader. Its material is EMT_SOLID.
272 u32 getShaderIdDirect(const std::string &name,
273 const u8 material_type, const u8 drawtype);
276 If shader specified by the name pointed by the id doesn't
277 exist, create it, then return id.
279 Can be called from any thread. If called from some other thread
280 and not found in cache, the call is queued to the main thread
284 u32 getShader(const std::string &name,
285 const u8 material_type, const u8 drawtype);
287 ShaderInfo getShaderInfo(u32 id);
289 // Processes queued shader requests from other threads.
290 // Shall be called from the main thread.
293 // Insert a shader program into the cache without touching the
294 // filesystem. Shall be called from the main thread.
295 void insertSourceShader(const std::string &name_of_shader,
296 const std::string &filename, const std::string &program);
298 // Rebuild shaders from the current set of source shaders
299 // Shall be called from the main thread.
300 void rebuildShaders();
302 void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter)
304 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,
341 u8 material_type, u8 drawtype, 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(const std::string &name,
375 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>
399 result = result_queue.pop_frontNoEx();
401 if (result.key == name) {
405 errorstream << "Got shader with invalid name: " << result.key << std::endl;
408 infostream << "getShader(): Failed" << std::endl;
414 This method generates all the shaders
416 u32 ShaderSource::getShaderIdDirect(const std::string &name,
417 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"<<std::endl;
444 ShaderInfo info = generate_shader(name, material_type, drawtype,
445 m_callbacks, m_setter_factories, &m_sourcecache);
448 Add shader to caches (add dummy shaders too)
451 MutexAutoLock lock(m_shaderinfo_cache_mutex);
453 u32 id = m_shaderinfo_cache.size();
454 m_shaderinfo_cache.push_back(info);
456 infostream<<"getShaderIdDirect(): "
457 <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;
463 ShaderInfo ShaderSource::getShaderInfo(u32 id)
465 MutexAutoLock lock(m_shaderinfo_cache_mutex);
467 if(id >= m_shaderinfo_cache.size())
470 return m_shaderinfo_cache[id];
473 void ShaderSource::processQueue()
479 void ShaderSource::insertSourceShader(const std::string &name_of_shader,
480 const std::string &filename, const std::string &program)
482 /*infostream<<"ShaderSource::insertSourceShader(): "
483 "name_of_shader=\""<<name_of_shader<<"\", "
484 "filename=\""<<filename<<"\""<<std::endl;*/
486 sanity_check(std::this_thread::get_id() == m_main_thread);
488 m_sourcecache.insert(name_of_shader, filename, program, true);
491 void ShaderSource::rebuildShaders()
493 MutexAutoLock lock(m_shaderinfo_cache_mutex);
495 /*// Oh well... just clear everything, they'll load sometime.
496 m_shaderinfo_cache.clear();
497 m_name_to_id.clear();*/
500 FIXME: Old shader materials can't be deleted in Irrlicht,
502 (This would be nice to do in the destructor too)
506 for (ShaderInfo &i : m_shaderinfo_cache) {
507 ShaderInfo *info = &i;
508 if (!info->name.empty()) {
509 *info = generate_shader(info->name, info->material_type,
510 info->drawtype, m_callbacks,
511 m_setter_factories, &m_sourcecache);
517 ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtype,
518 std::vector<ShaderCallback *> &callbacks,
519 const std::vector<IShaderConstantSetterFactory *> &setter_factories,
520 SourceShaderCache *sourcecache)
522 ShaderInfo shaderinfo;
523 shaderinfo.name = name;
524 shaderinfo.material_type = material_type;
525 shaderinfo.drawtype = drawtype;
526 shaderinfo.material = video::EMT_SOLID;
527 switch (material_type) {
528 case TILE_MATERIAL_OPAQUE:
529 case TILE_MATERIAL_LIQUID_OPAQUE:
530 case TILE_MATERIAL_WAVING_LIQUID_OPAQUE:
531 shaderinfo.base_material = video::EMT_SOLID;
533 case TILE_MATERIAL_ALPHA:
534 case TILE_MATERIAL_LIQUID_TRANSPARENT:
535 case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
536 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
538 case TILE_MATERIAL_BASIC:
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 \""<<name<<"\", "
556 "GPU programming not supported."
561 // Choose shader language depending on driver type and settings
563 std::string vertex_program;
564 std::string pixel_program;
565 std::string geometry_program;
567 load_shaders(name, sourcecache, driver->getDriverType(),
568 enable_shaders, vertex_program, pixel_program,
569 geometry_program, is_highlevel);
570 // Check hardware/driver support
571 if (!vertex_program.empty() &&
572 !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
573 !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
574 infostream<<"generate_shader(): vertex shaders disabled "
575 "because of missing driver/hardware support."
579 if (!pixel_program.empty() &&
580 !driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
581 !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
582 infostream<<"generate_shader(): pixel shaders disabled "
583 "because of missing driver/hardware support."
587 if (!geometry_program.empty() &&
588 !driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
589 infostream<<"generate_shader(): geometry shaders disabled "
590 "because of missing driver/hardware support."
592 geometry_program = "";
595 // If no shaders are used, don't make a separate material type
596 if (vertex_program.empty() && pixel_program.empty() && geometry_program.empty())
599 // Create shaders header
600 std::string shaders_header = "#version 120\n";
602 static const char* drawTypes[] = {
609 "NDT_ALLFACES_OPTIONAL",
616 "NDT_GLASSLIKE_FRAMED",
618 "NDT_GLASSLIKE_FRAMED_OPTIONAL",
619 "NDT_PLANTLIKE_ROOTED",
622 for (int i = 0; i < 14; i++){
623 shaders_header += "#define ";
624 shaders_header += drawTypes[i];
625 shaders_header += " ";
626 shaders_header += itos(i);
627 shaders_header += "\n";
630 static const char* materialTypes[] = {
631 "TILE_MATERIAL_BASIC",
632 "TILE_MATERIAL_ALPHA",
633 "TILE_MATERIAL_LIQUID_TRANSPARENT",
634 "TILE_MATERIAL_LIQUID_OPAQUE",
635 "TILE_MATERIAL_WAVING_LEAVES",
636 "TILE_MATERIAL_WAVING_PLANTS",
637 "TILE_MATERIAL_OPAQUE",
638 "TILE_MATERIAL_WAVING_LIQUID_BASIC",
639 "TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT",
640 "TILE_MATERIAL_WAVING_LIQUID_OPAQUE",
643 for (int i = 0; i < 10; i++){
644 shaders_header += "#define ";
645 shaders_header += materialTypes[i];
646 shaders_header += " ";
647 shaders_header += itos(i);
648 shaders_header += "\n";
651 shaders_header += "#define MATERIAL_TYPE ";
652 shaders_header += itos(material_type);
653 shaders_header += "\n";
654 shaders_header += "#define DRAW_TYPE ";
655 shaders_header += itos(drawtype);
656 shaders_header += "\n";
658 if (g_settings->getBool("generate_normalmaps")) {
659 shaders_header += "#define GENERATE_NORMALMAPS 1\n";
661 shaders_header += "#define GENERATE_NORMALMAPS 0\n";
663 shaders_header += "#define NORMALMAPS_STRENGTH ";
664 shaders_header += ftos(g_settings->getFloat("normalmaps_strength"));
665 shaders_header += "\n";
667 int smooth = (int)g_settings->getFloat("normalmaps_smooth");
670 sample_step = 0.0078125; // 1.0 / 128.0
673 sample_step = 0.00390625; // 1.0 / 256.0
676 sample_step = 0.001953125; // 1.0 / 512.0
679 sample_step = 0.0078125;
682 shaders_header += "#define SAMPLE_STEP ";
683 shaders_header += ftos(sample_step);
684 shaders_header += "\n";
686 if (g_settings->getBool("enable_bumpmapping"))
687 shaders_header += "#define ENABLE_BUMPMAPPING\n";
689 if (g_settings->getBool("enable_parallax_occlusion")){
690 int mode = g_settings->getFloat("parallax_occlusion_mode");
691 float scale = g_settings->getFloat("parallax_occlusion_scale");
692 float bias = g_settings->getFloat("parallax_occlusion_bias");
693 int iterations = g_settings->getFloat("parallax_occlusion_iterations");
694 shaders_header += "#define ENABLE_PARALLAX_OCCLUSION\n";
695 shaders_header += "#define PARALLAX_OCCLUSION_MODE ";
696 shaders_header += itos(mode);
697 shaders_header += "\n";
698 shaders_header += "#define PARALLAX_OCCLUSION_SCALE ";
699 shaders_header += ftos(scale);
700 shaders_header += "\n";
701 shaders_header += "#define PARALLAX_OCCLUSION_BIAS ";
702 shaders_header += ftos(bias);
703 shaders_header += "\n";
704 shaders_header += "#define PARALLAX_OCCLUSION_ITERATIONS ";
705 shaders_header += itos(iterations);
706 shaders_header += "\n";
709 shaders_header += "#define USE_NORMALMAPS ";
710 if (g_settings->getBool("enable_bumpmapping") || g_settings->getBool("enable_parallax_occlusion"))
711 shaders_header += "1\n";
713 shaders_header += "0\n";
715 if (g_settings->getBool("enable_waving_water")){
716 shaders_header += "#define ENABLE_WAVING_WATER 1\n";
717 shaders_header += "#define WATER_WAVE_HEIGHT ";
718 shaders_header += ftos(g_settings->getFloat("water_wave_height"));
719 shaders_header += "\n";
720 shaders_header += "#define WATER_WAVE_LENGTH ";
721 shaders_header += ftos(g_settings->getFloat("water_wave_length"));
722 shaders_header += "\n";
723 shaders_header += "#define WATER_WAVE_SPEED ";
724 shaders_header += ftos(g_settings->getFloat("water_wave_speed"));
725 shaders_header += "\n";
727 shaders_header += "#define ENABLE_WAVING_WATER 0\n";
730 shaders_header += "#define ENABLE_WAVING_LEAVES ";
731 if (g_settings->getBool("enable_waving_leaves"))
732 shaders_header += "1\n";
734 shaders_header += "0\n";
736 shaders_header += "#define ENABLE_WAVING_PLANTS ";
737 if (g_settings->getBool("enable_waving_plants"))
738 shaders_header += "1\n";
740 shaders_header += "0\n";
742 if (g_settings->getBool("tone_mapping"))
743 shaders_header += "#define ENABLE_TONE_MAPPING\n";
745 shaders_header += "#define FOG_START ";
746 shaders_header += ftos(rangelim(g_settings->getFloat("fog_start"), 0.0f, 0.99f));
747 shaders_header += "\n";
749 // Call addHighLevelShaderMaterial() or addShaderMaterial()
750 const c8* vertex_program_ptr = 0;
751 const c8* pixel_program_ptr = 0;
752 const c8* geometry_program_ptr = 0;
753 if (!vertex_program.empty()) {
754 vertex_program = shaders_header + vertex_program;
755 vertex_program_ptr = vertex_program.c_str();
757 if (!pixel_program.empty()) {
758 pixel_program = shaders_header + pixel_program;
759 pixel_program_ptr = pixel_program.c_str();
761 if (!geometry_program.empty()) {
762 geometry_program = shaders_header + geometry_program;
763 geometry_program_ptr = geometry_program.c_str();
765 ShaderCallback *cb = new ShaderCallback(setter_factories);
768 infostream<<"Compiling high level shaders for "<<name<<std::endl;
769 shadermat = gpu->addHighLevelShaderMaterial(
770 vertex_program_ptr, // Vertex shader program
771 "vertexMain", // Vertex shader entry point
772 video::EVST_VS_1_1, // Vertex shader version
773 pixel_program_ptr, // Pixel shader program
774 "pixelMain", // Pixel shader entry point
775 video::EPST_PS_1_2, // Pixel shader version
776 geometry_program_ptr, // Geometry shader program
777 "geometryMain", // Geometry shader entry point
778 video::EGST_GS_4_0, // Geometry shader version
779 scene::EPT_TRIANGLES, // Geometry shader input
780 scene::EPT_TRIANGLE_STRIP, // Geometry shader output
781 0, // Support maximum number of vertices
782 cb, // Set-constant callback
783 shaderinfo.base_material, // Base material
784 1 // Userdata passed to callback
787 errorstream<<"generate_shader(): "
788 "failed to generate \""<<name<<"\", "
789 "addHighLevelShaderMaterial failed."
791 dumpShaderProgram(warningstream, "Vertex", vertex_program);
792 dumpShaderProgram(warningstream, "Pixel", pixel_program);
793 dumpShaderProgram(warningstream, "Geometry", geometry_program);
799 infostream<<"Compiling assembly shaders for "<<name<<std::endl;
800 shadermat = gpu->addShaderMaterial(
801 vertex_program_ptr, // Vertex shader program
802 pixel_program_ptr, // Pixel shader program
803 cb, // Set-constant callback
804 shaderinfo.base_material, // Base material
805 0 // Userdata passed to callback
809 errorstream<<"generate_shader(): "
810 "failed to generate \""<<name<<"\", "
811 "addShaderMaterial failed."
813 dumpShaderProgram(warningstream, "Vertex", vertex_program);
814 dumpShaderProgram(warningstream,"Pixel", pixel_program);
819 callbacks.push_back(cb);
821 // HACK, TODO: investigate this better
822 // Grab the material renderer once more so minetest doesn't crash on exit
823 driver->getMaterialRenderer(shadermat)->grab();
825 // Apply the newly created material type
826 shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
830 void load_shaders(const std::string &name, SourceShaderCache *sourcecache,
831 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
832 std::string &vertex_program, std::string &pixel_program,
833 std::string &geometry_program, bool &is_highlevel)
837 geometry_program = "";
838 is_highlevel = false;
841 // Look for high level shaders
842 if(drivertype == video::EDT_DIRECT3D9){
844 // (All shaders in one file)
845 vertex_program = sourcecache->getOrLoad(name, "d3d9.hlsl");
846 pixel_program = vertex_program;
847 geometry_program = vertex_program;
849 else if(drivertype == video::EDT_OPENGL){
851 vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.glsl");
852 pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.glsl");
853 geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl");
855 if (!vertex_program.empty() || !pixel_program.empty() || !geometry_program.empty()){
863 void dumpShaderProgram(std::ostream &output_stream,
864 const std::string &program_type, const std::string &program)
866 output_stream << program_type << " shader program:" << std::endl <<
867 "----------------------------------" << std::endl;
871 while ((pos = program.find('\n', prev)) != std::string::npos) {
872 output_stream << line++ << ": "<< program.substr(prev, pos - prev) <<
876 output_stream << line << ": " << program.substr(prev) << std::endl <<
877 "End of " << program_type << " shader program." << std::endl <<