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