]> git.lizzy.rs Git - minetest.git/blob - src/shader.cpp
Use hexadecimal RRGGBB instead of colorkeys, rename getColor to parseColor
[minetest.git] / src / shader.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 Copyright (C) 2013 Kahrl <kahrl@gmx.net>
5
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.
10
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.
15
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.
19 */
20
21 #include "shader.h"
22 #include "irrlichttypes_extrabloated.h"
23 #include "debug.h"
24 #include "main.h" // for g_settings
25 #include "filesys.h"
26 #include "util/container.h"
27 #include "util/thread.h"
28 #include "settings.h"
29 #include <iterator>
30 #include <ICameraSceneNode.h>
31 #include <IGPUProgrammingServices.h>
32 #include <IMaterialRenderer.h>
33 #include <IMaterialRendererServices.h>
34 #include <IShaderConstantSetCallBack.h>
35 #include "EShaderTypes.h"
36 #include "log.h"
37 #include "gamedef.h"
38 #include "strfnd.h" // trim()
39
40 /*
41         A cache from shader name to shader path
42 */
43 MutexedMap<std::string, std::string> g_shadername_to_path_cache;
44
45 /*
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.
49
50         If not found, returns "".
51
52         Utilizes a thread-safe cache.
53 */
54 std::string getShaderPath(const std::string &name_of_shader,
55                 const std::string &filename)
56 {
57         std::string combined = name_of_shader + DIR_DELIM + filename;
58         std::string fullpath = "";
59         /*
60                 Check from cache
61         */
62         bool incache = g_shadername_to_path_cache.get(combined, &fullpath);
63         if(incache)
64                 return fullpath;
65
66         /*
67                 Check from shader_path
68         */
69         std::string shader_path = g_settings->get("shader_path");
70         if(shader_path != "")
71         {
72                 std::string testpath = shader_path + DIR_DELIM + combined;
73                 if(fs::PathExists(testpath))
74                         fullpath = testpath;
75         }
76
77         /*
78                 Check from default data directory
79         */
80         if(fullpath == "")
81         {
82                 std::string rel_path = std::string("client") + DIR_DELIM
83                                 + "shaders" + DIR_DELIM
84                                 + name_of_shader + DIR_DELIM
85                                 + filename;
86                 std::string testpath = porting::path_share + DIR_DELIM + rel_path;
87                 if(fs::PathExists(testpath))
88                         fullpath = testpath;
89         }
90
91         // Add to cache (also an empty result is cached)
92         g_shadername_to_path_cache.set(combined, fullpath);
93
94         // Finally return it
95         return fullpath;
96 }
97
98 /*
99         SourceShaderCache: A cache used for storing source shaders.
100 */
101
102 class SourceShaderCache
103 {
104 public:
105         void insert(const std::string &name_of_shader,
106                         const std::string &filename,
107                         const std::string &program,
108                         bool prefer_local)
109         {
110                 std::string combined = name_of_shader + DIR_DELIM + filename;
111                 // Try to use local shader instead if asked to
112                 if(prefer_local){
113                         std::string path = getShaderPath(name_of_shader, filename);
114                         if(path != ""){
115                                 std::string p = readFile(path);
116                                 if(p != ""){
117                                         m_programs[combined] = p;
118                                         return;
119                                 }
120                         }
121                 }
122                 m_programs[combined] = program;
123         }
124         std::string get(const std::string &name_of_shader,
125                         const std::string &filename)
126         {
127                 std::string combined = name_of_shader + DIR_DELIM + filename;
128                 std::map<std::string, std::string>::iterator n;
129                 n = m_programs.find(combined);
130                 if(n != m_programs.end())
131                         return n->second;
132                 return "";
133         }
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)
137         {
138                 std::string combined = name_of_shader + DIR_DELIM + filename;
139                 std::map<std::string, std::string>::iterator n;
140                 n = m_programs.find(combined);
141                 if(n != m_programs.end())
142                         return n->second;
143                 std::string path = getShaderPath(name_of_shader, filename);
144                 if(path == ""){
145                         infostream<<"SourceShaderCache::getOrLoad(): No path found for \""
146                                         <<combined<<"\""<<std::endl;
147                         return "";
148                 }
149                 infostream<<"SourceShaderCache::getOrLoad(): Loading path \""<<path
150                                 <<"\""<<std::endl;
151                 std::string p = readFile(path);
152                 if(p != ""){
153                         m_programs[combined] = p;
154                         return p;
155                 }
156                 return "";
157         }
158 private:
159         std::map<std::string, std::string> m_programs;
160         std::string readFile(const std::string &path)
161         {
162                 std::ifstream is(path.c_str(), std::ios::binary);
163                 if(!is.is_open())
164                         return "";
165                 std::ostringstream tmp_os;
166                 tmp_os << is.rdbuf();
167                 return tmp_os.str();
168         }
169 };
170
171 /*
172         ShaderCallback: Sets constants that can be used in shaders
173 */
174
175 class IShaderConstantSetterRegistry
176 {
177 public:
178         virtual ~IShaderConstantSetterRegistry(){};
179         virtual void onSetConstants(video::IMaterialRendererServices *services,
180                         bool is_highlevel, const std::string &name) = 0;
181 };
182
183 class ShaderCallback : public video::IShaderConstantSetCallBack
184 {
185         IShaderConstantSetterRegistry *m_scsr;
186         std::string m_name;
187
188 public:
189         ShaderCallback(IShaderConstantSetterRegistry *scsr, const std::string &name):
190                 m_scsr(scsr),
191                 m_name(name)
192         {}
193         ~ShaderCallback() {}
194
195         virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData)
196         {
197                 video::IVideoDriver *driver = services->getVideoDriver();
198                 assert(driver);
199
200                 bool is_highlevel = userData;
201
202                 m_scsr->onSetConstants(services, is_highlevel, m_name);
203         }
204 };
205
206 /*
207         MainShaderConstantSetter: Set basic constants required for almost everything
208 */
209
210 class MainShaderConstantSetter : public IShaderConstantSetter
211 {
212 public:
213         MainShaderConstantSetter(IrrlichtDevice *device):
214                 m_device(device)
215         {}
216         ~MainShaderConstantSetter() {}
217
218         virtual void onSetConstants(video::IMaterialRendererServices *services,
219                         bool is_highlevel)
220         {
221                 video::IVideoDriver *driver = services->getVideoDriver();
222                 assert(driver);
223
224                 // set inverted world matrix
225                 core::matrix4 invWorld = driver->getTransform(video::ETS_WORLD);
226                 invWorld.makeInverse();
227                 if(is_highlevel)
228                         services->setVertexShaderConstant("mInvWorld", invWorld.pointer(), 16);
229                 else
230                         services->setVertexShaderConstant(invWorld.pointer(), 0, 4);
231
232                 // set clip matrix
233                 core::matrix4 worldViewProj;
234                 worldViewProj = driver->getTransform(video::ETS_PROJECTION);
235                 worldViewProj *= driver->getTransform(video::ETS_VIEW);
236                 worldViewProj *= driver->getTransform(video::ETS_WORLD);
237                 if(is_highlevel)
238                         services->setVertexShaderConstant("mWorldViewProj", worldViewProj.pointer(), 16);
239                 else
240                         services->setVertexShaderConstant(worldViewProj.pointer(), 4, 4);
241
242                 // set transposed world matrix
243                 core::matrix4 world = driver->getTransform(video::ETS_WORLD);
244                 world = world.getTransposed();
245                 if(is_highlevel)
246                         services->setVertexShaderConstant("mTransWorld", world.pointer(), 16);
247                 else
248                         services->setVertexShaderConstant(world.pointer(), 8, 4);
249         }
250
251 private:
252         IrrlichtDevice *m_device;
253 };
254
255 /*
256         ShaderSource
257 */
258
259 class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterRegistry
260 {
261 public:
262         ShaderSource(IrrlichtDevice *device);
263         ~ShaderSource();
264
265         /*
266                 Gets a shader material id from cache or
267                 - if main thread, from getShaderIdDirect
268                 - if other thread, adds to request queue and waits for main thread
269         */
270         u32 getShaderId(const std::string &name);
271
272         /*
273                 - If shader material specified by name is found from cache,
274                   return the cached id.
275                 - Otherwise generate the shader material, add to cache and return id.
276
277                 The id 0 points to a null shader. Its material is EMT_SOLID.
278         */
279         u32 getShaderIdDirect(const std::string &name);
280
281         // Finds out the name of a cached shader.
282         std::string getShaderName(u32 id);
283
284         /*
285                 If shader specified by the name pointed by the id doesn't
286                 exist, create it, then return the cached shader.
287
288                 Can be called from any thread. If called from some other thread
289                 and not found in cache, the call is queued to the main thread
290                 for processing.
291         */
292         ShaderInfo getShader(u32 id);
293
294         ShaderInfo getShader(const std::string &name)
295         {
296                 return getShader(getShaderId(name));
297         }
298
299         // Processes queued shader requests from other threads.
300         // Shall be called from the main thread.
301         void processQueue();
302
303         // Insert a shader program into the cache without touching the
304         // filesystem. Shall be called from the main thread.
305         void insertSourceShader(const std::string &name_of_shader,
306                 const std::string &filename, const std::string &program);
307
308         // Rebuild shaders from the current set of source shaders
309         // Shall be called from the main thread.
310         void rebuildShaders();
311
312         void addGlobalConstantSetter(IShaderConstantSetter *setter)
313         {
314                 m_global_setters.push_back(setter);
315         }
316
317         void onSetConstants(video::IMaterialRendererServices *services,
318                         bool is_highlevel, const std::string &name);
319
320 private:
321
322         // The id of the thread that is allowed to use irrlicht directly
323         threadid_t m_main_thread;
324         // The irrlicht device
325         IrrlichtDevice *m_device;
326         // The set-constants callback
327         ShaderCallback *m_shader_callback;
328
329         // Cache of source shaders
330         // This should be only accessed from the main thread
331         SourceShaderCache m_sourcecache;
332
333         // A shader id is index in this array.
334         // The first position contains a dummy shader.
335         std::vector<ShaderInfo> m_shaderinfo_cache;
336         // Maps a shader name to an index in the former.
337         std::map<std::string, u32> m_name_to_id;
338         // The two former containers are behind this mutex
339         JMutex m_shaderinfo_cache_mutex;
340
341         // Queued shader fetches (to be processed by the main thread)
342         RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
343
344         // Global constant setters
345         // TODO: Delete these in the destructor
346         std::vector<IShaderConstantSetter*> m_global_setters;
347 };
348
349 IWritableShaderSource* createShaderSource(IrrlichtDevice *device)
350 {
351         return new ShaderSource(device);
352 }
353
354 /*
355         Generate shader given the shader name.
356 */
357 ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
358                 video::IShaderConstantSetCallBack *callback,
359                 SourceShaderCache *sourcecache);
360
361 /*
362         Load shader programs
363 */
364 void load_shaders(std::string name, SourceShaderCache *sourcecache,
365                 video::E_DRIVER_TYPE drivertype, s32 enable_shaders,
366                 std::string &vertex_program, std::string &pixel_program,
367                 std::string &geometry_program, bool &is_highlevel);
368
369 ShaderSource::ShaderSource(IrrlichtDevice *device):
370                 m_device(device)
371 {
372         assert(m_device);
373
374         m_shader_callback = new ShaderCallback(this, "default");
375
376         m_shaderinfo_cache_mutex.Init();
377
378         m_main_thread = get_current_thread_id();
379
380         // Add a dummy ShaderInfo as the first index, named ""
381         m_shaderinfo_cache.push_back(ShaderInfo());
382         m_name_to_id[""] = 0;
383
384         // Add main global constant setter
385         addGlobalConstantSetter(new MainShaderConstantSetter(device));
386 }
387
388 ShaderSource::~ShaderSource()
389 {
390         //m_shader_callback->drop();
391
392         for (std::vector<IShaderConstantSetter*>::iterator iter = m_global_setters.begin();
393                         iter != m_global_setters.end(); iter++) {
394                 delete *iter;
395         }
396         m_global_setters.clear();
397 }
398
399 u32 ShaderSource::getShaderId(const std::string &name)
400 {
401         //infostream<<"getShaderId(): \""<<name<<"\""<<std::endl;
402
403         {
404                 /*
405                         See if shader already exists
406                 */
407                 JMutexAutoLock lock(m_shaderinfo_cache_mutex);
408                 std::map<std::string, u32>::iterator n;
409                 n = m_name_to_id.find(name);
410                 if(n != m_name_to_id.end())
411                         return n->second;
412         }
413
414         /*
415                 Get shader
416         */
417         if(get_current_thread_id() == m_main_thread){
418                 return getShaderIdDirect(name);
419         } else {
420                 infostream<<"getShaderId(): Queued: name=\""<<name<<"\""<<std::endl;
421
422                 // We're gonna ask the result to be put into here
423                 ResultQueue<std::string, u32, u8, u8> result_queue;
424
425                 // Throw a request in
426                 m_get_shader_queue.add(name, 0, 0, &result_queue);
427
428                 infostream<<"Waiting for shader from main thread, name=\""
429                                 <<name<<"\""<<std::endl;
430
431                 try{
432                         // Wait result for a second
433                         GetResult<std::string, u32, u8, u8>
434                                         result = result_queue.pop_front(1000);
435
436                         // Check that at least something worked OK
437                         assert(result.key == name);
438
439                         return result.item;
440                 }
441                 catch(ItemNotFoundException &e){
442                         infostream<<"Waiting for shader timed out."<<std::endl;
443                         return 0;
444                 }
445         }
446
447         infostream<<"getShaderId(): Failed"<<std::endl;
448
449         return 0;
450 }
451
452 /*
453         This method generates all the shaders
454 */
455 u32 ShaderSource::getShaderIdDirect(const std::string &name)
456 {
457         //infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
458
459         // Empty name means shader 0
460         if(name == ""){
461                 infostream<<"getShaderIdDirect(): name is empty"<<std::endl;
462                 return 0;
463         }
464
465         /*
466                 Calling only allowed from main thread
467         */
468         if(get_current_thread_id() != m_main_thread){
469                 errorstream<<"ShaderSource::getShaderIdDirect() "
470                                 "called not from main thread"<<std::endl;
471                 return 0;
472         }
473
474         /*
475                 See if shader already exists
476         */
477         {
478                 JMutexAutoLock lock(m_shaderinfo_cache_mutex);
479
480                 std::map<std::string, u32>::iterator n;
481                 n = m_name_to_id.find(name);
482                 if(n != m_name_to_id.end()){
483                         /*infostream<<"getShaderIdDirect(): \""<<name
484                                         <<"\" found in cache"<<std::endl;*/
485                         return n->second;
486                 }
487         }
488
489         /*infostream<<"getShaderIdDirect(): \""<<name
490                         <<"\" NOT found in cache. Creating it."<<std::endl;*/
491
492         ShaderInfo info = generate_shader(name, m_device,
493                         m_shader_callback, &m_sourcecache);
494
495         /*
496                 Add shader to caches (add dummy shaders too)
497         */
498
499         JMutexAutoLock lock(m_shaderinfo_cache_mutex);
500
501         u32 id = m_shaderinfo_cache.size();
502         m_shaderinfo_cache.push_back(info);
503         m_name_to_id[name] = id;
504
505         /*infostream<<"getShaderIdDirect(): "
506                         <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;*/
507
508         return id;
509 }
510
511 std::string ShaderSource::getShaderName(u32 id)
512 {
513         JMutexAutoLock lock(m_shaderinfo_cache_mutex);
514
515         if(id >= m_shaderinfo_cache.size()){
516                 errorstream<<"ShaderSource::getShaderName(): id="<<id
517                                 <<" >= m_shaderinfo_cache.size()="
518                                 <<m_shaderinfo_cache.size()<<std::endl;
519                 return "";
520         }
521
522         return m_shaderinfo_cache[id].name;
523 }
524
525 ShaderInfo ShaderSource::getShader(u32 id)
526 {
527         JMutexAutoLock lock(m_shaderinfo_cache_mutex);
528
529         if(id >= m_shaderinfo_cache.size())
530                 return ShaderInfo();
531
532         return m_shaderinfo_cache[id];
533 }
534
535 void ShaderSource::processQueue()
536 {
537         /*
538                 Fetch shaders
539         */
540         if(!m_get_shader_queue.empty()){
541                 GetRequest<std::string, u32, u8, u8>
542                                 request = m_get_shader_queue.pop();
543
544                 /*infostream<<"ShaderSource::processQueue(): "
545                                 <<"got shader request with "
546                                 <<"name=\""<<request.key<<"\""
547                                 <<std::endl;*/
548
549                 GetResult<std::string, u32, u8, u8>
550                                 result;
551                 result.key = request.key;
552                 result.callers = request.callers;
553                 result.item = getShaderIdDirect(request.key);
554
555                 request.dest->push_back(result);
556         }
557 }
558
559 void ShaderSource::insertSourceShader(const std::string &name_of_shader,
560                 const std::string &filename, const std::string &program)
561 {
562         /*infostream<<"ShaderSource::insertSourceShader(): "
563                         "name_of_shader=\""<<name_of_shader<<"\", "
564                         "filename=\""<<filename<<"\""<<std::endl;*/
565
566         assert(get_current_thread_id() == m_main_thread);
567
568         m_sourcecache.insert(name_of_shader, filename, program, true);
569 }
570
571 void ShaderSource::rebuildShaders()
572 {
573         JMutexAutoLock lock(m_shaderinfo_cache_mutex);
574
575         /*// Oh well... just clear everything, they'll load sometime.
576         m_shaderinfo_cache.clear();
577         m_name_to_id.clear();*/
578
579         /*
580                 FIXME: Old shader materials can't be deleted in Irrlicht,
581                 or can they?
582                 (This would be nice to do in the destructor too)
583         */
584
585         // Recreate shaders
586         for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
587                 ShaderInfo *info = &m_shaderinfo_cache[i];
588                 if(info->name != ""){
589                         *info = generate_shader(info->name, m_device,
590                                         m_shader_callback, &m_sourcecache);
591                 }
592         }
593 }
594
595 void ShaderSource::onSetConstants(video::IMaterialRendererServices *services,
596                 bool is_highlevel, const std::string &name)
597 {
598         for(u32 i=0; i<m_global_setters.size(); i++){
599                 IShaderConstantSetter *setter = m_global_setters[i];
600                 setter->onSetConstants(services, is_highlevel);
601         }
602 }
603  
604 ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
605                 video::IShaderConstantSetCallBack *callback,
606                 SourceShaderCache *sourcecache)
607 {
608         /*infostream<<"generate_shader(): "
609                         "\""<<name<<"\""<<std::endl;*/
610
611         ShaderInfo shaderinfo;
612         shaderinfo.name = name;
613         shaderinfo.material = video::EMT_SOLID;
614
615         /*
616                 Get the base material
617         */
618         std::string base_material_name =
619                 trim(sourcecache->getOrLoad(name, "base.txt"));
620         for(s32 i = 0; video::sBuiltInMaterialTypeNames[i] != 0; i++){
621                 if(video::sBuiltInMaterialTypeNames[i] == base_material_name){
622                         shaderinfo.material = (video::E_MATERIAL_TYPE) i;
623                         break;
624                 }
625         }
626
627         // 0 = off, 1 = assembly shaders only, 2 = highlevel or assembly
628         s32 enable_shaders = g_settings->getS32("enable_shaders");
629         if(enable_shaders <= 0)
630                 return shaderinfo;
631
632         video::IVideoDriver* driver = device->getVideoDriver();
633         assert(driver);
634
635         video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
636         if(!gpu){
637                 errorstream<<"generate_shader(): "
638                                 "failed to generate \""<<name<<"\", "
639                                 "GPU programming not supported."
640                                 <<std::endl;
641                 return shaderinfo;
642         }
643
644         // Choose shader language depending on driver type and settings
645         // Then load shaders
646         std::string vertex_program;
647         std::string pixel_program;
648         std::string geometry_program;
649         bool is_highlevel;
650         load_shaders(name, sourcecache, driver->getDriverType(),
651                         enable_shaders, vertex_program, pixel_program,
652                         geometry_program, is_highlevel);
653
654         // Check hardware/driver support
655         if(vertex_program != "" &&
656                         !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
657                         !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
658                 infostream<<"generate_shader(): vertex shaders disabled "
659                                 "because of missing driver/hardware support."
660                                 <<std::endl;
661                 vertex_program = "";
662         }
663         if(pixel_program != "" &&
664                         !driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
665                         !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
666                 infostream<<"generate_shader(): pixel shaders disabled "
667                                 "because of missing driver/hardware support."
668                                 <<std::endl;
669                 pixel_program = "";
670         }
671         if(geometry_program != "" &&
672                         !driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
673                 infostream<<"generate_shader(): geometry shaders disabled "
674                                 "because of missing driver/hardware support."
675                                 <<std::endl;
676                 geometry_program = "";
677         }
678
679         // If no shaders are used, don't make a separate material type
680         if(vertex_program == "" && pixel_program == "" && geometry_program == "")
681                 return shaderinfo;
682
683         // Call addHighLevelShaderMaterial() or addShaderMaterial()
684         const c8* vertex_program_ptr = 0;
685         const c8* pixel_program_ptr = 0;
686         const c8* geometry_program_ptr = 0;
687         if(vertex_program != "")
688                 vertex_program_ptr = vertex_program.c_str();
689         if(pixel_program != "")
690                 pixel_program_ptr = pixel_program.c_str();
691         if(geometry_program != "")
692                 geometry_program_ptr = geometry_program.c_str();
693         s32 shadermat = -1;
694         if(is_highlevel){
695                 infostream<<"Compiling high level shaders for "<<name<<std::endl;
696                 shadermat = gpu->addHighLevelShaderMaterial(
697                         vertex_program_ptr,   // Vertex shader program
698                         "vertexMain",         // Vertex shader entry point
699                         video::EVST_VS_1_1,   // Vertex shader version
700                         pixel_program_ptr,    // Pixel shader program
701                         "pixelMain",          // Pixel shader entry point
702                         video::EPST_PS_1_1,   // Pixel shader version
703                         geometry_program_ptr, // Geometry shader program
704                         "geometryMain",       // Geometry shader entry point
705                         video::EGST_GS_4_0,   // Geometry shader version
706                         scene::EPT_TRIANGLES,      // Geometry shader input
707                         scene::EPT_TRIANGLE_STRIP, // Geometry shader output
708                         0,                         // Support maximum number of vertices
709                         callback,             // Set-constant callback
710                         shaderinfo.material,  // Base material
711                         1                     // Userdata passed to callback
712                         );
713
714                 if(shadermat == -1){
715                         errorstream<<"generate_shader(): "
716                                         "failed to generate \""<<name<<"\", "
717                                         "addHighLevelShaderMaterial failed."
718                                         <<std::endl;
719                         return shaderinfo;
720                 }
721         }
722         else{
723                 infostream<<"Compiling assembly shaders for "<<name<<std::endl;
724                 shadermat = gpu->addShaderMaterial(
725                         vertex_program_ptr,   // Vertex shader program
726                         pixel_program_ptr,    // Pixel shader program
727                         callback,             // Set-constant callback
728                         shaderinfo.material,  // Base material
729                         0                     // Userdata passed to callback
730                         );
731
732                 if(shadermat == -1){
733                         errorstream<<"generate_shader(): "
734                                         "failed to generate \""<<name<<"\", "
735                                         "addShaderMaterial failed."
736                                         <<std::endl;
737                         return shaderinfo;
738                 }
739         }
740
741         // HACK, TODO: investigate this better
742         // Grab the material renderer once more so minetest doesn't crash on exit
743         driver->getMaterialRenderer(shadermat)->grab();
744
745         // Apply the newly created material type
746         shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
747         return shaderinfo;
748 }
749
750 void load_shaders(std::string name, SourceShaderCache *sourcecache,
751                 video::E_DRIVER_TYPE drivertype, s32 enable_shaders,
752                 std::string &vertex_program, std::string &pixel_program,
753                 std::string &geometry_program, bool &is_highlevel)
754 {
755         vertex_program = "";
756         pixel_program = "";
757         geometry_program = "";
758         is_highlevel = false;
759
760         if(enable_shaders >= 2){
761                 // Look for high level shaders
762                 if(drivertype == video::EDT_DIRECT3D9){
763                         // Direct3D 9: HLSL
764                         // (All shaders in one file)
765                         vertex_program = sourcecache->getOrLoad(name, "d3d9.hlsl");
766                         pixel_program = vertex_program;
767                         geometry_program = vertex_program;
768                 }
769                 else if(drivertype == video::EDT_OPENGL){
770                         // OpenGL: GLSL
771                         vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.glsl");
772                         pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.glsl");
773                         geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl");
774                 }
775                 if(vertex_program != "" || pixel_program != "" || geometry_program != ""){
776                         is_highlevel = true;
777                         return;
778                 }
779         }
780
781         if(enable_shaders >= 1){
782                 // Look for assembly shaders
783                 if(drivertype == video::EDT_DIRECT3D8){
784                         // Direct3D 8 assembly shaders
785                         vertex_program = sourcecache->getOrLoad(name, "d3d8_vertex.asm");
786                         pixel_program = sourcecache->getOrLoad(name, "d3d8_pixel.asm");
787                 }
788                 else if(drivertype == video::EDT_DIRECT3D9){
789                         // Direct3D 9 assembly shaders
790                         vertex_program = sourcecache->getOrLoad(name, "d3d9_vertex.asm");
791                         pixel_program = sourcecache->getOrLoad(name, "d3d9_pixel.asm");
792                 }
793                 else if(drivertype == video::EDT_OPENGL){
794                         // OpenGL assembly shaders
795                         vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.asm");
796                         pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.asm");
797                 }
798                 if(vertex_program != "" || pixel_program != "")
799                         return;
800         }
801 }