]> git.lizzy.rs Git - dragonfireclient.git/blob - src/client/shader.cpp
c5fe5dfe00bc28b5fcaa1cfcc25eb1a24eda6cde
[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 #if ENABLE_GLES
42 #ifdef _IRR_COMPILE_WITH_OGLES1_
43 #include <GLES/gl.h>
44 #else
45 #include <GLES2/gl2.h>
46 #endif
47 #else
48 #ifndef __APPLE__
49 #include <GL/gl.h>
50 #else
51 #define GL_SILENCE_DEPRECATION
52 #include <OpenGL/gl.h>
53 #endif
54 #endif
55
56 /*
57         A cache from shader name to shader path
58 */
59 MutexedMap<std::string, std::string> g_shadername_to_path_cache;
60
61 /*
62         Gets the path to a shader by first checking if the file
63           name_of_shader/filename
64         exists in shader_path and if not, using the data path.
65
66         If not found, returns "".
67
68         Utilizes a thread-safe cache.
69 */
70 std::string getShaderPath(const std::string &name_of_shader,
71                 const std::string &filename)
72 {
73         std::string combined = name_of_shader + DIR_DELIM + filename;
74         std::string fullpath;
75         /*
76                 Check from cache
77         */
78         bool incache = g_shadername_to_path_cache.get(combined, &fullpath);
79         if(incache)
80                 return fullpath;
81
82         /*
83                 Check from shader_path
84         */
85         std::string shader_path = g_settings->get("shader_path");
86         if (!shader_path.empty()) {
87                 std::string testpath = shader_path + DIR_DELIM + combined;
88                 if(fs::PathExists(testpath))
89                         fullpath = testpath;
90         }
91
92         /*
93                 Check from default data directory
94         */
95         if (fullpath.empty()) {
96                 std::string rel_path = std::string("client") + DIR_DELIM
97                                 + "shaders" + DIR_DELIM
98                                 + name_of_shader + DIR_DELIM
99                                 + filename;
100                 std::string testpath = porting::path_share + DIR_DELIM + rel_path;
101                 if(fs::PathExists(testpath))
102                         fullpath = testpath;
103         }
104
105         // Add to cache (also an empty result is cached)
106         g_shadername_to_path_cache.set(combined, fullpath);
107
108         // Finally return it
109         return fullpath;
110 }
111
112 /*
113         SourceShaderCache: A cache used for storing source shaders.
114 */
115
116 class SourceShaderCache
117 {
118 public:
119         void insert(const std::string &name_of_shader, const std::string &filename,
120                 const std::string &program, bool prefer_local)
121         {
122                 std::string combined = name_of_shader + DIR_DELIM + filename;
123                 // Try to use local shader instead if asked to
124                 if(prefer_local){
125                         std::string path = getShaderPath(name_of_shader, filename);
126                         if(!path.empty()){
127                                 std::string p = readFile(path);
128                                 if (!p.empty()) {
129                                         m_programs[combined] = p;
130                                         return;
131                                 }
132                         }
133                 }
134                 m_programs[combined] = program;
135         }
136
137         std::string get(const std::string &name_of_shader,
138                 const std::string &filename)
139         {
140                 std::string combined = name_of_shader + DIR_DELIM + filename;
141                 StringMap::iterator n = m_programs.find(combined);
142                 if (n != m_programs.end())
143                         return n->second;
144                 return "";
145         }
146
147         // Primarily fetches from cache, secondarily tries to read from filesystem
148         std::string getOrLoad(const std::string &name_of_shader,
149                 const std::string &filename)
150         {
151                 std::string combined = name_of_shader + DIR_DELIM + filename;
152                 StringMap::iterator n = m_programs.find(combined);
153                 if (n != m_programs.end())
154                         return n->second;
155                 std::string path = getShaderPath(name_of_shader, filename);
156                 if (path.empty()) {
157                         infostream << "SourceShaderCache::getOrLoad(): No path found for \""
158                                 << combined << "\"" << std::endl;
159                         return "";
160                 }
161                 infostream << "SourceShaderCache::getOrLoad(): Loading path \""
162                         << path << "\"" << std::endl;
163                 std::string p = readFile(path);
164                 if (!p.empty()) {
165                         m_programs[combined] = p;
166                         return p;
167                 }
168                 return "";
169         }
170 private:
171         StringMap m_programs;
172
173         std::string readFile(const std::string &path)
174         {
175                 std::ifstream is(path.c_str(), std::ios::binary);
176                 if(!is.is_open())
177                         return "";
178                 std::ostringstream tmp_os;
179                 tmp_os << is.rdbuf();
180                 return tmp_os.str();
181         }
182 };
183
184
185 /*
186         ShaderCallback: Sets constants that can be used in shaders
187 */
188
189 class ShaderCallback : public video::IShaderConstantSetCallBack
190 {
191         std::vector<IShaderConstantSetter*> m_setters;
192
193 public:
194         ShaderCallback(const std::vector<IShaderConstantSetterFactory *> &factories)
195         {
196                 for (IShaderConstantSetterFactory *factory : factories)
197                         m_setters.push_back(factory->create());
198         }
199
200         ~ShaderCallback()
201         {
202                 for (IShaderConstantSetter *setter : m_setters)
203                         delete setter;
204         }
205
206         virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData) override
207         {
208                 video::IVideoDriver *driver = services->getVideoDriver();
209                 sanity_check(driver != NULL);
210
211                 bool is_highlevel = userData;
212
213                 for (IShaderConstantSetter *setter : m_setters)
214                         setter->onSetConstants(services, is_highlevel);
215         }
216
217         virtual void OnSetMaterial(const video::SMaterial& material) override
218         {
219                 for (IShaderConstantSetter *setter : m_setters)
220                         setter->onSetMaterial(material);
221         }
222 };
223
224
225 /*
226         MainShaderConstantSetter: Set basic constants required for almost everything
227 */
228
229 class MainShaderConstantSetter : public IShaderConstantSetter
230 {
231         CachedVertexShaderSetting<float, 16> m_world_view_proj;
232         CachedVertexShaderSetting<float, 16> m_world;
233
234 public:
235         MainShaderConstantSetter() :
236                 m_world_view_proj("mWorldViewProj"),
237                 m_world("mWorld")
238         {}
239         ~MainShaderConstantSetter() = default;
240
241         virtual void onSetConstants(video::IMaterialRendererServices *services,
242                         bool is_highlevel)
243         {
244                 video::IVideoDriver *driver = services->getVideoDriver();
245                 sanity_check(driver);
246
247                 // Set clip matrix
248                 core::matrix4 worldViewProj;
249                 worldViewProj = driver->getTransform(video::ETS_PROJECTION);
250                 worldViewProj *= driver->getTransform(video::ETS_VIEW);
251                 worldViewProj *= driver->getTransform(video::ETS_WORLD);
252                 if (is_highlevel)
253                         m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
254                 else
255                         services->setVertexShaderConstant(worldViewProj.pointer(), 0, 4);
256
257                 // Set world matrix
258                 core::matrix4 world = driver->getTransform(video::ETS_WORLD);
259                 if (is_highlevel)
260                         m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
261                 else
262                         services->setVertexShaderConstant(world.pointer(), 4, 4);
263
264         }
265 };
266
267
268 class MainShaderConstantSetterFactory : public IShaderConstantSetterFactory
269 {
270 public:
271         virtual IShaderConstantSetter* create()
272                 { return new MainShaderConstantSetter(); }
273 };
274
275
276 /*
277         ShaderSource
278 */
279
280 class ShaderSource : public IWritableShaderSource
281 {
282 public:
283         ShaderSource();
284         ~ShaderSource();
285
286         /*
287                 - If shader material specified by name is found from cache,
288                   return the cached id.
289                 - Otherwise generate the shader material, add to cache and return id.
290
291                 The id 0 points to a null shader. Its material is EMT_SOLID.
292         */
293         u32 getShaderIdDirect(const std::string &name,
294                 const u8 material_type, const u8 drawtype);
295
296         /*
297                 If shader specified by the name pointed by the id doesn't
298                 exist, create it, then return id.
299
300                 Can be called from any thread. If called from some other thread
301                 and not found in cache, the call is queued to the main thread
302                 for processing.
303         */
304
305         u32 getShader(const std::string &name,
306                 const u8 material_type, const u8 drawtype);
307
308         ShaderInfo getShaderInfo(u32 id);
309
310         // Processes queued shader requests from other threads.
311         // Shall be called from the main thread.
312         void processQueue();
313
314         // Insert a shader program into the cache without touching the
315         // filesystem. Shall be called from the main thread.
316         void insertSourceShader(const std::string &name_of_shader,
317                 const std::string &filename, const std::string &program);
318
319         // Rebuild shaders from the current set of source shaders
320         // Shall be called from the main thread.
321         void rebuildShaders();
322
323         void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter)
324         {
325                 m_setter_factories.push_back(setter);
326         }
327
328 private:
329
330         // The id of the thread that is allowed to use irrlicht directly
331         std::thread::id m_main_thread;
332
333         // Cache of source shaders
334         // This should be only accessed from the main thread
335         SourceShaderCache m_sourcecache;
336
337         // A shader id is index in this array.
338         // The first position contains a dummy shader.
339         std::vector<ShaderInfo> m_shaderinfo_cache;
340         // The former container is behind this mutex
341         std::mutex m_shaderinfo_cache_mutex;
342
343         // Queued shader fetches (to be processed by the main thread)
344         RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
345
346         // Global constant setter factories
347         std::vector<IShaderConstantSetterFactory *> m_setter_factories;
348
349         // Shader callbacks
350         std::vector<ShaderCallback *> m_callbacks;
351 };
352
353 IWritableShaderSource *createShaderSource()
354 {
355         return new ShaderSource();
356 }
357
358 /*
359         Generate shader given the shader name.
360 */
361 ShaderInfo generate_shader(const std::string &name,
362                 u8 material_type, u8 drawtype, std::vector<ShaderCallback *> &callbacks,
363                 const std::vector<IShaderConstantSetterFactory *> &setter_factories,
364                 SourceShaderCache *sourcecache);
365
366 /*
367         Load shader programs
368 */
369 void load_shaders(const std::string &name, SourceShaderCache *sourcecache,
370                 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
371                 std::string &vertex_program, std::string &pixel_program,
372                 std::string &geometry_program, bool &is_highlevel);
373
374 ShaderSource::ShaderSource()
375 {
376         m_main_thread = std::this_thread::get_id();
377
378         // Add a dummy ShaderInfo as the first index, named ""
379         m_shaderinfo_cache.emplace_back();
380
381         // Add main global constant setter
382         addShaderConstantSetterFactory(new MainShaderConstantSetterFactory());
383 }
384
385 ShaderSource::~ShaderSource()
386 {
387         for (ShaderCallback *callback : m_callbacks) {
388                 delete callback;
389         }
390         for (IShaderConstantSetterFactory *setter_factorie : m_setter_factories) {
391                 delete setter_factorie;
392         }
393 }
394
395 u32 ShaderSource::getShader(const std::string &name,
396                 const u8 material_type, const u8 drawtype)
397 {
398         /*
399                 Get shader
400         */
401
402         if (std::this_thread::get_id() == m_main_thread) {
403                 return getShaderIdDirect(name, material_type, drawtype);
404         }
405
406         /*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/
407
408         // We're gonna ask the result to be put into here
409
410         static ResultQueue<std::string, u32, u8, u8> result_queue;
411
412         // Throw a request in
413         m_get_shader_queue.add(name, 0, 0, &result_queue);
414
415         /* infostream<<"Waiting for shader from main thread, name=\""
416                         <<name<<"\""<<std::endl;*/
417
418         while(true) {
419                 GetResult<std::string, u32, u8, u8>
420                         result = result_queue.pop_frontNoEx();
421
422                 if (result.key == name) {
423                         return result.item;
424                 }
425
426                 errorstream << "Got shader with invalid name: " << result.key << std::endl;
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.empty()) {
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 (std::this_thread::get_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,
466                         m_callbacks, m_setter_factories, &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(std::this_thread::get_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 (ShaderInfo &i : m_shaderinfo_cache) {
528                 ShaderInfo *info = &i;
529                 if (!info->name.empty()) {
530                         *info = generate_shader(info->name, info->material_type,
531                                         info->drawtype, m_callbacks,
532                                         m_setter_factories, &m_sourcecache);
533                 }
534         }
535 }
536
537
538 ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtype,
539                 std::vector<ShaderCallback *> &callbacks,
540                 const std::vector<IShaderConstantSetterFactory *> &setter_factories,
541                 SourceShaderCache *sourcecache)
542 {
543         ShaderInfo shaderinfo;
544         shaderinfo.name = name;
545         shaderinfo.material_type = material_type;
546         shaderinfo.drawtype = drawtype;
547         shaderinfo.material = video::EMT_SOLID;
548         switch (material_type) {
549         case TILE_MATERIAL_OPAQUE:
550         case TILE_MATERIAL_LIQUID_OPAQUE:
551         case TILE_MATERIAL_WAVING_LIQUID_OPAQUE:
552                 shaderinfo.base_material = video::EMT_SOLID;
553                 break;
554         case TILE_MATERIAL_ALPHA:
555         case TILE_MATERIAL_PLAIN_ALPHA:
556         case TILE_MATERIAL_LIQUID_TRANSPARENT:
557         case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
558                 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
559                 break;
560         case TILE_MATERIAL_BASIC:
561         case TILE_MATERIAL_PLAIN:
562         case TILE_MATERIAL_WAVING_LEAVES:
563         case TILE_MATERIAL_WAVING_PLANTS:
564         case TILE_MATERIAL_WAVING_LIQUID_BASIC:
565                 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
566                 break;
567         }
568
569         bool enable_shaders = g_settings->getBool("enable_shaders");
570         if (!enable_shaders)
571                 return shaderinfo;
572
573         video::IVideoDriver *driver = RenderingEngine::get_video_driver();
574
575         video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
576         if(!gpu){
577                 errorstream<<"generate_shader(): "
578                                 "failed to generate \""<<name<<"\", "
579                                 "GPU programming not supported."
580                                 <<std::endl;
581                 return shaderinfo;
582         }
583
584         // Choose shader language depending on driver type and settings
585         // Then load shaders
586         std::string vertex_program;
587         std::string pixel_program;
588         std::string geometry_program;
589         bool is_highlevel;
590         load_shaders(name, sourcecache, driver->getDriverType(),
591                         enable_shaders, vertex_program, pixel_program,
592                         geometry_program, is_highlevel);
593         // Check hardware/driver support
594         if (!vertex_program.empty() &&
595                         !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
596                         !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
597                 infostream<<"generate_shader(): vertex shaders disabled "
598                                 "because of missing driver/hardware support."
599                                 <<std::endl;
600                 vertex_program = "";
601         }
602         if (!pixel_program.empty() &&
603                         !driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
604                         !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
605                 infostream<<"generate_shader(): pixel shaders disabled "
606                                 "because of missing driver/hardware support."
607                                 <<std::endl;
608                 pixel_program = "";
609         }
610         if (!geometry_program.empty() &&
611                         !driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
612                 infostream<<"generate_shader(): geometry shaders disabled "
613                                 "because of missing driver/hardware support."
614                                 <<std::endl;
615                 geometry_program = "";
616         }
617
618         // If no shaders are used, don't make a separate material type
619         if (vertex_program.empty() && pixel_program.empty() && geometry_program.empty())
620                 return shaderinfo;
621
622         // Create shaders header
623         std::string shaders_header = "#version 120\n";
624
625 #ifdef __unix__
626         // For renderers that should use discard instead of GL_ALPHA_TEST
627         const char* gl_renderer = (const char*)glGetString(GL_RENDERER);
628         if (strstr(gl_renderer, "GC7000")) {
629                 shaders_header += "#define USE_DISCARD\n";
630         }
631 #endif
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                 "NDT_PLANTLIKE_ROOTED",
651         };
652
653         for (int i = 0; i < 14; i++){
654                 shaders_header += "#define ";
655                 shaders_header += drawTypes[i];
656                 shaders_header += " ";
657                 shaders_header += itos(i);
658                 shaders_header += "\n";
659         }
660
661         static const char* materialTypes[] = {
662                 "TILE_MATERIAL_BASIC",
663                 "TILE_MATERIAL_ALPHA",
664                 "TILE_MATERIAL_LIQUID_TRANSPARENT",
665                 "TILE_MATERIAL_LIQUID_OPAQUE",
666                 "TILE_MATERIAL_WAVING_LEAVES",
667                 "TILE_MATERIAL_WAVING_PLANTS",
668                 "TILE_MATERIAL_OPAQUE",
669                 "TILE_MATERIAL_WAVING_LIQUID_BASIC",
670                 "TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT",
671                 "TILE_MATERIAL_WAVING_LIQUID_OPAQUE",
672                 "TILE_MATERIAL_PLAIN",
673                 "TILE_MATERIAL_PLAIN_ALPHA",
674         };
675
676         for (int i = 0; i < 12; i++){
677                 shaders_header += "#define ";
678                 shaders_header += materialTypes[i];
679                 shaders_header += " ";
680                 shaders_header += itos(i);
681                 shaders_header += "\n";
682         }
683
684         shaders_header += "#define MATERIAL_TYPE ";
685         shaders_header += itos(material_type);
686         shaders_header += "\n";
687         shaders_header += "#define DRAW_TYPE ";
688         shaders_header += itos(drawtype);
689         shaders_header += "\n";
690
691         if (g_settings->getBool("enable_bumpmapping"))
692                 shaders_header += "#define ENABLE_BUMPMAPPING\n";
693
694         if (g_settings->getBool("enable_parallax_occlusion")){
695                 int mode = g_settings->getFloat("parallax_occlusion_mode");
696                 float scale = g_settings->getFloat("parallax_occlusion_scale");
697                 float bias = g_settings->getFloat("parallax_occlusion_bias");
698                 int iterations = g_settings->getFloat("parallax_occlusion_iterations");
699                 shaders_header += "#define ENABLE_PARALLAX_OCCLUSION\n";
700                 shaders_header += "#define PARALLAX_OCCLUSION_MODE ";
701                 shaders_header += itos(mode);
702                 shaders_header += "\n";
703                 shaders_header += "#define PARALLAX_OCCLUSION_SCALE ";
704                 shaders_header += ftos(scale);
705                 shaders_header += "\n";
706                 shaders_header += "#define PARALLAX_OCCLUSION_BIAS ";
707                 shaders_header += ftos(bias);
708                 shaders_header += "\n";
709                 shaders_header += "#define PARALLAX_OCCLUSION_ITERATIONS ";
710                 shaders_header += itos(iterations);
711                 shaders_header += "\n";
712         }
713
714         shaders_header += "#define USE_NORMALMAPS ";
715         if (g_settings->getBool("enable_bumpmapping") || g_settings->getBool("enable_parallax_occlusion"))
716                 shaders_header += "1\n";
717         else
718                 shaders_header += "0\n";
719
720         if (g_settings->getBool("enable_waving_water")){
721                 shaders_header += "#define ENABLE_WAVING_WATER 1\n";
722                 shaders_header += "#define WATER_WAVE_HEIGHT ";
723                 shaders_header += ftos(g_settings->getFloat("water_wave_height"));
724                 shaders_header += "\n";
725                 shaders_header += "#define WATER_WAVE_LENGTH ";
726                 shaders_header += ftos(g_settings->getFloat("water_wave_length"));
727                 shaders_header += "\n";
728                 shaders_header += "#define WATER_WAVE_SPEED ";
729                 shaders_header += ftos(g_settings->getFloat("water_wave_speed"));
730                 shaders_header += "\n";
731         } else{
732                 shaders_header += "#define ENABLE_WAVING_WATER 0\n";
733         }
734
735         shaders_header += "#define ENABLE_WAVING_LEAVES ";
736         if (g_settings->getBool("enable_waving_leaves"))
737                 shaders_header += "1\n";
738         else
739                 shaders_header += "0\n";
740
741         shaders_header += "#define ENABLE_WAVING_PLANTS ";
742         if (g_settings->getBool("enable_waving_plants"))
743                 shaders_header += "1\n";
744         else
745                 shaders_header += "0\n";
746
747         if (g_settings->getBool("tone_mapping"))
748                 shaders_header += "#define ENABLE_TONE_MAPPING\n";
749
750         shaders_header += "#define FOG_START ";
751         shaders_header += ftos(rangelim(g_settings->getFloat("fog_start"), 0.0f, 0.99f));
752         shaders_header += "\n";
753
754         // Call addHighLevelShaderMaterial() or addShaderMaterial()
755         const c8* vertex_program_ptr = 0;
756         const c8* pixel_program_ptr = 0;
757         const c8* geometry_program_ptr = 0;
758         if (!vertex_program.empty()) {
759                 vertex_program = shaders_header + vertex_program;
760                 vertex_program_ptr = vertex_program.c_str();
761         }
762         if (!pixel_program.empty()) {
763                 pixel_program = shaders_header + pixel_program;
764                 pixel_program_ptr = pixel_program.c_str();
765         }
766         if (!geometry_program.empty()) {
767                 geometry_program = shaders_header + geometry_program;
768                 geometry_program_ptr = geometry_program.c_str();
769         }
770         ShaderCallback *cb = new ShaderCallback(setter_factories);
771         s32 shadermat = -1;
772         if(is_highlevel){
773                 infostream<<"Compiling high level shaders for "<<name<<std::endl;
774                 shadermat = gpu->addHighLevelShaderMaterial(
775                         vertex_program_ptr,   // Vertex shader program
776                         "vertexMain",         // Vertex shader entry point
777                         video::EVST_VS_1_1,   // Vertex shader version
778                         pixel_program_ptr,    // Pixel shader program
779                         "pixelMain",          // Pixel shader entry point
780                         video::EPST_PS_1_2,   // Pixel shader version
781                         geometry_program_ptr, // Geometry shader program
782                         "geometryMain",       // Geometry shader entry point
783                         video::EGST_GS_4_0,   // Geometry shader version
784                         scene::EPT_TRIANGLES,      // Geometry shader input
785                         scene::EPT_TRIANGLE_STRIP, // Geometry shader output
786                         0,                         // Support maximum number of vertices
787                         cb, // Set-constant callback
788                         shaderinfo.base_material,  // Base material
789                         1                          // Userdata passed to callback
790                         );
791                 if(shadermat == -1){
792                         errorstream<<"generate_shader(): "
793                                         "failed to generate \""<<name<<"\", "
794                                         "addHighLevelShaderMaterial failed."
795                                         <<std::endl;
796                         dumpShaderProgram(warningstream, "Vertex", vertex_program);
797                         dumpShaderProgram(warningstream, "Pixel", pixel_program);
798                         dumpShaderProgram(warningstream, "Geometry", geometry_program);
799                         delete cb;
800                         return shaderinfo;
801                 }
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 \""<<name<<"\", "
816                                         "addShaderMaterial failed."
817                                         <<std::endl;
818                         dumpShaderProgram(warningstream, "Vertex", vertex_program);
819                         dumpShaderProgram(warningstream,"Pixel", pixel_program);
820                         delete cb;
821                         return shaderinfo;
822                 }
823         }
824         callbacks.push_back(cb);
825
826         // HACK, TODO: investigate this better
827         // Grab the material renderer once more so minetest doesn't crash on exit
828         driver->getMaterialRenderer(shadermat)->grab();
829
830         // Apply the newly created material type
831         shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
832         return shaderinfo;
833 }
834
835 void load_shaders(const std::string &name, SourceShaderCache *sourcecache,
836                 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
837                 std::string &vertex_program, std::string &pixel_program,
838                 std::string &geometry_program, bool &is_highlevel)
839 {
840         vertex_program = "";
841         pixel_program = "";
842         geometry_program = "";
843         is_highlevel = false;
844
845         if(enable_shaders){
846                 // Look for high level shaders
847                 if(drivertype == video::EDT_DIRECT3D9){
848                         // Direct3D 9: HLSL
849                         // (All shaders in one file)
850                         vertex_program = sourcecache->getOrLoad(name, "d3d9.hlsl");
851                         pixel_program = vertex_program;
852                         geometry_program = vertex_program;
853                 }
854                 else if(drivertype == video::EDT_OPENGL){
855                         // OpenGL: GLSL
856                         vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.glsl");
857                         pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.glsl");
858                         geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl");
859                 }
860                 if (!vertex_program.empty() || !pixel_program.empty() || !geometry_program.empty()){
861                         is_highlevel = true;
862                         return;
863                 }
864         }
865
866 }
867
868 void dumpShaderProgram(std::ostream &output_stream,
869                 const std::string &program_type, const std::string &program)
870 {
871         output_stream << program_type << " shader program:" << std::endl <<
872                 "----------------------------------" << std::endl;
873         size_t pos = 0;
874         size_t prev = 0;
875         s16 line = 1;
876         while ((pos = program.find('\n', prev)) != std::string::npos) {
877                 output_stream << line++ << ": "<< program.substr(prev, pos - prev) <<
878                         std::endl;
879                 prev = pos + 1;
880         }
881         output_stream << line << ": " << program.substr(prev) << std::endl <<
882                 "End of " << program_type << " shader program." << std::endl <<
883                 " " << std::endl;
884 }