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