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