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;
59 std::string fullpath = "";
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");
73 std::string testpath = shader_path + DIR_DELIM + combined;
74 if(fs::PathExists(testpath))
79 Check from default data directory
83 std::string rel_path = std::string("client") + DIR_DELIM
84 + "shaders" + DIR_DELIM
85 + name_of_shader + DIR_DELIM
87 std::string testpath = porting::path_share + DIR_DELIM + rel_path;
88 if(fs::PathExists(testpath))
92 // Add to cache (also an empty result is cached)
93 g_shadername_to_path_cache.set(combined, fullpath);
100 SourceShaderCache: A cache used for storing source shaders.
103 class SourceShaderCache
106 void insert(const std::string &name_of_shader, const std::string &filename,
107 const std::string &program, bool prefer_local)
109 std::string combined = name_of_shader + DIR_DELIM + filename;
110 // Try to use local shader instead if asked to
112 std::string path = getShaderPath(name_of_shader, filename);
114 std::string p = readFile(path);
116 m_programs[combined] = p;
121 m_programs[combined] = program;
124 std::string get(const std::string &name_of_shader,
125 const std::string &filename)
127 std::string combined = name_of_shader + DIR_DELIM + filename;
128 StringMap::iterator n = m_programs.find(combined);
129 if (n != m_programs.end())
134 // Primarily fetches from cache, secondarily tries to read from filesystem
135 std::string getOrLoad(const std::string &name_of_shader,
136 const std::string &filename)
138 std::string combined = name_of_shader + DIR_DELIM + filename;
139 StringMap::iterator n = m_programs.find(combined);
140 if (n != m_programs.end())
142 std::string path = getShaderPath(name_of_shader, filename);
144 infostream << "SourceShaderCache::getOrLoad(): No path found for \""
145 << combined << "\"" << std::endl;
148 infostream << "SourceShaderCache::getOrLoad(): Loading path \""
149 << path << "\"" << std::endl;
150 std::string p = readFile(path);
152 m_programs[combined] = p;
158 StringMap m_programs;
160 std::string readFile(const std::string &path)
162 std::ifstream is(path.c_str(), std::ios::binary);
165 std::ostringstream tmp_os;
166 tmp_os << is.rdbuf();
173 ShaderCallback: Sets constants that can be used in shaders
176 class ShaderCallback : public video::IShaderConstantSetCallBack
178 std::vector<IShaderConstantSetter*> m_setters;
181 ShaderCallback(const std::vector<IShaderConstantSetterFactory *> &factories)
183 for (u32 i = 0; i < factories.size(); ++i)
184 m_setters.push_back(factories[i]->create());
189 for (u32 i = 0; i < m_setters.size(); ++i)
193 virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData)
195 video::IVideoDriver *driver = services->getVideoDriver();
196 sanity_check(driver != NULL);
198 bool is_highlevel = userData;
200 for (u32 i = 0; i < m_setters.size(); ++i)
201 m_setters[i]->onSetConstants(services, is_highlevel);
207 MainShaderConstantSetter: Set basic constants required for almost everything
210 class MainShaderConstantSetter : public IShaderConstantSetter
212 CachedVertexShaderSetting<float, 16> m_world_view_proj;
213 CachedVertexShaderSetting<float, 16> m_world;
216 MainShaderConstantSetter() :
217 m_world_view_proj("mWorldViewProj"),
220 ~MainShaderConstantSetter() {}
222 virtual void onSetConstants(video::IMaterialRendererServices *services,
225 video::IVideoDriver *driver = services->getVideoDriver();
226 sanity_check(driver);
229 core::matrix4 worldViewProj;
230 worldViewProj = driver->getTransform(video::ETS_PROJECTION);
231 worldViewProj *= driver->getTransform(video::ETS_VIEW);
232 worldViewProj *= driver->getTransform(video::ETS_WORLD);
234 m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
236 services->setVertexShaderConstant(worldViewProj.pointer(), 0, 4);
239 core::matrix4 world = driver->getTransform(video::ETS_WORLD);
241 m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
243 services->setVertexShaderConstant(world.pointer(), 4, 4);
249 class MainShaderConstantSetterFactory : public IShaderConstantSetterFactory
252 virtual IShaderConstantSetter* create()
253 { 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,
275 const u8 material_type, const u8 drawtype);
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,
287 const u8 material_type, const u8 drawtype);
289 ShaderInfo getShaderInfo(u32 id);
291 // Processes queued shader requests from other threads.
292 // Shall be called from the main thread.
295 // Insert a shader program into the cache without touching the
296 // filesystem. Shall be called from the main thread.
297 void insertSourceShader(const std::string &name_of_shader,
298 const std::string &filename, const std::string &program);
300 // Rebuild shaders from the current set of source shaders
301 // Shall be called from the main thread.
302 void rebuildShaders();
304 void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter)
306 m_setter_factories.push_back(setter);
311 // The id of the thread that is allowed to use irrlicht directly
312 std::thread::id m_main_thread;
314 // Cache of source shaders
315 // This should be only accessed from the main thread
316 SourceShaderCache m_sourcecache;
318 // A shader id is index in this array.
319 // The first position contains a dummy shader.
320 std::vector<ShaderInfo> m_shaderinfo_cache;
321 // The former container is behind this mutex
322 std::mutex m_shaderinfo_cache_mutex;
324 // Queued shader fetches (to be processed by the main thread)
325 RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
327 // Global constant setter factories
328 std::vector<IShaderConstantSetterFactory *> m_setter_factories;
331 std::vector<ShaderCallback *> m_callbacks;
334 IWritableShaderSource *createShaderSource()
336 return new ShaderSource();
340 Generate shader given the shader name.
342 ShaderInfo generate_shader(const std::string &name,
343 u8 material_type, u8 drawtype, std::vector<ShaderCallback *> &callbacks,
344 const std::vector<IShaderConstantSetterFactory *> &setter_factories,
345 SourceShaderCache *sourcecache);
350 void load_shaders(std::string name, SourceShaderCache *sourcecache,
351 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
352 std::string &vertex_program, std::string &pixel_program,
353 std::string &geometry_program, bool &is_highlevel);
355 ShaderSource::ShaderSource()
357 m_main_thread = std::this_thread::get_id();
359 // Add a dummy ShaderInfo as the first index, named ""
360 m_shaderinfo_cache.push_back(ShaderInfo());
362 // Add main global constant setter
363 addShaderConstantSetterFactory(new MainShaderConstantSetterFactory());
366 ShaderSource::~ShaderSource()
368 for (std::vector<ShaderCallback *>::iterator iter = m_callbacks.begin();
369 iter != m_callbacks.end(); ++iter) {
372 for (std::vector<IShaderConstantSetterFactory *>::iterator iter = m_setter_factories.begin();
373 iter != m_setter_factories.end(); ++iter) {
378 u32 ShaderSource::getShader(const std::string &name,
379 const u8 material_type, const u8 drawtype)
385 if (std::this_thread::get_id() == m_main_thread) {
386 return getShaderIdDirect(name, material_type, drawtype);
388 /*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/
390 // We're gonna ask the result to be put into here
392 static ResultQueue<std::string, u32, u8, u8> result_queue;
394 // Throw a request in
395 m_get_shader_queue.add(name, 0, 0, &result_queue);
397 /* infostream<<"Waiting for shader from main thread, name=\""
398 <<name<<"\""<<std::endl;*/
401 GetResult<std::string, u32, u8, u8>
402 result = result_queue.pop_frontNoEx();
404 if (result.key == name) {
408 errorstream << "Got shader with invalid name: " << result.key << std::endl;
414 infostream<<"getShader(): Failed"<<std::endl;
420 This method generates all the shaders
422 u32 ShaderSource::getShaderIdDirect(const std::string &name,
423 const u8 material_type, const u8 drawtype)
425 //infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
427 // Empty name means shader 0
429 infostream<<"getShaderIdDirect(): name is empty"<<std::endl;
433 // Check if already have such instance
434 for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
435 ShaderInfo *info = &m_shaderinfo_cache[i];
436 if(info->name == name && info->material_type == material_type &&
437 info->drawtype == drawtype)
442 Calling only allowed from main thread
444 if (std::this_thread::get_id() != m_main_thread) {
445 errorstream<<"ShaderSource::getShaderIdDirect() "
446 "called not from main thread"<<std::endl;
450 ShaderInfo info = generate_shader(name, material_type, drawtype,
451 m_callbacks, m_setter_factories, &m_sourcecache);
454 Add shader to caches (add dummy shaders too)
457 MutexAutoLock lock(m_shaderinfo_cache_mutex);
459 u32 id = m_shaderinfo_cache.size();
460 m_shaderinfo_cache.push_back(info);
462 infostream<<"getShaderIdDirect(): "
463 <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;
469 ShaderInfo ShaderSource::getShaderInfo(u32 id)
471 MutexAutoLock lock(m_shaderinfo_cache_mutex);
473 if(id >= m_shaderinfo_cache.size())
476 return m_shaderinfo_cache[id];
479 void ShaderSource::processQueue()
485 void ShaderSource::insertSourceShader(const std::string &name_of_shader,
486 const std::string &filename, const std::string &program)
488 /*infostream<<"ShaderSource::insertSourceShader(): "
489 "name_of_shader=\""<<name_of_shader<<"\", "
490 "filename=\""<<filename<<"\""<<std::endl;*/
492 sanity_check(std::this_thread::get_id() == m_main_thread);
494 m_sourcecache.insert(name_of_shader, filename, program, true);
497 void ShaderSource::rebuildShaders()
499 MutexAutoLock lock(m_shaderinfo_cache_mutex);
501 /*// Oh well... just clear everything, they'll load sometime.
502 m_shaderinfo_cache.clear();
503 m_name_to_id.clear();*/
506 FIXME: Old shader materials can't be deleted in Irrlicht,
508 (This would be nice to do in the destructor too)
512 for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
513 ShaderInfo *info = &m_shaderinfo_cache[i];
514 if(info->name != ""){
515 *info = generate_shader(info->name, info->material_type,
516 info->drawtype, m_callbacks,
517 m_setter_factories, &m_sourcecache);
523 ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtype,
524 std::vector<ShaderCallback *> &callbacks,
525 const std::vector<IShaderConstantSetterFactory *> &setter_factories,
526 SourceShaderCache *sourcecache)
528 ShaderInfo shaderinfo;
529 shaderinfo.name = name;
530 shaderinfo.material_type = material_type;
531 shaderinfo.drawtype = drawtype;
532 shaderinfo.material = video::EMT_SOLID;
533 switch (material_type) {
534 case TILE_MATERIAL_BASIC:
535 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
537 case TILE_MATERIAL_ALPHA:
538 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
540 case TILE_MATERIAL_LIQUID_TRANSPARENT:
541 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
543 case TILE_MATERIAL_LIQUID_OPAQUE:
544 shaderinfo.base_material = video::EMT_SOLID;
546 case TILE_MATERIAL_WAVING_LEAVES:
547 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
549 case TILE_MATERIAL_WAVING_PLANTS:
550 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
556 bool enable_shaders = g_settings->getBool("enable_shaders");
560 video::IVideoDriver *driver = RenderingEngine::get_video_driver();
562 video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
564 errorstream<<"generate_shader(): "
565 "failed to generate \""<<name<<"\", "
566 "GPU programming not supported."
571 // Choose shader language depending on driver type and settings
573 std::string vertex_program;
574 std::string pixel_program;
575 std::string geometry_program;
577 load_shaders(name, sourcecache, driver->getDriverType(),
578 enable_shaders, vertex_program, pixel_program,
579 geometry_program, is_highlevel);
580 // Check hardware/driver support
581 if(vertex_program != "" &&
582 !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
583 !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
584 infostream<<"generate_shader(): vertex shaders disabled "
585 "because of missing driver/hardware support."
589 if(pixel_program != "" &&
590 !driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
591 !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
592 infostream<<"generate_shader(): pixel shaders disabled "
593 "because of missing driver/hardware support."
597 if(geometry_program != "" &&
598 !driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
599 infostream<<"generate_shader(): geometry shaders disabled "
600 "because of missing driver/hardware support."
602 geometry_program = "";
605 // If no shaders are used, don't make a separate material type
606 if(vertex_program == "" && pixel_program == "" && geometry_program == "")
609 // Create shaders header
610 std::string shaders_header = "#version 120\n";
612 static const char* drawTypes[] = {
619 "NDT_ALLFACES_OPTIONAL",
626 "NDT_GLASSLIKE_FRAMED",
628 "NDT_GLASSLIKE_FRAMED_OPTIONAL"
631 for (int i = 0; i < 14; i++){
632 shaders_header += "#define ";
633 shaders_header += drawTypes[i];
634 shaders_header += " ";
635 shaders_header += itos(i);
636 shaders_header += "\n";
639 static const char* materialTypes[] = {
640 "TILE_MATERIAL_BASIC",
641 "TILE_MATERIAL_ALPHA",
642 "TILE_MATERIAL_LIQUID_TRANSPARENT",
643 "TILE_MATERIAL_LIQUID_OPAQUE",
644 "TILE_MATERIAL_WAVING_LEAVES",
645 "TILE_MATERIAL_WAVING_PLANTS"
648 for (int i = 0; i < 6; i++){
649 shaders_header += "#define ";
650 shaders_header += materialTypes[i];
651 shaders_header += " ";
652 shaders_header += itos(i);
653 shaders_header += "\n";
656 shaders_header += "#define MATERIAL_TYPE ";
657 shaders_header += itos(material_type);
658 shaders_header += "\n";
659 shaders_header += "#define DRAW_TYPE ";
660 shaders_header += itos(drawtype);
661 shaders_header += "\n";
663 if (g_settings->getBool("generate_normalmaps")) {
664 shaders_header += "#define GENERATE_NORMALMAPS 1\n";
666 shaders_header += "#define GENERATE_NORMALMAPS 0\n";
668 shaders_header += "#define NORMALMAPS_STRENGTH ";
669 shaders_header += ftos(g_settings->getFloat("normalmaps_strength"));
670 shaders_header += "\n";
672 int smooth = (int)g_settings->getFloat("normalmaps_smooth");
675 sample_step = 0.0078125; // 1.0 / 128.0
678 sample_step = 0.00390625; // 1.0 / 256.0
681 sample_step = 0.001953125; // 1.0 / 512.0
684 sample_step = 0.0078125;
687 shaders_header += "#define SAMPLE_STEP ";
688 shaders_header += ftos(sample_step);
689 shaders_header += "\n";
691 if (g_settings->getBool("enable_bumpmapping"))
692 shaders_header += "#define ENABLE_BUMPMAPPING\n";
694 if (g_settings->getBool("enable_parallax_occlusion")){
695 int mode = g_settings->getFloat("parallax_occlusion_mode");
696 float scale = g_settings->getFloat("parallax_occlusion_scale");
697 float bias = g_settings->getFloat("parallax_occlusion_bias");
698 int iterations = g_settings->getFloat("parallax_occlusion_iterations");
699 shaders_header += "#define ENABLE_PARALLAX_OCCLUSION\n";
700 shaders_header += "#define PARALLAX_OCCLUSION_MODE ";
701 shaders_header += itos(mode);
702 shaders_header += "\n";
703 shaders_header += "#define PARALLAX_OCCLUSION_SCALE ";
704 shaders_header += ftos(scale);
705 shaders_header += "\n";
706 shaders_header += "#define PARALLAX_OCCLUSION_BIAS ";
707 shaders_header += ftos(bias);
708 shaders_header += "\n";
709 shaders_header += "#define PARALLAX_OCCLUSION_ITERATIONS ";
710 shaders_header += itos(iterations);
711 shaders_header += "\n";
714 shaders_header += "#define USE_NORMALMAPS ";
715 if (g_settings->getBool("enable_bumpmapping") || g_settings->getBool("enable_parallax_occlusion"))
716 shaders_header += "1\n";
718 shaders_header += "0\n";
720 if (g_settings->getBool("enable_waving_water")){
721 shaders_header += "#define ENABLE_WAVING_WATER 1\n";
722 shaders_header += "#define WATER_WAVE_HEIGHT ";
723 shaders_header += ftos(g_settings->getFloat("water_wave_height"));
724 shaders_header += "\n";
725 shaders_header += "#define WATER_WAVE_LENGTH ";
726 shaders_header += ftos(g_settings->getFloat("water_wave_length"));
727 shaders_header += "\n";
728 shaders_header += "#define WATER_WAVE_SPEED ";
729 shaders_header += ftos(g_settings->getFloat("water_wave_speed"));
730 shaders_header += "\n";
732 shaders_header += "#define ENABLE_WAVING_WATER 0\n";
735 shaders_header += "#define ENABLE_WAVING_LEAVES ";
736 if (g_settings->getBool("enable_waving_leaves"))
737 shaders_header += "1\n";
739 shaders_header += "0\n";
741 shaders_header += "#define ENABLE_WAVING_PLANTS ";
742 if (g_settings->getBool("enable_waving_plants"))
743 shaders_header += "1\n";
745 shaders_header += "0\n";
747 if (g_settings->getBool("tone_mapping"))
748 shaders_header += "#define ENABLE_TONE_MAPPING\n";
750 shaders_header += "#define FOG_START ";
751 shaders_header += ftos(rangelim(g_settings->getFloat("fog_start"), 0.0f, 0.99f));
752 shaders_header += "\n";
754 // Call addHighLevelShaderMaterial() or addShaderMaterial()
755 const c8* vertex_program_ptr = 0;
756 const c8* pixel_program_ptr = 0;
757 const c8* geometry_program_ptr = 0;
758 if (!vertex_program.empty()) {
759 vertex_program = shaders_header + vertex_program;
760 vertex_program_ptr = vertex_program.c_str();
762 if (!pixel_program.empty()) {
763 pixel_program = shaders_header + pixel_program;
764 pixel_program_ptr = pixel_program.c_str();
766 if (!geometry_program.empty()) {
767 geometry_program = shaders_header + geometry_program;
768 geometry_program_ptr = geometry_program.c_str();
770 ShaderCallback *cb = new ShaderCallback(setter_factories);
773 infostream<<"Compiling high level shaders for "<<name<<std::endl;
774 shadermat = gpu->addHighLevelShaderMaterial(
775 vertex_program_ptr, // Vertex shader program
776 "vertexMain", // Vertex shader entry point
777 video::EVST_VS_1_1, // Vertex shader version
778 pixel_program_ptr, // Pixel shader program
779 "pixelMain", // Pixel shader entry point
780 video::EPST_PS_1_2, // Pixel shader version
781 geometry_program_ptr, // Geometry shader program
782 "geometryMain", // Geometry shader entry point
783 video::EGST_GS_4_0, // Geometry shader version
784 scene::EPT_TRIANGLES, // Geometry shader input
785 scene::EPT_TRIANGLE_STRIP, // Geometry shader output
786 0, // Support maximum number of vertices
787 cb, // Set-constant callback
788 shaderinfo.base_material, // Base material
789 1 // Userdata passed to callback
792 errorstream<<"generate_shader(): "
793 "failed to generate \""<<name<<"\", "
794 "addHighLevelShaderMaterial failed."
796 dumpShaderProgram(warningstream, "Vertex", vertex_program);
797 dumpShaderProgram(warningstream, "Pixel", pixel_program);
798 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
814 errorstream<<"generate_shader(): "
815 "failed to generate \""<<name<<"\", "
816 "addShaderMaterial failed."
818 dumpShaderProgram(warningstream, "Vertex", vertex_program);
819 dumpShaderProgram(warningstream,"Pixel", pixel_program);
824 callbacks.push_back(cb);
826 // HACK, TODO: investigate this better
827 // Grab the material renderer once more so minetest doesn't crash on exit
828 driver->getMaterialRenderer(shadermat)->grab();
830 // Apply the newly created material type
831 shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
835 void load_shaders(std::string name, SourceShaderCache *sourcecache,
836 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
837 std::string &vertex_program, std::string &pixel_program,
838 std::string &geometry_program, bool &is_highlevel)
842 geometry_program = "";
843 is_highlevel = false;
846 // Look for high level shaders
847 if(drivertype == video::EDT_DIRECT3D9){
849 // (All shaders in one file)
850 vertex_program = sourcecache->getOrLoad(name, "d3d9.hlsl");
851 pixel_program = vertex_program;
852 geometry_program = vertex_program;
854 else if(drivertype == video::EDT_OPENGL){
856 vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.glsl");
857 pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.glsl");
858 geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl");
860 if(vertex_program != "" || pixel_program != "" || geometry_program != ""){
868 void dumpShaderProgram(std::ostream &output_stream,
869 const std::string &program_type, const std::string &program)
871 output_stream << program_type << " shader program:" << std::endl <<
872 "----------------------------------" << std::endl;
876 while ((pos = program.find("\n", prev)) != std::string::npos) {
877 output_stream << line++ << ": "<< program.substr(prev, pos - prev) <<
881 output_stream << line << ": " << program.substr(prev) << std::endl <<
882 "End of " << program_type << " shader program." << std::endl <<