]> git.lizzy.rs Git - dragonfireclient.git/blob - src/shader.cpp
Increase performance of getLight() by at least 2x
[dragonfireclient.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 #include "tile.h"
40
41 /*
42         A cache from shader name to shader path
43 */
44 MutexedMap<std::string, std::string> g_shadername_to_path_cache;
45
46 /*
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.
50
51         If not found, returns "".
52
53         Utilizes a thread-safe cache.
54 */
55 std::string getShaderPath(const std::string &name_of_shader,
56                 const std::string &filename)
57 {
58         std::string combined = name_of_shader + DIR_DELIM + filename;
59         std::string fullpath = "";
60         /*
61                 Check from cache
62         */
63         bool incache = g_shadername_to_path_cache.get(combined, &fullpath);
64         if(incache)
65                 return fullpath;
66
67         /*
68                 Check from shader_path
69         */
70         std::string shader_path = g_settings->get("shader_path");
71         if(shader_path != "")
72         {
73                 std::string testpath = shader_path + DIR_DELIM + combined;
74                 if(fs::PathExists(testpath))
75                         fullpath = testpath;
76         }
77
78         /*
79                 Check from default data directory
80         */
81         if(fullpath == "")
82         {
83                 std::string rel_path = std::string("client") + DIR_DELIM
84                                 + "shaders" + DIR_DELIM
85                                 + name_of_shader + DIR_DELIM
86                                 + filename;
87                 std::string testpath = porting::path_share + DIR_DELIM + rel_path;
88                 if(fs::PathExists(testpath))
89                         fullpath = testpath;
90         }
91
92         // Add to cache (also an empty result is cached)
93         g_shadername_to_path_cache.set(combined, fullpath);
94
95         // Finally return it
96         return fullpath;
97 }
98
99 /*
100         SourceShaderCache: A cache used for storing source shaders.
101 */
102
103 class SourceShaderCache
104 {
105 public:
106         void insert(const std::string &name_of_shader,
107                         const std::string &filename,
108                         const std::string &program,
109                         bool prefer_local)
110         {
111                 std::string combined = name_of_shader + DIR_DELIM + filename;
112                 // Try to use local shader instead if asked to
113                 if(prefer_local){
114                         std::string path = getShaderPath(name_of_shader, filename);
115                         if(path != ""){
116                                 std::string p = readFile(path);
117                                 if(p != ""){
118                                         m_programs[combined] = p;
119                                         return;
120                                 }
121                         }
122                 }
123                 m_programs[combined] = program;
124         }
125         std::string get(const std::string &name_of_shader,
126                         const std::string &filename)
127         {
128                 std::string combined = name_of_shader + DIR_DELIM + filename;
129                 std::map<std::string, std::string>::iterator n;
130                 n = m_programs.find(combined);
131                 if(n != m_programs.end())
132                         return n->second;
133                 return "";
134         }
135         // Primarily fetches from cache, secondarily tries to read from filesystem
136         std::string getOrLoad(const std::string &name_of_shader,
137                         const std::string &filename)
138         {
139                 std::string combined = name_of_shader + DIR_DELIM + filename;
140                 std::map<std::string, std::string>::iterator n;
141                 n = m_programs.find(combined);
142                 if(n != m_programs.end())
143                         return n->second;
144                 std::string path = getShaderPath(name_of_shader, filename);
145                 if(path == ""){
146                         infostream<<"SourceShaderCache::getOrLoad(): No path found for \""
147                                         <<combined<<"\""<<std::endl;
148                         return "";
149                 }
150                 infostream<<"SourceShaderCache::getOrLoad(): Loading path \""<<path
151                                 <<"\""<<std::endl;
152                 std::string p = readFile(path);
153                 if(p != ""){
154                         m_programs[combined] = p;
155                         return p;
156                 }
157                 return "";
158         }
159 private:
160         std::map<std::string, std::string> m_programs;
161         std::string readFile(const std::string &path)
162         {
163                 std::ifstream is(path.c_str(), std::ios::binary);
164                 if(!is.is_open())
165                         return "";
166                 std::ostringstream tmp_os;
167                 tmp_os << is.rdbuf();
168                 return tmp_os.str();
169         }
170 };
171
172 /*
173         ShaderCallback: Sets constants that can be used in shaders
174 */
175
176 class IShaderConstantSetterRegistry
177 {
178 public:
179         virtual ~IShaderConstantSetterRegistry(){};
180         virtual void onSetConstants(video::IMaterialRendererServices *services,
181                         bool is_highlevel, const std::string &name) = 0;
182 };
183
184 class ShaderCallback : public video::IShaderConstantSetCallBack
185 {
186         IShaderConstantSetterRegistry *m_scsr;
187         std::string m_name;
188
189 public:
190         ShaderCallback(IShaderConstantSetterRegistry *scsr, const std::string &name):
191                 m_scsr(scsr),
192                 m_name(name)
193         {}
194         ~ShaderCallback() {}
195
196         virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData)
197         {
198                 video::IVideoDriver *driver = services->getVideoDriver();
199                 assert(driver);
200
201                 bool is_highlevel = userData;
202
203                 m_scsr->onSetConstants(services, is_highlevel, m_name);
204         }
205 };
206
207 /*
208         MainShaderConstantSetter: Set basic constants required for almost everything
209 */
210
211 class MainShaderConstantSetter : public IShaderConstantSetter
212 {
213 public:
214         MainShaderConstantSetter(IrrlichtDevice *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 transWorld = driver->getTransform(video::ETS_WORLD);
244                 transWorld = transWorld.getTransposed();
245                 if(is_highlevel)
246                         services->setVertexShaderConstant("mTransWorld", transWorld.pointer(), 16);
247                 else
248                         services->setVertexShaderConstant(transWorld.pointer(), 8, 4);
249
250                 // set world matrix
251                 core::matrix4 world = driver->getTransform(video::ETS_WORLD);
252                 if(is_highlevel)
253                         services->setVertexShaderConstant("mWorld", world.pointer(), 16);
254                 else
255                         services->setVertexShaderConstant(world.pointer(), 8, 4);
256
257         }
258 };
259
260 /*
261         ShaderSource
262 */
263
264 class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterRegistry
265 {
266 public:
267         ShaderSource(IrrlichtDevice *device);
268         ~ShaderSource();
269
270         /*
271                 - If shader material specified by name is found from cache,
272                   return the cached id.
273                 - Otherwise generate the shader material, add to cache and return id.
274
275                 The id 0 points to a null shader. Its material is EMT_SOLID.
276         */
277         u32 getShaderIdDirect(const std::string &name, 
278                 const u8 material_type, const u8 drawtype);
279
280         /*
281                 If shader specified by the name pointed by the id doesn't
282                 exist, create it, then return id. 
283
284                 Can be called from any thread. If called from some other thread
285                 and not found in cache, the call is queued to the main thread
286                 for processing.
287         */
288         
289         u32 getShader(const std::string &name,
290                 const u8 material_type, const u8 drawtype);
291         
292         ShaderInfo getShaderInfo(u32 id);
293         
294         // Processes queued shader requests from other threads.
295         // Shall be called from the main thread.
296         void processQueue();
297
298         // Insert a shader program into the cache without touching the
299         // filesystem. Shall be called from the main thread.
300         void insertSourceShader(const std::string &name_of_shader,
301                 const std::string &filename, const std::string &program);
302
303         // Rebuild shaders from the current set of source shaders
304         // Shall be called from the main thread.
305         void rebuildShaders();
306
307         void addGlobalConstantSetter(IShaderConstantSetter *setter)
308         {
309                 m_global_setters.push_back(setter);
310         }
311
312         void onSetConstants(video::IMaterialRendererServices *services,
313                         bool is_highlevel, const std::string &name);
314
315 private:
316
317         // The id of the thread that is allowed to use irrlicht directly
318         threadid_t m_main_thread;
319         // The irrlicht device
320         IrrlichtDevice *m_device;
321         // The set-constants callback
322         ShaderCallback *m_shader_callback;
323
324         // Cache of source shaders
325         // This should be only accessed from the main thread
326         SourceShaderCache m_sourcecache;
327
328         // A shader id is index in this array.
329         // The first position contains a dummy shader.
330         std::vector<ShaderInfo> m_shaderinfo_cache;
331         // The former container is behind this mutex
332         JMutex m_shaderinfo_cache_mutex;
333
334         // Queued shader fetches (to be processed by the main thread)
335         RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
336
337         // Global constant setters
338         // TODO: Delete these in the destructor
339         std::vector<IShaderConstantSetter*> m_global_setters;
340 };
341
342 IWritableShaderSource* createShaderSource(IrrlichtDevice *device)
343 {
344         return new ShaderSource(device);
345 }
346
347 /*
348         Generate shader given the shader name.
349 */
350 ShaderInfo generate_shader(std::string name,
351                 u8 material_type, u8 drawtype,
352                 IrrlichtDevice *device,
353                 video::IShaderConstantSetCallBack *callback,
354                 SourceShaderCache *sourcecache);
355
356 /*
357         Load shader programs
358 */
359 void load_shaders(std::string name, SourceShaderCache *sourcecache,
360                 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
361                 std::string &vertex_program, std::string &pixel_program,
362                 std::string &geometry_program, bool &is_highlevel);
363
364 ShaderSource::ShaderSource(IrrlichtDevice *device):
365                 m_device(device)
366 {
367         assert(m_device);
368
369         m_shader_callback = new ShaderCallback(this, "default");
370
371         m_main_thread = get_current_thread_id();
372
373         // Add a dummy ShaderInfo as the first index, named ""
374         m_shaderinfo_cache.push_back(ShaderInfo());
375
376         // Add main global constant setter
377         addGlobalConstantSetter(new MainShaderConstantSetter(device));
378 }
379
380 ShaderSource::~ShaderSource()
381 {
382         for (std::vector<IShaderConstantSetter*>::iterator iter = m_global_setters.begin();
383                         iter != m_global_setters.end(); iter++) {
384                 delete *iter;
385         }
386         m_global_setters.clear();
387
388         if (m_shader_callback) {
389                 m_shader_callback->drop();
390                 m_shader_callback = NULL;
391         }
392 }
393
394 u32 ShaderSource::getShader(const std::string &name, 
395                 const u8 material_type, const u8 drawtype)
396 {
397         /*
398                 Get shader
399         */
400
401         if(get_current_thread_id() == m_main_thread){
402                 return getShaderIdDirect(name, material_type, drawtype);
403         } else {
404                 /*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/
405
406                 // We're gonna ask the result to be put into here
407
408                 static ResultQueue<std::string, u32, u8, u8> result_queue;
409
410                 // Throw a request in
411                 m_get_shader_queue.add(name, 0, 0, &result_queue);
412
413                 /* infostream<<"Waiting for shader from main thread, name=\""
414                                 <<name<<"\""<<std::endl;*/
415
416                 while(true) {
417                         GetResult<std::string, u32, u8, u8>
418                                 result = result_queue.pop_frontNoEx();
419
420                         if (result.key == name) {
421                                 return result.item;
422                         }
423                         else {
424                                 errorstream << "Got shader with invalid name: " << result.key << std::endl;
425                         }
426                 }
427
428         }
429
430         infostream<<"getShader(): Failed"<<std::endl;
431
432         return 0;
433 }
434
435 /*
436         This method generates all the shaders
437 */
438 u32 ShaderSource::getShaderIdDirect(const std::string &name, 
439                 const u8 material_type, const u8 drawtype)
440 {
441         //infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
442
443         // Empty name means shader 0
444         if(name == ""){
445                 infostream<<"getShaderIdDirect(): name is empty"<<std::endl;
446                 return 0;
447         }
448
449         // Check if already have such instance
450         for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
451                 ShaderInfo *info = &m_shaderinfo_cache[i];
452                 if(info->name == name && info->material_type == material_type &&
453                         info->drawtype == drawtype)
454                         return i;
455         }
456
457         /*
458                 Calling only allowed from main thread
459         */
460         if(get_current_thread_id() != m_main_thread){
461                 errorstream<<"ShaderSource::getShaderIdDirect() "
462                                 "called not from main thread"<<std::endl;
463                 return 0;
464         }
465
466         ShaderInfo info = generate_shader(name, material_type, drawtype, m_device,
467                         m_shader_callback, &m_sourcecache);
468
469         /*
470                 Add shader to caches (add dummy shaders too)
471         */
472
473         JMutexAutoLock lock(m_shaderinfo_cache_mutex);
474
475         u32 id = m_shaderinfo_cache.size();
476         m_shaderinfo_cache.push_back(info);
477
478         infostream<<"getShaderIdDirect(): "
479                         <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;
480
481         return id;
482 }
483
484
485 ShaderInfo ShaderSource::getShaderInfo(u32 id)
486 {
487         JMutexAutoLock lock(m_shaderinfo_cache_mutex);
488
489         if(id >= m_shaderinfo_cache.size())
490                 return ShaderInfo();
491
492         return m_shaderinfo_cache[id];
493 }
494
495 void ShaderSource::processQueue()
496 {
497  
498
499 }
500
501 void ShaderSource::insertSourceShader(const std::string &name_of_shader,
502                 const std::string &filename, const std::string &program)
503 {
504         /*infostream<<"ShaderSource::insertSourceShader(): "
505                         "name_of_shader=\""<<name_of_shader<<"\", "
506                         "filename=\""<<filename<<"\""<<std::endl;*/
507
508         assert(get_current_thread_id() == m_main_thread);
509
510         m_sourcecache.insert(name_of_shader, filename, program, true);
511 }
512
513 void ShaderSource::rebuildShaders()
514 {
515         JMutexAutoLock lock(m_shaderinfo_cache_mutex);
516
517         /*// Oh well... just clear everything, they'll load sometime.
518         m_shaderinfo_cache.clear();
519         m_name_to_id.clear();*/
520
521         /*
522                 FIXME: Old shader materials can't be deleted in Irrlicht,
523                 or can they?
524                 (This would be nice to do in the destructor too)
525         */
526
527         // Recreate shaders
528         for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
529                 ShaderInfo *info = &m_shaderinfo_cache[i];
530                 if(info->name != ""){
531                         *info = generate_shader(info->name, info->material_type,
532                                         info->drawtype, m_device, m_shader_callback, &m_sourcecache);
533                 }
534         }
535 }
536
537 void ShaderSource::onSetConstants(video::IMaterialRendererServices *services,
538                 bool is_highlevel, const std::string &name)
539 {
540         for(u32 i=0; i<m_global_setters.size(); i++){
541                 IShaderConstantSetter *setter = m_global_setters[i];
542                 setter->onSetConstants(services, is_highlevel);
543         }
544 }
545
546 ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
547                 IrrlichtDevice *device, video::IShaderConstantSetCallBack *callback,
548                 SourceShaderCache *sourcecache)
549 {
550         ShaderInfo shaderinfo;
551         shaderinfo.name = name;
552         shaderinfo.material_type = material_type;
553         shaderinfo.drawtype = drawtype;
554         shaderinfo.material = video::EMT_SOLID;
555         switch(material_type){
556                 case TILE_MATERIAL_BASIC:
557                         shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
558                         break;
559                 case TILE_MATERIAL_ALPHA:
560                         shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
561                         break;
562                 case TILE_MATERIAL_LIQUID_TRANSPARENT:
563                         shaderinfo.base_material = video::EMT_TRANSPARENT_VERTEX_ALPHA;
564                         break;
565                 case TILE_MATERIAL_LIQUID_OPAQUE:
566                         shaderinfo.base_material = video::EMT_SOLID;
567                         break;
568                 case TILE_MATERIAL_WAVING_LEAVES:
569                         shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
570                         break;
571                 case TILE_MATERIAL_WAVING_PLANTS:
572                         shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
573                 break;
574         }
575         
576         bool enable_shaders = g_settings->getBool("enable_shaders");
577         if(!enable_shaders)
578                 return shaderinfo;
579
580         video::IVideoDriver* driver = device->getVideoDriver();
581         assert(driver);
582
583         video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
584         if(!gpu){
585                 errorstream<<"generate_shader(): "
586                                 "failed to generate \""<<name<<"\", "
587                                 "GPU programming not supported."
588                                 <<std::endl;
589                 return shaderinfo;
590         }
591
592         // Choose shader language depending on driver type and settings
593         // Then load shaders
594         std::string vertex_program;
595         std::string pixel_program;
596         std::string geometry_program;
597         bool is_highlevel;
598         load_shaders(name, sourcecache, driver->getDriverType(),
599                         enable_shaders, vertex_program, pixel_program,
600                         geometry_program, is_highlevel);
601         // Check hardware/driver support
602         if(vertex_program != "" &&
603                         !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
604                         !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
605                 infostream<<"generate_shader(): vertex shaders disabled "
606                                 "because of missing driver/hardware support."
607                                 <<std::endl;
608                 vertex_program = "";
609         }
610         if(pixel_program != "" &&
611                         !driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
612                         !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
613                 infostream<<"generate_shader(): pixel shaders disabled "
614                                 "because of missing driver/hardware support."
615                                 <<std::endl;
616                 pixel_program = "";
617         }
618         if(geometry_program != "" &&
619                         !driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
620                 infostream<<"generate_shader(): geometry shaders disabled "
621                                 "because of missing driver/hardware support."
622                                 <<std::endl;
623                 geometry_program = "";
624         }
625
626         // If no shaders are used, don't make a separate material type
627         if(vertex_program == "" && pixel_program == "" && geometry_program == "")
628                 return shaderinfo;
629
630         // Create shaders header
631         std::string shaders_header = "#version 120\n";
632
633         static const char* drawTypes[] = {
634                 "NDT_NORMAL",
635                 "NDT_AIRLIKE",
636                 "NDT_LIQUID",
637                 "NDT_FLOWINGLIQUID",
638                 "NDT_GLASSLIKE",
639                 "NDT_ALLFACES",
640                 "NDT_ALLFACES_OPTIONAL",
641                 "NDT_TORCHLIKE",
642                 "NDT_SIGNLIKE",
643                 "NDT_PLANTLIKE",
644                 "NDT_FENCELIKE",
645                 "NDT_RAILLIKE",
646                 "NDT_NODEBOX",
647                 "NDT_GLASSLIKE_FRAMED",
648                 "NDT_FIRELIKE",
649                 "NDT_GLASSLIKE_FRAMED_OPTIONAL"
650         };
651         
652         for (int i = 0; i < 14; i++){
653                 shaders_header += "#define ";
654                 shaders_header += drawTypes[i];
655                 shaders_header += " ";
656                 shaders_header += itos(i);
657                 shaders_header += "\n";
658         }
659
660         static const char* materialTypes[] = {
661                 "TILE_MATERIAL_BASIC",
662                 "TILE_MATERIAL_ALPHA",
663                 "TILE_MATERIAL_LIQUID_TRANSPARENT",
664                 "TILE_MATERIAL_LIQUID_OPAQUE",
665                 "TILE_MATERIAL_WAVING_LEAVES",
666                 "TILE_MATERIAL_WAVING_PLANTS"
667         };
668
669         for (int i = 0; i < 6; i++){
670                 shaders_header += "#define ";
671                 shaders_header += materialTypes[i];
672                 shaders_header += " ";
673                 shaders_header += itos(i);
674                 shaders_header += "\n";
675         }
676
677         shaders_header += "#define MATERIAL_TYPE ";
678         shaders_header += itos(material_type);
679         shaders_header += "\n";
680         shaders_header += "#define DRAW_TYPE ";
681         shaders_header += itos(drawtype);
682         shaders_header += "\n";
683
684         if (g_settings->getBool("generate_normalmaps")){
685                 shaders_header += "#define GENERATE_NORMALMAPS\n";
686                 shaders_header += "#define NORMALMAPS_STRENGTH ";
687                 shaders_header += ftos(g_settings->getFloat("normalmaps_strength"));
688                 shaders_header += "\n";
689                 float sample_step;
690                 int smooth = (int)g_settings->getFloat("normalmaps_smooth");
691                 switch (smooth){
692                 case 0:
693                         sample_step = 0.0078125; // 1.0 / 128.0
694                         break;
695                 case 1:
696                         sample_step = 0.00390625; // 1.0 / 256.0
697                         break;
698                 case 2:
699                         sample_step = 0.001953125; // 1.0 / 512.0
700                         break;
701                 default:
702                         sample_step = 0.0078125;
703                         break;
704                 }
705                 shaders_header += "#define SAMPLE_STEP ";
706                 shaders_header += ftos(sample_step);
707                 shaders_header += "\n";
708         }
709
710         if (g_settings->getBool("enable_bumpmapping"))
711                 shaders_header += "#define ENABLE_BUMPMAPPING\n";
712
713         if (g_settings->getBool("enable_parallax_occlusion")){
714                 shaders_header += "#define ENABLE_PARALLAX_OCCLUSION\n";
715                 shaders_header += "#define PARALLAX_OCCLUSION_SCALE ";
716                 shaders_header += ftos(g_settings->getFloat("parallax_occlusion_scale"));
717                 shaders_header += "\n";
718                 shaders_header += "#define PARALLAX_OCCLUSION_BIAS ";
719                 shaders_header += ftos(g_settings->getFloat("parallax_occlusion_bias"));
720                 shaders_header += "\n";
721         }
722
723         if (g_settings->getBool("enable_bumpmapping") || g_settings->getBool("enable_parallax_occlusion"))
724                 shaders_header += "#define USE_NORMALMAPS\n";
725
726         if (g_settings->getBool("enable_waving_water")){
727                 shaders_header += "#define ENABLE_WAVING_WATER 1\n";
728                 shaders_header += "#define WATER_WAVE_HEIGHT ";
729                 shaders_header += ftos(g_settings->getFloat("water_wave_height"));
730                 shaders_header += "\n";
731                 shaders_header += "#define WATER_WAVE_LENGTH ";
732                 shaders_header += ftos(g_settings->getFloat("water_wave_length"));
733                 shaders_header += "\n";
734                 shaders_header += "#define WATER_WAVE_SPEED ";
735                 shaders_header += ftos(g_settings->getFloat("water_wave_speed"));
736                 shaders_header += "\n";
737         } else{
738                 shaders_header += "#define ENABLE_WAVING_WATER 0\n";
739         }
740
741         shaders_header += "#define ENABLE_WAVING_LEAVES ";
742         if (g_settings->getBool("enable_waving_leaves"))
743                 shaders_header += "1\n";
744         else    
745                 shaders_header += "0\n";
746
747         shaders_header += "#define ENABLE_WAVING_PLANTS ";              
748         if (g_settings->getBool("enable_waving_plants"))
749                 shaders_header += "1\n";
750         else
751                 shaders_header += "0\n";
752
753         if(pixel_program != "")
754                 pixel_program = shaders_header + pixel_program;
755         if(vertex_program != "")
756                 vertex_program = shaders_header + vertex_program;
757         if(geometry_program != "")
758                 geometry_program = shaders_header + geometry_program;
759
760         // Call addHighLevelShaderMaterial() or addShaderMaterial()
761         const c8* vertex_program_ptr = 0;
762         const c8* pixel_program_ptr = 0;
763         const c8* geometry_program_ptr = 0;
764         if(vertex_program != "")
765                 vertex_program_ptr = vertex_program.c_str();
766         if(pixel_program != "")
767                 pixel_program_ptr = pixel_program.c_str();
768         if(geometry_program != "")
769                 geometry_program_ptr = geometry_program.c_str();
770         s32 shadermat = -1;
771         if(is_highlevel){
772                 infostream<<"Compiling high level shaders for "<<name<<std::endl;
773                 shadermat = gpu->addHighLevelShaderMaterial(
774                         vertex_program_ptr,   // Vertex shader program
775                         "vertexMain",         // Vertex shader entry point
776                         video::EVST_VS_1_1,   // Vertex shader version
777                         pixel_program_ptr,    // Pixel shader program
778                         "pixelMain",          // Pixel shader entry point
779                         video::EPST_PS_1_1,   // Pixel shader version
780                         geometry_program_ptr, // Geometry shader program
781                         "geometryMain",       // Geometry shader entry point
782                         video::EGST_GS_4_0,   // Geometry shader version
783                         scene::EPT_TRIANGLES,      // Geometry shader input
784                         scene::EPT_TRIANGLE_STRIP, // Geometry shader output
785                         0,                         // Support maximum number of vertices
786                         callback,                  // Set-constant callback
787                         shaderinfo.base_material,  // Base material
788                         1                          // Userdata passed to callback
789                         );
790                 if(shadermat == -1){
791                         errorstream<<"generate_shader(): "
792                                         "failed to generate \""<<name<<"\", "
793                                         "addHighLevelShaderMaterial failed."
794                                         <<std::endl;
795                         return shaderinfo;
796                 }
797         }
798         else{
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                         callback,             // Set-constant callback
804                         shaderinfo.base_material,  // Base material
805                         0                     // Userdata passed to callback
806                         );
807
808                 if(shadermat == -1){
809                         errorstream<<"generate_shader(): "
810                                         "failed to generate \""<<name<<"\", "
811                                         "addShaderMaterial failed."
812                                         <<std::endl;
813                         return shaderinfo;
814                 }
815         }
816
817         // HACK, TODO: investigate this better
818         // Grab the material renderer once more so minetest doesn't crash on exit
819         driver->getMaterialRenderer(shadermat)->grab();
820
821         // Apply the newly created material type
822         shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
823         return shaderinfo;
824 }
825
826 void load_shaders(std::string name, SourceShaderCache *sourcecache,
827                 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
828                 std::string &vertex_program, std::string &pixel_program,
829                 std::string &geometry_program, bool &is_highlevel)
830 {
831         vertex_program = "";
832         pixel_program = "";
833         geometry_program = "";
834         is_highlevel = false;
835
836         if(enable_shaders){
837                 // Look for high level shaders
838                 if(drivertype == video::EDT_DIRECT3D9){
839                         // Direct3D 9: HLSL
840                         // (All shaders in one file)
841                         vertex_program = sourcecache->getOrLoad(name, "d3d9.hlsl");
842                         pixel_program = vertex_program;
843                         geometry_program = vertex_program;
844                 }
845                 else if(drivertype == video::EDT_OPENGL){
846                         // OpenGL: GLSL
847                         vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.glsl");
848                         pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.glsl");
849                         geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl");
850                 }
851                 if(vertex_program != "" || pixel_program != "" || geometry_program != ""){
852                         is_highlevel = true;
853                         return;
854                 }
855         }
856
857 }