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