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