]> git.lizzy.rs Git - dragonfireclient.git/blob - src/client/shader.cpp
Attachments: Fix attachments to temporary removed objects (#8989)
[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         case TILE_MATERIAL_WAVING_LIQUID_OPAQUE:
531                 shaderinfo.base_material = video::EMT_SOLID;
532                 break;
533         case TILE_MATERIAL_ALPHA:
534         case TILE_MATERIAL_LIQUID_TRANSPARENT:
535         case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
536                 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
537                 break;
538         case TILE_MATERIAL_BASIC:
539         case TILE_MATERIAL_WAVING_LEAVES:
540         case TILE_MATERIAL_WAVING_PLANTS:
541         case TILE_MATERIAL_WAVING_LIQUID_BASIC:
542                 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
543                 break;
544         }
545
546         bool enable_shaders = g_settings->getBool("enable_shaders");
547         if (!enable_shaders)
548                 return shaderinfo;
549
550         video::IVideoDriver *driver = RenderingEngine::get_video_driver();
551
552         video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
553         if(!gpu){
554                 errorstream<<"generate_shader(): "
555                                 "failed to generate \""<<name<<"\", "
556                                 "GPU programming not supported."
557                                 <<std::endl;
558                 return shaderinfo;
559         }
560
561         // Choose shader language depending on driver type and settings
562         // Then load shaders
563         std::string vertex_program;
564         std::string pixel_program;
565         std::string geometry_program;
566         bool is_highlevel;
567         load_shaders(name, sourcecache, driver->getDriverType(),
568                         enable_shaders, vertex_program, pixel_program,
569                         geometry_program, is_highlevel);
570         // Check hardware/driver support
571         if (!vertex_program.empty() &&
572                         !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
573                         !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
574                 infostream<<"generate_shader(): vertex shaders disabled "
575                                 "because of missing driver/hardware support."
576                                 <<std::endl;
577                 vertex_program = "";
578         }
579         if (!pixel_program.empty() &&
580                         !driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
581                         !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
582                 infostream<<"generate_shader(): pixel shaders disabled "
583                                 "because of missing driver/hardware support."
584                                 <<std::endl;
585                 pixel_program = "";
586         }
587         if (!geometry_program.empty() &&
588                         !driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
589                 infostream<<"generate_shader(): geometry shaders disabled "
590                                 "because of missing driver/hardware support."
591                                 <<std::endl;
592                 geometry_program = "";
593         }
594
595         // If no shaders are used, don't make a separate material type
596         if (vertex_program.empty() && pixel_program.empty() && geometry_program.empty())
597                 return shaderinfo;
598
599         // Create shaders header
600         std::string shaders_header = "#version 120\n";
601
602         static const char* drawTypes[] = {
603                 "NDT_NORMAL",
604                 "NDT_AIRLIKE",
605                 "NDT_LIQUID",
606                 "NDT_FLOWINGLIQUID",
607                 "NDT_GLASSLIKE",
608                 "NDT_ALLFACES",
609                 "NDT_ALLFACES_OPTIONAL",
610                 "NDT_TORCHLIKE",
611                 "NDT_SIGNLIKE",
612                 "NDT_PLANTLIKE",
613                 "NDT_FENCELIKE",
614                 "NDT_RAILLIKE",
615                 "NDT_NODEBOX",
616                 "NDT_GLASSLIKE_FRAMED",
617                 "NDT_FIRELIKE",
618                 "NDT_GLASSLIKE_FRAMED_OPTIONAL",
619                 "NDT_PLANTLIKE_ROOTED",
620         };
621
622         for (int i = 0; i < 14; i++){
623                 shaders_header += "#define ";
624                 shaders_header += drawTypes[i];
625                 shaders_header += " ";
626                 shaders_header += itos(i);
627                 shaders_header += "\n";
628         }
629
630         static const char* materialTypes[] = {
631                 "TILE_MATERIAL_BASIC",
632                 "TILE_MATERIAL_ALPHA",
633                 "TILE_MATERIAL_LIQUID_TRANSPARENT",
634                 "TILE_MATERIAL_LIQUID_OPAQUE",
635                 "TILE_MATERIAL_WAVING_LEAVES",
636                 "TILE_MATERIAL_WAVING_PLANTS",
637                 "TILE_MATERIAL_OPAQUE",
638                 "TILE_MATERIAL_WAVING_LIQUID_BASIC",
639                 "TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT",
640                 "TILE_MATERIAL_WAVING_LIQUID_OPAQUE",
641         };
642
643         for (int i = 0; i < 10; i++){
644                 shaders_header += "#define ";
645                 shaders_header += materialTypes[i];
646                 shaders_header += " ";
647                 shaders_header += itos(i);
648                 shaders_header += "\n";
649         }
650
651         shaders_header += "#define MATERIAL_TYPE ";
652         shaders_header += itos(material_type);
653         shaders_header += "\n";
654         shaders_header += "#define DRAW_TYPE ";
655         shaders_header += itos(drawtype);
656         shaders_header += "\n";
657
658         if (g_settings->getBool("generate_normalmaps")) {
659                 shaders_header += "#define GENERATE_NORMALMAPS 1\n";
660         } else {
661                 shaders_header += "#define GENERATE_NORMALMAPS 0\n";
662         }
663         shaders_header += "#define NORMALMAPS_STRENGTH ";
664         shaders_header += ftos(g_settings->getFloat("normalmaps_strength"));
665         shaders_header += "\n";
666         float sample_step;
667         int smooth = (int)g_settings->getFloat("normalmaps_smooth");
668         switch (smooth){
669         case 0:
670                 sample_step = 0.0078125; // 1.0 / 128.0
671                 break;
672         case 1:
673                 sample_step = 0.00390625; // 1.0 / 256.0
674                 break;
675         case 2:
676                 sample_step = 0.001953125; // 1.0 / 512.0
677                 break;
678         default:
679                 sample_step = 0.0078125;
680                 break;
681         }
682         shaders_header += "#define SAMPLE_STEP ";
683         shaders_header += ftos(sample_step);
684         shaders_header += "\n";
685
686         if (g_settings->getBool("enable_bumpmapping"))
687                 shaders_header += "#define ENABLE_BUMPMAPPING\n";
688
689         if (g_settings->getBool("enable_parallax_occlusion")){
690                 int mode = g_settings->getFloat("parallax_occlusion_mode");
691                 float scale = g_settings->getFloat("parallax_occlusion_scale");
692                 float bias = g_settings->getFloat("parallax_occlusion_bias");
693                 int iterations = g_settings->getFloat("parallax_occlusion_iterations");
694                 shaders_header += "#define ENABLE_PARALLAX_OCCLUSION\n";
695                 shaders_header += "#define PARALLAX_OCCLUSION_MODE ";
696                 shaders_header += itos(mode);
697                 shaders_header += "\n";
698                 shaders_header += "#define PARALLAX_OCCLUSION_SCALE ";
699                 shaders_header += ftos(scale);
700                 shaders_header += "\n";
701                 shaders_header += "#define PARALLAX_OCCLUSION_BIAS ";
702                 shaders_header += ftos(bias);
703                 shaders_header += "\n";
704                 shaders_header += "#define PARALLAX_OCCLUSION_ITERATIONS ";
705                 shaders_header += itos(iterations);
706                 shaders_header += "\n";
707         }
708
709         shaders_header += "#define USE_NORMALMAPS ";
710         if (g_settings->getBool("enable_bumpmapping") || g_settings->getBool("enable_parallax_occlusion"))
711                 shaders_header += "1\n";
712         else
713                 shaders_header += "0\n";
714
715         if (g_settings->getBool("enable_waving_water")){
716                 shaders_header += "#define ENABLE_WAVING_WATER 1\n";
717                 shaders_header += "#define WATER_WAVE_HEIGHT ";
718                 shaders_header += ftos(g_settings->getFloat("water_wave_height"));
719                 shaders_header += "\n";
720                 shaders_header += "#define WATER_WAVE_LENGTH ";
721                 shaders_header += ftos(g_settings->getFloat("water_wave_length"));
722                 shaders_header += "\n";
723                 shaders_header += "#define WATER_WAVE_SPEED ";
724                 shaders_header += ftos(g_settings->getFloat("water_wave_speed"));
725                 shaders_header += "\n";
726         } else{
727                 shaders_header += "#define ENABLE_WAVING_WATER 0\n";
728         }
729
730         shaders_header += "#define ENABLE_WAVING_LEAVES ";
731         if (g_settings->getBool("enable_waving_leaves"))
732                 shaders_header += "1\n";
733         else
734                 shaders_header += "0\n";
735
736         shaders_header += "#define ENABLE_WAVING_PLANTS ";
737         if (g_settings->getBool("enable_waving_plants"))
738                 shaders_header += "1\n";
739         else
740                 shaders_header += "0\n";
741
742         if (g_settings->getBool("tone_mapping"))
743                 shaders_header += "#define ENABLE_TONE_MAPPING\n";
744
745         shaders_header += "#define FOG_START ";
746         shaders_header += ftos(rangelim(g_settings->getFloat("fog_start"), 0.0f, 0.99f));
747         shaders_header += "\n";
748
749         // Call addHighLevelShaderMaterial() or addShaderMaterial()
750         const c8* vertex_program_ptr = 0;
751         const c8* pixel_program_ptr = 0;
752         const c8* geometry_program_ptr = 0;
753         if (!vertex_program.empty()) {
754                 vertex_program = shaders_header + vertex_program;
755                 vertex_program_ptr = vertex_program.c_str();
756         }
757         if (!pixel_program.empty()) {
758                 pixel_program = shaders_header + pixel_program;
759                 pixel_program_ptr = pixel_program.c_str();
760         }
761         if (!geometry_program.empty()) {
762                 geometry_program = shaders_header + geometry_program;
763                 geometry_program_ptr = geometry_program.c_str();
764         }
765         ShaderCallback *cb = new ShaderCallback(setter_factories);
766         s32 shadermat = -1;
767         if(is_highlevel){
768                 infostream<<"Compiling high level shaders for "<<name<<std::endl;
769                 shadermat = gpu->addHighLevelShaderMaterial(
770                         vertex_program_ptr,   // Vertex shader program
771                         "vertexMain",         // Vertex shader entry point
772                         video::EVST_VS_1_1,   // Vertex shader version
773                         pixel_program_ptr,    // Pixel shader program
774                         "pixelMain",          // Pixel shader entry point
775                         video::EPST_PS_1_2,   // Pixel shader version
776                         geometry_program_ptr, // Geometry shader program
777                         "geometryMain",       // Geometry shader entry point
778                         video::EGST_GS_4_0,   // Geometry shader version
779                         scene::EPT_TRIANGLES,      // Geometry shader input
780                         scene::EPT_TRIANGLE_STRIP, // Geometry shader output
781                         0,                         // Support maximum number of vertices
782                         cb, // Set-constant callback
783                         shaderinfo.base_material,  // Base material
784                         1                          // Userdata passed to callback
785                         );
786                 if(shadermat == -1){
787                         errorstream<<"generate_shader(): "
788                                         "failed to generate \""<<name<<"\", "
789                                         "addHighLevelShaderMaterial failed."
790                                         <<std::endl;
791                         dumpShaderProgram(warningstream, "Vertex", vertex_program);
792                         dumpShaderProgram(warningstream, "Pixel", pixel_program);
793                         dumpShaderProgram(warningstream, "Geometry", geometry_program);
794                         delete cb;
795                         return shaderinfo;
796                 }
797         }
798         else{
799                 infostream<<"Compiling assembly shaders for "<<name<<std::endl;
800                 shadermat = gpu->addShaderMaterial(
801                         vertex_program_ptr,   // Vertex shader program
802                         pixel_program_ptr,    // Pixel shader program
803                         cb, // Set-constant callback
804                         shaderinfo.base_material,  // Base material
805                         0                     // Userdata passed to callback
806                         );
807
808                 if(shadermat == -1){
809                         errorstream<<"generate_shader(): "
810                                         "failed to generate \""<<name<<"\", "
811                                         "addShaderMaterial failed."
812                                         <<std::endl;
813                         dumpShaderProgram(warningstream, "Vertex", vertex_program);
814                         dumpShaderProgram(warningstream,"Pixel", pixel_program);
815                         delete cb;
816                         return shaderinfo;
817                 }
818         }
819         callbacks.push_back(cb);
820
821         // HACK, TODO: investigate this better
822         // Grab the material renderer once more so minetest doesn't crash on exit
823         driver->getMaterialRenderer(shadermat)->grab();
824
825         // Apply the newly created material type
826         shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
827         return shaderinfo;
828 }
829
830 void load_shaders(const std::string &name, SourceShaderCache *sourcecache,
831                 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
832                 std::string &vertex_program, std::string &pixel_program,
833                 std::string &geometry_program, bool &is_highlevel)
834 {
835         vertex_program = "";
836         pixel_program = "";
837         geometry_program = "";
838         is_highlevel = false;
839
840         if(enable_shaders){
841                 // Look for high level shaders
842                 if(drivertype == video::EDT_DIRECT3D9){
843                         // Direct3D 9: HLSL
844                         // (All shaders in one file)
845                         vertex_program = sourcecache->getOrLoad(name, "d3d9.hlsl");
846                         pixel_program = vertex_program;
847                         geometry_program = vertex_program;
848                 }
849                 else if(drivertype == video::EDT_OPENGL){
850                         // OpenGL: GLSL
851                         vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.glsl");
852                         pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.glsl");
853                         geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl");
854                 }
855                 if (!vertex_program.empty() || !pixel_program.empty() || !geometry_program.empty()){
856                         is_highlevel = true;
857                         return;
858                 }
859         }
860
861 }
862
863 void dumpShaderProgram(std::ostream &output_stream,
864                 const std::string &program_type, const std::string &program)
865 {
866         output_stream << program_type << " shader program:" << std::endl <<
867                 "----------------------------------" << std::endl;
868         size_t pos = 0;
869         size_t prev = 0;
870         s16 line = 1;
871         while ((pos = program.find('\n', prev)) != std::string::npos) {
872                 output_stream << line++ << ": "<< program.substr(prev, pos - prev) <<
873                         std::endl;
874                 prev = pos + 1;
875         }
876         output_stream << line << ": " << program.substr(prev) << std::endl <<
877                 "End of " << program_type << " shader program." << std::endl <<
878                 " " << std::endl;
879 }