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();
171 ShaderCallback: Sets constants that can be used in shaders
174 class IShaderConstantSetterRegistry
177 virtual ~IShaderConstantSetterRegistry(){};
178 virtual void onSetConstants(video::IMaterialRendererServices *services,
179 bool is_highlevel, const std::string &name) = 0;
182 class ShaderCallback : public video::IShaderConstantSetCallBack
184 IShaderConstantSetterRegistry *m_scsr;
188 ShaderCallback(IShaderConstantSetterRegistry *scsr, const std::string &name):
194 virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData)
196 video::IVideoDriver *driver = services->getVideoDriver();
197 sanity_check(driver != NULL);
199 bool is_highlevel = userData;
201 m_scsr->onSetConstants(services, is_highlevel, m_name);
206 MainShaderConstantSetter: Set basic constants required for almost everything
209 class MainShaderConstantSetter : public IShaderConstantSetter
212 MainShaderConstantSetter(IrrlichtDevice *device)
214 ~MainShaderConstantSetter() {}
216 virtual void onSetConstants(video::IMaterialRendererServices *services,
219 video::IVideoDriver *driver = services->getVideoDriver();
220 sanity_check(driver);
223 core::matrix4 worldViewProj;
224 worldViewProj = driver->getTransform(video::ETS_PROJECTION);
225 worldViewProj *= driver->getTransform(video::ETS_VIEW);
226 worldViewProj *= driver->getTransform(video::ETS_WORLD);
228 services->setVertexShaderConstant("mWorldViewProj", worldViewProj.pointer(), 16);
230 services->setVertexShaderConstant(worldViewProj.pointer(), 4, 4);
233 core::matrix4 world = driver->getTransform(video::ETS_WORLD);
235 services->setVertexShaderConstant("mWorld", world.pointer(), 16);
237 services->setVertexShaderConstant(world.pointer(), 8, 4);
246 class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterRegistry
249 ShaderSource(IrrlichtDevice *device);
253 - If shader material specified by name is found from cache,
254 return the cached id.
255 - Otherwise generate the shader material, add to cache and return id.
257 The id 0 points to a null shader. Its material is EMT_SOLID.
259 u32 getShaderIdDirect(const std::string &name,
260 const u8 material_type, const u8 drawtype);
263 If shader specified by the name pointed by the id doesn't
264 exist, create it, then return id.
266 Can be called from any thread. If called from some other thread
267 and not found in cache, the call is queued to the main thread
271 u32 getShader(const std::string &name,
272 const u8 material_type, const u8 drawtype);
274 ShaderInfo getShaderInfo(u32 id);
276 // Processes queued shader requests from other threads.
277 // Shall be called from the main thread.
280 // Insert a shader program into the cache without touching the
281 // filesystem. Shall be called from the main thread.
282 void insertSourceShader(const std::string &name_of_shader,
283 const std::string &filename, const std::string &program);
285 // Rebuild shaders from the current set of source shaders
286 // Shall be called from the main thread.
287 void rebuildShaders();
289 void addGlobalConstantSetter(IShaderConstantSetter *setter)
291 m_global_setters.push_back(setter);
294 void onSetConstants(video::IMaterialRendererServices *services,
295 bool is_highlevel, const std::string &name);
299 // The id of the thread that is allowed to use irrlicht directly
300 threadid_t m_main_thread;
301 // The irrlicht device
302 IrrlichtDevice *m_device;
303 // The set-constants callback
304 ShaderCallback *m_shader_callback;
306 // Cache of source shaders
307 // This should be only accessed from the main thread
308 SourceShaderCache m_sourcecache;
310 // A shader id is index in this array.
311 // The first position contains a dummy shader.
312 std::vector<ShaderInfo> m_shaderinfo_cache;
313 // The former container is behind this mutex
314 Mutex m_shaderinfo_cache_mutex;
316 // Queued shader fetches (to be processed by the main thread)
317 RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
319 // Global constant setters
320 // TODO: Delete these in the destructor
321 std::vector<IShaderConstantSetter*> m_global_setters;
324 IWritableShaderSource* createShaderSource(IrrlichtDevice *device)
326 return new ShaderSource(device);
330 Generate shader given the shader name.
332 ShaderInfo generate_shader(std::string name,
333 u8 material_type, u8 drawtype,
334 IrrlichtDevice *device,
335 video::IShaderConstantSetCallBack *callback,
336 SourceShaderCache *sourcecache);
341 void load_shaders(std::string name, SourceShaderCache *sourcecache,
342 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
343 std::string &vertex_program, std::string &pixel_program,
344 std::string &geometry_program, bool &is_highlevel);
346 ShaderSource::ShaderSource(IrrlichtDevice *device):
349 assert(m_device); // Pre-condition
351 m_shader_callback = new ShaderCallback(this, "default");
353 m_main_thread = thr_get_current_thread_id();
355 // Add a dummy ShaderInfo as the first index, named ""
356 m_shaderinfo_cache.push_back(ShaderInfo());
358 // Add main global constant setter
359 addGlobalConstantSetter(new MainShaderConstantSetter(device));
362 ShaderSource::~ShaderSource()
364 for (std::vector<IShaderConstantSetter*>::iterator iter = m_global_setters.begin();
365 iter != m_global_setters.end(); ++iter) {
368 m_global_setters.clear();
370 if (m_shader_callback) {
371 m_shader_callback->drop();
372 m_shader_callback = NULL;
376 u32 ShaderSource::getShader(const std::string &name,
377 const u8 material_type, const u8 drawtype)
383 if (thr_is_current_thread(m_main_thread)) {
384 return getShaderIdDirect(name, material_type, drawtype);
386 /*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/
388 // We're gonna ask the result to be put into here
390 static ResultQueue<std::string, u32, u8, u8> result_queue;
392 // Throw a request in
393 m_get_shader_queue.add(name, 0, 0, &result_queue);
395 /* infostream<<"Waiting for shader from main thread, name=\""
396 <<name<<"\""<<std::endl;*/
399 GetResult<std::string, u32, u8, u8>
400 result = result_queue.pop_frontNoEx();
402 if (result.key == name) {
406 errorstream << "Got shader with invalid name: " << result.key << std::endl;
412 infostream<<"getShader(): Failed"<<std::endl;
418 This method generates all the shaders
420 u32 ShaderSource::getShaderIdDirect(const std::string &name,
421 const u8 material_type, const u8 drawtype)
423 //infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
425 // Empty name means shader 0
427 infostream<<"getShaderIdDirect(): name is empty"<<std::endl;
431 // Check if already have such instance
432 for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
433 ShaderInfo *info = &m_shaderinfo_cache[i];
434 if(info->name == name && info->material_type == material_type &&
435 info->drawtype == drawtype)
440 Calling only allowed from main thread
442 if (!thr_is_current_thread(m_main_thread)) {
443 errorstream<<"ShaderSource::getShaderIdDirect() "
444 "called not from main thread"<<std::endl;
448 ShaderInfo info = generate_shader(name, material_type, drawtype, m_device,
449 m_shader_callback, &m_sourcecache);
452 Add shader to caches (add dummy shaders too)
455 MutexAutoLock lock(m_shaderinfo_cache_mutex);
457 u32 id = m_shaderinfo_cache.size();
458 m_shaderinfo_cache.push_back(info);
460 infostream<<"getShaderIdDirect(): "
461 <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;
467 ShaderInfo ShaderSource::getShaderInfo(u32 id)
469 MutexAutoLock lock(m_shaderinfo_cache_mutex);
471 if(id >= m_shaderinfo_cache.size())
474 return m_shaderinfo_cache[id];
477 void ShaderSource::processQueue()
483 void ShaderSource::insertSourceShader(const std::string &name_of_shader,
484 const std::string &filename, const std::string &program)
486 /*infostream<<"ShaderSource::insertSourceShader(): "
487 "name_of_shader=\""<<name_of_shader<<"\", "
488 "filename=\""<<filename<<"\""<<std::endl;*/
490 sanity_check(thr_is_current_thread(m_main_thread));
492 m_sourcecache.insert(name_of_shader, filename, program, true);
495 void ShaderSource::rebuildShaders()
497 MutexAutoLock lock(m_shaderinfo_cache_mutex);
499 /*// Oh well... just clear everything, they'll load sometime.
500 m_shaderinfo_cache.clear();
501 m_name_to_id.clear();*/
504 FIXME: Old shader materials can't be deleted in Irrlicht,
506 (This would be nice to do in the destructor too)
510 for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
511 ShaderInfo *info = &m_shaderinfo_cache[i];
512 if(info->name != ""){
513 *info = generate_shader(info->name, info->material_type,
514 info->drawtype, m_device, m_shader_callback, &m_sourcecache);
519 void ShaderSource::onSetConstants(video::IMaterialRendererServices *services,
520 bool is_highlevel, const std::string &name)
522 for(u32 i=0; i<m_global_setters.size(); i++){
523 IShaderConstantSetter *setter = m_global_setters[i];
524 setter->onSetConstants(services, is_highlevel);
528 ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
529 IrrlichtDevice *device, video::IShaderConstantSetCallBack *callback,
530 SourceShaderCache *sourcecache)
532 ShaderInfo shaderinfo;
533 shaderinfo.name = name;
534 shaderinfo.material_type = material_type;
535 shaderinfo.drawtype = drawtype;
536 shaderinfo.material = video::EMT_SOLID;
537 switch(material_type){
538 case TILE_MATERIAL_BASIC:
539 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
541 case TILE_MATERIAL_ALPHA:
542 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
544 case TILE_MATERIAL_LIQUID_TRANSPARENT:
545 shaderinfo.base_material = video::EMT_TRANSPARENT_VERTEX_ALPHA;
547 case TILE_MATERIAL_LIQUID_OPAQUE:
548 shaderinfo.base_material = video::EMT_SOLID;
550 case TILE_MATERIAL_WAVING_LEAVES:
551 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
553 case TILE_MATERIAL_WAVING_PLANTS:
554 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
558 bool enable_shaders = g_settings->getBool("enable_shaders");
562 video::IVideoDriver* driver = device->getVideoDriver();
563 sanity_check(driver);
565 video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
567 errorstream<<"generate_shader(): "
568 "failed to generate \""<<name<<"\", "
569 "GPU programming not supported."
574 // Choose shader language depending on driver type and settings
576 std::string vertex_program;
577 std::string pixel_program;
578 std::string geometry_program;
580 load_shaders(name, sourcecache, driver->getDriverType(),
581 enable_shaders, vertex_program, pixel_program,
582 geometry_program, is_highlevel);
583 // Check hardware/driver support
584 if(vertex_program != "" &&
585 !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
586 !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
587 infostream<<"generate_shader(): vertex shaders disabled "
588 "because of missing driver/hardware support."
592 if(pixel_program != "" &&
593 !driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
594 !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
595 infostream<<"generate_shader(): pixel shaders disabled "
596 "because of missing driver/hardware support."
600 if(geometry_program != "" &&
601 !driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
602 infostream<<"generate_shader(): geometry shaders disabled "
603 "because of missing driver/hardware support."
605 geometry_program = "";
608 // If no shaders are used, don't make a separate material type
609 if(vertex_program == "" && pixel_program == "" && geometry_program == "")
612 // Create shaders header
613 std::string shaders_header = "#version 120\n";
615 static const char* drawTypes[] = {
622 "NDT_ALLFACES_OPTIONAL",
629 "NDT_GLASSLIKE_FRAMED",
631 "NDT_GLASSLIKE_FRAMED_OPTIONAL"
634 for (int i = 0; i < 14; i++){
635 shaders_header += "#define ";
636 shaders_header += drawTypes[i];
637 shaders_header += " ";
638 shaders_header += itos(i);
639 shaders_header += "\n";
642 static const char* materialTypes[] = {
643 "TILE_MATERIAL_BASIC",
644 "TILE_MATERIAL_ALPHA",
645 "TILE_MATERIAL_LIQUID_TRANSPARENT",
646 "TILE_MATERIAL_LIQUID_OPAQUE",
647 "TILE_MATERIAL_WAVING_LEAVES",
648 "TILE_MATERIAL_WAVING_PLANTS"
651 for (int i = 0; i < 6; i++){
652 shaders_header += "#define ";
653 shaders_header += materialTypes[i];
654 shaders_header += " ";
655 shaders_header += itos(i);
656 shaders_header += "\n";
659 shaders_header += "#define MATERIAL_TYPE ";
660 shaders_header += itos(material_type);
661 shaders_header += "\n";
662 shaders_header += "#define DRAW_TYPE ";
663 shaders_header += itos(drawtype);
664 shaders_header += "\n";
666 if (g_settings->getBool("generate_normalmaps")) {
667 shaders_header += "#define GENERATE_NORMALMAPS 1\n";
669 shaders_header += "#define GENERATE_NORMALMAPS 0\n";
671 shaders_header += "#define NORMALMAPS_STRENGTH ";
672 shaders_header += ftos(g_settings->getFloat("normalmaps_strength"));
673 shaders_header += "\n";
675 int smooth = (int)g_settings->getFloat("normalmaps_smooth");
678 sample_step = 0.0078125; // 1.0 / 128.0
681 sample_step = 0.00390625; // 1.0 / 256.0
684 sample_step = 0.001953125; // 1.0 / 512.0
687 sample_step = 0.0078125;
690 shaders_header += "#define SAMPLE_STEP ";
691 shaders_header += ftos(sample_step);
692 shaders_header += "\n";
694 if (g_settings->getBool("enable_bumpmapping"))
695 shaders_header += "#define ENABLE_BUMPMAPPING\n";
697 if (g_settings->getBool("enable_parallax_occlusion")){
698 int mode = g_settings->getFloat("parallax_occlusion_mode");
699 float scale = g_settings->getFloat("parallax_occlusion_scale");
700 float bias = g_settings->getFloat("parallax_occlusion_bias");
701 int iterations = g_settings->getFloat("parallax_occlusion_iterations");
702 shaders_header += "#define ENABLE_PARALLAX_OCCLUSION\n";
703 shaders_header += "#define PARALLAX_OCCLUSION_MODE ";
704 shaders_header += itos(mode);
705 shaders_header += "\n";
706 shaders_header += "#define PARALLAX_OCCLUSION_SCALE ";
707 shaders_header += ftos(scale);
708 shaders_header += "\n";
709 shaders_header += "#define PARALLAX_OCCLUSION_BIAS ";
710 shaders_header += ftos(bias);
711 shaders_header += "\n";
712 shaders_header += "#define PARALLAX_OCCLUSION_ITERATIONS ";
713 shaders_header += itos(iterations);
714 shaders_header += "\n";
717 shaders_header += "#define USE_NORMALMAPS ";
718 if (g_settings->getBool("enable_bumpmapping") || g_settings->getBool("enable_parallax_occlusion"))
719 shaders_header += "1\n";
721 shaders_header += "0\n";
723 if (g_settings->getBool("enable_waving_water")){
724 shaders_header += "#define ENABLE_WAVING_WATER 1\n";
725 shaders_header += "#define WATER_WAVE_HEIGHT ";
726 shaders_header += ftos(g_settings->getFloat("water_wave_height"));
727 shaders_header += "\n";
728 shaders_header += "#define WATER_WAVE_LENGTH ";
729 shaders_header += ftos(g_settings->getFloat("water_wave_length"));
730 shaders_header += "\n";
731 shaders_header += "#define WATER_WAVE_SPEED ";
732 shaders_header += ftos(g_settings->getFloat("water_wave_speed"));
733 shaders_header += "\n";
735 shaders_header += "#define ENABLE_WAVING_WATER 0\n";
738 shaders_header += "#define ENABLE_WAVING_LEAVES ";
739 if (g_settings->getBool("enable_waving_leaves"))
740 shaders_header += "1\n";
742 shaders_header += "0\n";
744 shaders_header += "#define ENABLE_WAVING_PLANTS ";
745 if (g_settings->getBool("enable_waving_plants"))
746 shaders_header += "1\n";
748 shaders_header += "0\n";
750 if (g_settings->getBool("tone_mapping"))
751 shaders_header += "#define ENABLE_TONE_MAPPING\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();
771 infostream<<"Compiling high level shaders for "<<name<<std::endl;
772 shadermat = gpu->addHighLevelShaderMaterial(
773 vertex_program_ptr, // Vertex shader program
774 "vertexMain", // Vertex shader entry point
775 video::EVST_VS_1_1, // Vertex shader version
776 pixel_program_ptr, // Pixel shader program
777 "pixelMain", // Pixel shader entry point
778 video::EPST_PS_1_2, // Pixel shader version
779 geometry_program_ptr, // Geometry shader program
780 "geometryMain", // Geometry shader entry point
781 video::EGST_GS_4_0, // Geometry shader version
782 scene::EPT_TRIANGLES, // Geometry shader input
783 scene::EPT_TRIANGLE_STRIP, // Geometry shader output
784 0, // Support maximum number of vertices
785 callback, // Set-constant callback
786 shaderinfo.base_material, // Base material
787 1 // Userdata passed to callback
790 errorstream<<"generate_shader(): "
791 "failed to generate \""<<name<<"\", "
792 "addHighLevelShaderMaterial failed."
794 dumpShaderProgram(warningstream, "Vertex", vertex_program);
795 dumpShaderProgram(warningstream, "Pixel", pixel_program);
796 dumpShaderProgram(warningstream, "Geometry", geometry_program);
801 infostream<<"Compiling assembly shaders for "<<name<<std::endl;
802 shadermat = gpu->addShaderMaterial(
803 vertex_program_ptr, // Vertex shader program
804 pixel_program_ptr, // Pixel shader program
805 callback, // Set-constant callback
806 shaderinfo.base_material, // Base material
807 0 // Userdata passed to callback
811 errorstream<<"generate_shader(): "
812 "failed to generate \""<<name<<"\", "
813 "addShaderMaterial failed."
815 dumpShaderProgram(warningstream, "Vertex", vertex_program);
816 dumpShaderProgram(warningstream,"Pixel", pixel_program);
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(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 != "" || pixel_program != "" || geometry_program != ""){
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 <<