]> git.lizzy.rs Git - minetest.git/blob - src/shader.cpp
6e89d75adca0d18739b4eefdbfe0909d8dc0a260
[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 "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,
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 /*
173         ShaderCallback: Sets constants that can be used in shaders
174 */
175
176 class ShaderCallback : public video::IShaderConstantSetCallBack
177 {
178         std::vector<IShaderConstantSetter*> m_setters;
179
180 public:
181         ShaderCallback(const std::vector<IShaderConstantSetterFactory *> &factories)
182         {
183                 for (u32 i = 0; i < factories.size(); ++i)
184                         m_setters.push_back(factories[i]->create());
185         }
186
187         ~ShaderCallback()
188         {
189                 for (u32 i = 0; i < m_setters.size(); ++i)
190                         delete m_setters[i];
191         }
192
193         virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData)
194         {
195                 video::IVideoDriver *driver = services->getVideoDriver();
196                 sanity_check(driver != NULL);
197
198                 bool is_highlevel = userData;
199
200                 for (u32 i = 0; i < m_setters.size(); ++i)
201                         m_setters[i]->onSetConstants(services, is_highlevel);
202         }
203 };
204
205
206 /*
207         MainShaderConstantSetter: Set basic constants required for almost everything
208 */
209
210 class MainShaderConstantSetter : public IShaderConstantSetter
211 {
212         CachedVertexShaderSetting<float, 16> m_world_view_proj;
213         CachedVertexShaderSetting<float, 16> m_world;
214
215 public:
216         MainShaderConstantSetter() :
217                 m_world_view_proj("mWorldViewProj"),
218                 m_world("mWorld")
219         {}
220         ~MainShaderConstantSetter() {}
221
222         virtual void onSetConstants(video::IMaterialRendererServices *services,
223                         bool is_highlevel)
224         {
225                 video::IVideoDriver *driver = services->getVideoDriver();
226                 sanity_check(driver);
227
228                 // Set clip matrix
229                 core::matrix4 worldViewProj;
230                 worldViewProj = driver->getTransform(video::ETS_PROJECTION);
231                 worldViewProj *= driver->getTransform(video::ETS_VIEW);
232                 worldViewProj *= driver->getTransform(video::ETS_WORLD);
233                 if (is_highlevel)
234                         m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
235                 else
236                         services->setVertexShaderConstant(worldViewProj.pointer(), 0, 4);
237
238                 // Set world matrix
239                 core::matrix4 world = driver->getTransform(video::ETS_WORLD);
240                 if (is_highlevel)
241                         m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
242                 else
243                         services->setVertexShaderConstant(world.pointer(), 4, 4);
244
245         }
246 };
247
248
249 class MainShaderConstantSetterFactory : public IShaderConstantSetterFactory
250 {
251 public:
252         virtual IShaderConstantSetter* create()
253                 { return new MainShaderConstantSetter(); }
254 };
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,
275                 const u8 material_type, 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,
287                 const u8 material_type, const u8 drawtype);
288
289         ShaderInfo getShaderInfo(u32 id);
290
291         // Processes queued shader requests from other threads.
292         // Shall be called from the main thread.
293         void processQueue();
294
295         // Insert a shader program into the cache without touching the
296         // filesystem. Shall be called from the main thread.
297         void insertSourceShader(const std::string &name_of_shader,
298                 const std::string &filename, const std::string &program);
299
300         // Rebuild shaders from the current set of source shaders
301         // Shall be called from the main thread.
302         void rebuildShaders();
303
304         void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter)
305         {
306                 m_setter_factories.push_back(setter);
307         }
308
309 private:
310
311         // The id of the thread that is allowed to use irrlicht directly
312         std::thread::id m_main_thread;
313
314         // Cache of source shaders
315         // This should be only accessed from the main thread
316         SourceShaderCache m_sourcecache;
317
318         // A shader id is index in this array.
319         // The first position contains a dummy shader.
320         std::vector<ShaderInfo> m_shaderinfo_cache;
321         // The former container is behind this mutex
322         std::mutex m_shaderinfo_cache_mutex;
323
324         // Queued shader fetches (to be processed by the main thread)
325         RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
326
327         // Global constant setter factories
328         std::vector<IShaderConstantSetterFactory *> m_setter_factories;
329
330         // Shader callbacks
331         std::vector<ShaderCallback *> m_callbacks;
332 };
333
334 IWritableShaderSource *createShaderSource()
335 {
336         return new ShaderSource();
337 }
338
339 /*
340         Generate shader given the shader name.
341 */
342 ShaderInfo generate_shader(const std::string &name,
343                 u8 material_type, u8 drawtype, std::vector<ShaderCallback *> &callbacks,
344                 const std::vector<IShaderConstantSetterFactory *> &setter_factories,
345                 SourceShaderCache *sourcecache);
346
347 /*
348         Load shader programs
349 */
350 void load_shaders(std::string name, SourceShaderCache *sourcecache,
351                 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
352                 std::string &vertex_program, std::string &pixel_program,
353                 std::string &geometry_program, bool &is_highlevel);
354
355 ShaderSource::ShaderSource()
356 {
357         m_main_thread = std::this_thread::get_id();
358
359         // Add a dummy ShaderInfo as the first index, named ""
360         m_shaderinfo_cache.push_back(ShaderInfo());
361
362         // Add main global constant setter
363         addShaderConstantSetterFactory(new MainShaderConstantSetterFactory());
364 }
365
366 ShaderSource::~ShaderSource()
367 {
368         for (std::vector<ShaderCallback *>::iterator iter = m_callbacks.begin();
369                         iter != m_callbacks.end(); ++iter) {
370                 delete *iter;
371         }
372         for (std::vector<IShaderConstantSetterFactory *>::iterator iter = m_setter_factories.begin();
373                         iter != m_setter_factories.end(); ++iter) {
374                 delete *iter;
375         }
376 }
377
378 u32 ShaderSource::getShader(const std::string &name,
379                 const u8 material_type, const u8 drawtype)
380 {
381         /*
382                 Get shader
383         */
384
385         if (std::this_thread::get_id() == m_main_thread) {
386                 return getShaderIdDirect(name, material_type, drawtype);
387         } else {
388                 /*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/
389
390                 // We're gonna ask the result to be put into here
391
392                 static ResultQueue<std::string, u32, u8, u8> result_queue;
393
394                 // Throw a request in
395                 m_get_shader_queue.add(name, 0, 0, &result_queue);
396
397                 /* infostream<<"Waiting for shader from main thread, name=\""
398                                 <<name<<"\""<<std::endl;*/
399
400                 while(true) {
401                         GetResult<std::string, u32, u8, u8>
402                                 result = result_queue.pop_frontNoEx();
403
404                         if (result.key == name) {
405                                 return result.item;
406                         }
407                         else {
408                                 errorstream << "Got shader with invalid name: " << result.key << std::endl;
409                         }
410                 }
411
412         }
413
414         infostream<<"getShader(): Failed"<<std::endl;
415
416         return 0;
417 }
418
419 /*
420         This method generates all the shaders
421 */
422 u32 ShaderSource::getShaderIdDirect(const std::string &name,
423                 const u8 material_type, const u8 drawtype)
424 {
425         //infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
426
427         // Empty name means shader 0
428         if(name == ""){
429                 infostream<<"getShaderIdDirect(): name is empty"<<std::endl;
430                 return 0;
431         }
432
433         // Check if already have such instance
434         for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
435                 ShaderInfo *info = &m_shaderinfo_cache[i];
436                 if(info->name == name && info->material_type == material_type &&
437                         info->drawtype == drawtype)
438                         return i;
439         }
440
441         /*
442                 Calling only allowed from main thread
443         */
444         if (std::this_thread::get_id() != m_main_thread) {
445                 errorstream<<"ShaderSource::getShaderIdDirect() "
446                                 "called not from main thread"<<std::endl;
447                 return 0;
448         }
449
450         ShaderInfo info = generate_shader(name, material_type, drawtype,
451                         m_callbacks, m_setter_factories, &m_sourcecache);
452
453         /*
454                 Add shader to caches (add dummy shaders too)
455         */
456
457         MutexAutoLock lock(m_shaderinfo_cache_mutex);
458
459         u32 id = m_shaderinfo_cache.size();
460         m_shaderinfo_cache.push_back(info);
461
462         infostream<<"getShaderIdDirect(): "
463                         <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;
464
465         return id;
466 }
467
468
469 ShaderInfo ShaderSource::getShaderInfo(u32 id)
470 {
471         MutexAutoLock lock(m_shaderinfo_cache_mutex);
472
473         if(id >= m_shaderinfo_cache.size())
474                 return ShaderInfo();
475
476         return m_shaderinfo_cache[id];
477 }
478
479 void ShaderSource::processQueue()
480 {
481
482
483 }
484
485 void ShaderSource::insertSourceShader(const std::string &name_of_shader,
486                 const std::string &filename, const std::string &program)
487 {
488         /*infostream<<"ShaderSource::insertSourceShader(): "
489                         "name_of_shader=\""<<name_of_shader<<"\", "
490                         "filename=\""<<filename<<"\""<<std::endl;*/
491
492         sanity_check(std::this_thread::get_id() == m_main_thread);
493
494         m_sourcecache.insert(name_of_shader, filename, program, true);
495 }
496
497 void ShaderSource::rebuildShaders()
498 {
499         MutexAutoLock lock(m_shaderinfo_cache_mutex);
500
501         /*// Oh well... just clear everything, they'll load sometime.
502         m_shaderinfo_cache.clear();
503         m_name_to_id.clear();*/
504
505         /*
506                 FIXME: Old shader materials can't be deleted in Irrlicht,
507                 or can they?
508                 (This would be nice to do in the destructor too)
509         */
510
511         // Recreate shaders
512         for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
513                 ShaderInfo *info = &m_shaderinfo_cache[i];
514                 if(info->name != ""){
515                         *info = generate_shader(info->name, info->material_type,
516                                         info->drawtype, m_callbacks,
517                                         m_setter_factories, &m_sourcecache);
518                 }
519         }
520 }
521
522
523 ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtype,
524                 std::vector<ShaderCallback *> &callbacks,
525                 const std::vector<IShaderConstantSetterFactory *> &setter_factories,
526                 SourceShaderCache *sourcecache)
527 {
528         ShaderInfo shaderinfo;
529         shaderinfo.name = name;
530         shaderinfo.material_type = material_type;
531         shaderinfo.drawtype = drawtype;
532         shaderinfo.material = video::EMT_SOLID;
533         switch (material_type) {
534                 case TILE_MATERIAL_BASIC:
535                         shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
536                         break;
537                 case TILE_MATERIAL_ALPHA:
538                         shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
539                         break;
540                 case TILE_MATERIAL_LIQUID_TRANSPARENT:
541                         shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
542                         break;
543                 case TILE_MATERIAL_LIQUID_OPAQUE:
544                         shaderinfo.base_material = video::EMT_SOLID;
545                         break;
546                 case TILE_MATERIAL_WAVING_LEAVES:
547                         shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
548                         break;
549                 case TILE_MATERIAL_WAVING_PLANTS:
550                         shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
551                         break;
552                 default:
553                         break;
554         }
555
556         bool enable_shaders = g_settings->getBool("enable_shaders");
557         if (!enable_shaders)
558                 return shaderinfo;
559
560         video::IVideoDriver *driver = RenderingEngine::get_video_driver();
561
562         video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
563         if(!gpu){
564                 errorstream<<"generate_shader(): "
565                                 "failed to generate \""<<name<<"\", "
566                                 "GPU programming not supported."
567                                 <<std::endl;
568                 return shaderinfo;
569         }
570
571         // Choose shader language depending on driver type and settings
572         // Then load shaders
573         std::string vertex_program;
574         std::string pixel_program;
575         std::string geometry_program;
576         bool is_highlevel;
577         load_shaders(name, sourcecache, driver->getDriverType(),
578                         enable_shaders, vertex_program, pixel_program,
579                         geometry_program, is_highlevel);
580         // Check hardware/driver support
581         if(vertex_program != "" &&
582                         !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
583                         !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
584                 infostream<<"generate_shader(): vertex shaders disabled "
585                                 "because of missing driver/hardware support."
586                                 <<std::endl;
587                 vertex_program = "";
588         }
589         if(pixel_program != "" &&
590                         !driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
591                         !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
592                 infostream<<"generate_shader(): pixel shaders disabled "
593                                 "because of missing driver/hardware support."
594                                 <<std::endl;
595                 pixel_program = "";
596         }
597         if(geometry_program != "" &&
598                         !driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
599                 infostream<<"generate_shader(): geometry shaders disabled "
600                                 "because of missing driver/hardware support."
601                                 <<std::endl;
602                 geometry_program = "";
603         }
604
605         // If no shaders are used, don't make a separate material type
606         if(vertex_program == "" && pixel_program == "" && geometry_program == "")
607                 return shaderinfo;
608
609         // Create shaders header
610         std::string shaders_header = "#version 120\n";
611
612         static const char* drawTypes[] = {
613                 "NDT_NORMAL",
614                 "NDT_AIRLIKE",
615                 "NDT_LIQUID",
616                 "NDT_FLOWINGLIQUID",
617                 "NDT_GLASSLIKE",
618                 "NDT_ALLFACES",
619                 "NDT_ALLFACES_OPTIONAL",
620                 "NDT_TORCHLIKE",
621                 "NDT_SIGNLIKE",
622                 "NDT_PLANTLIKE",
623                 "NDT_FENCELIKE",
624                 "NDT_RAILLIKE",
625                 "NDT_NODEBOX",
626                 "NDT_GLASSLIKE_FRAMED",
627                 "NDT_FIRELIKE",
628                 "NDT_GLASSLIKE_FRAMED_OPTIONAL"
629         };
630
631         for (int i = 0; i < 14; i++){
632                 shaders_header += "#define ";
633                 shaders_header += drawTypes[i];
634                 shaders_header += " ";
635                 shaders_header += itos(i);
636                 shaders_header += "\n";
637         }
638
639         static const char* materialTypes[] = {
640                 "TILE_MATERIAL_BASIC",
641                 "TILE_MATERIAL_ALPHA",
642                 "TILE_MATERIAL_LIQUID_TRANSPARENT",
643                 "TILE_MATERIAL_LIQUID_OPAQUE",
644                 "TILE_MATERIAL_WAVING_LEAVES",
645                 "TILE_MATERIAL_WAVING_PLANTS"
646         };
647
648         for (int i = 0; i < 6; i++){
649                 shaders_header += "#define ";
650                 shaders_header += materialTypes[i];
651                 shaders_header += " ";
652                 shaders_header += itos(i);
653                 shaders_header += "\n";
654         }
655
656         shaders_header += "#define MATERIAL_TYPE ";
657         shaders_header += itos(material_type);
658         shaders_header += "\n";
659         shaders_header += "#define DRAW_TYPE ";
660         shaders_header += itos(drawtype);
661         shaders_header += "\n";
662
663         if (g_settings->getBool("generate_normalmaps")) {
664                 shaders_header += "#define GENERATE_NORMALMAPS 1\n";
665         } else {
666                 shaders_header += "#define GENERATE_NORMALMAPS 0\n";
667         }
668         shaders_header += "#define NORMALMAPS_STRENGTH ";
669         shaders_header += ftos(g_settings->getFloat("normalmaps_strength"));
670         shaders_header += "\n";
671         float sample_step;
672         int smooth = (int)g_settings->getFloat("normalmaps_smooth");
673         switch (smooth){
674         case 0:
675                 sample_step = 0.0078125; // 1.0 / 128.0
676                 break;
677         case 1:
678                 sample_step = 0.00390625; // 1.0 / 256.0
679                 break;
680         case 2:
681                 sample_step = 0.001953125; // 1.0 / 512.0
682                 break;
683         default:
684                 sample_step = 0.0078125;
685                 break;
686         }
687         shaders_header += "#define SAMPLE_STEP ";
688         shaders_header += ftos(sample_step);
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(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 != "" || pixel_program != "" || geometry_program != ""){
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 }