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