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