]> git.lizzy.rs Git - dragonfireclient.git/blob - src/shader.cpp
Various server.cpp cleanups
[dragonfireclient.git] / src / shader.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 Copyright (C) 2013 Kahrl <kahrl@gmx.net>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include <fstream>
22 #include <iterator>
23 #include "shader.h"
24 #include "irrlichttypes_extrabloated.h"
25 #include "debug.h"
26 #include "filesys.h"
27 #include "util/container.h"
28 #include "util/thread.h"
29 #include "settings.h"
30 #include <ICameraSceneNode.h>
31 #include <IGPUProgrammingServices.h>
32 #include <IMaterialRenderer.h>
33 #include <IMaterialRendererServices.h>
34 #include <IShaderConstantSetCallBack.h>
35 #include "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 != "")
72         {
73                 std::string testpath = shader_path + DIR_DELIM + combined;
74                 if(fs::PathExists(testpath))
75                         fullpath = testpath;
76         }
77
78         /*
79                 Check from default data directory
80         */
81         if(fullpath == "")
82         {
83                 std::string rel_path = std::string("client") + DIR_DELIM
84                                 + "shaders" + DIR_DELIM
85                                 + name_of_shader + DIR_DELIM
86                                 + filename;
87                 std::string testpath = porting::path_share + DIR_DELIM + rel_path;
88                 if(fs::PathExists(testpath))
89                         fullpath = testpath;
90         }
91
92         // Add to cache (also an empty result is cached)
93         g_shadername_to_path_cache.set(combined, fullpath);
94
95         // Finally return it
96         return fullpath;
97 }
98
99 /*
100         SourceShaderCache: A cache used for storing source shaders.
101 */
102
103 class SourceShaderCache
104 {
105 public:
106         void insert(const std::string &name_of_shader, const std::string &filename,
107                 const std::string &program, bool prefer_local)
108         {
109                 std::string combined = name_of_shader + DIR_DELIM + filename;
110                 // Try to use local shader instead if asked to
111                 if(prefer_local){
112                         std::string path = getShaderPath(name_of_shader, filename);
113                         if(path != ""){
114                                 std::string p = readFile(path);
115                                 if(p != ""){
116                                         m_programs[combined] = p;
117                                         return;
118                                 }
119                         }
120                 }
121                 m_programs[combined] = program;
122         }
123
124         std::string get(const std::string &name_of_shader,
125                 const std::string &filename)
126         {
127                 std::string combined = name_of_shader + DIR_DELIM + filename;
128                 StringMap::iterator n = m_programs.find(combined);
129                 if (n != m_programs.end())
130                         return n->second;
131                 return "";
132         }
133
134         // Primarily fetches from cache, secondarily tries to read from filesystem
135         std::string getOrLoad(const std::string &name_of_shader,
136                 const std::string &filename)
137         {
138                 std::string combined = name_of_shader + DIR_DELIM + filename;
139                 StringMap::iterator n = m_programs.find(combined);
140                 if (n != m_programs.end())
141                         return n->second;
142                 std::string path = getShaderPath(name_of_shader, filename);
143                 if (path == "") {
144                         infostream << "SourceShaderCache::getOrLoad(): No path found for \""
145                                 << combined << "\"" << std::endl;
146                         return "";
147                 }
148                 infostream << "SourceShaderCache::getOrLoad(): Loading path \""
149                         << path << "\"" << std::endl;
150                 std::string p = readFile(path);
151                 if (p != "") {
152                         m_programs[combined] = p;
153                         return p;
154                 }
155                 return "";
156         }
157 private:
158         StringMap m_programs;
159
160         std::string readFile(const std::string &path)
161         {
162                 std::ifstream is(path.c_str(), std::ios::binary);
163                 if(!is.is_open())
164                         return "";
165                 std::ostringstream tmp_os;
166                 tmp_os << is.rdbuf();
167                 return tmp_os.str();
168         }
169 };
170
171
172 /*
173         ShaderCallback: Sets constants that can be used in shaders
174 */
175
176 class ShaderCallback : public video::IShaderConstantSetCallBack
177 {
178         std::vector<IShaderConstantSetter*> m_setters;
179
180 public:
181         ShaderCallback(const std::vector<IShaderConstantSetterFactory *> &factories)
182         {
183                 for (u32 i = 0; i < factories.size(); ++i)
184                         m_setters.push_back(factories[i]->create());
185         }
186
187         ~ShaderCallback()
188         {
189                 for (u32 i = 0; i < m_setters.size(); ++i)
190                         delete m_setters[i];
191         }
192
193         virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData)
194         {
195                 video::IVideoDriver *driver = services->getVideoDriver();
196                 sanity_check(driver != NULL);
197
198                 bool is_highlevel = userData;
199
200                 for (u32 i = 0; i < m_setters.size(); ++i)
201                         m_setters[i]->onSetConstants(services, is_highlevel);
202         }
203 };
204
205
206 /*
207         MainShaderConstantSetter: Set basic constants required for almost everything
208 */
209
210 class MainShaderConstantSetter : public IShaderConstantSetter
211 {
212         CachedVertexShaderSetting<float, 16> m_world_view_proj;
213         CachedVertexShaderSetting<float, 16> m_world;
214
215 public:
216         MainShaderConstantSetter() :
217                 m_world_view_proj("mWorldViewProj"),
218                 m_world("mWorld")
219         {}
220         ~MainShaderConstantSetter() {}
221
222         virtual void onSetConstants(video::IMaterialRendererServices *services,
223                         bool is_highlevel)
224         {
225                 video::IVideoDriver *driver = services->getVideoDriver();
226                 sanity_check(driver);
227
228                 // Set clip matrix
229                 core::matrix4 worldViewProj;
230                 worldViewProj = driver->getTransform(video::ETS_PROJECTION);
231                 worldViewProj *= driver->getTransform(video::ETS_VIEW);
232                 worldViewProj *= driver->getTransform(video::ETS_WORLD);
233                 if (is_highlevel)
234                         m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
235                 else
236                         services->setVertexShaderConstant(worldViewProj.pointer(), 0, 4);
237
238                 // Set world matrix
239                 core::matrix4 world = driver->getTransform(video::ETS_WORLD);
240                 if (is_highlevel)
241                         m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
242                 else
243                         services->setVertexShaderConstant(world.pointer(), 4, 4);
244
245         }
246 };
247
248
249 class MainShaderConstantSetterFactory : public IShaderConstantSetterFactory
250 {
251 public:
252         virtual IShaderConstantSetter* create()
253                 { return new MainShaderConstantSetter(); }
254 };
255
256
257 /*
258         ShaderSource
259 */
260
261 class ShaderSource : public IWritableShaderSource
262 {
263 public:
264         ShaderSource();
265         ~ShaderSource();
266
267         /*
268                 - If shader material specified by name is found from cache,
269                   return the cached id.
270                 - Otherwise generate the shader material, add to cache and return id.
271
272                 The id 0 points to a null shader. Its material is EMT_SOLID.
273         */
274         u32 getShaderIdDirect(const std::string &name,
275                 const u8 material_type, const u8 drawtype);
276
277         /*
278                 If shader specified by the name pointed by the id doesn't
279                 exist, create it, then return id.
280
281                 Can be called from any thread. If called from some other thread
282                 and not found in cache, the call is queued to the main thread
283                 for processing.
284         */
285
286         u32 getShader(const std::string &name,
287                 const u8 material_type, const u8 drawtype);
288
289         ShaderInfo getShaderInfo(u32 id);
290
291         // Processes queued shader requests from other threads.
292         // Shall be called from the main thread.
293         void processQueue();
294
295         // Insert a shader program into the cache without touching the
296         // filesystem. Shall be called from the main thread.
297         void insertSourceShader(const std::string &name_of_shader,
298                 const std::string &filename, const std::string &program);
299
300         // Rebuild shaders from the current set of source shaders
301         // Shall be called from the main thread.
302         void rebuildShaders();
303
304         void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter)
305         {
306                 m_setter_factories.push_back(setter);
307         }
308
309 private:
310
311         // The id of the thread that is allowed to use irrlicht directly
312         std::thread::id m_main_thread;
313
314         // Cache of source shaders
315         // This should be only accessed from the main thread
316         SourceShaderCache m_sourcecache;
317
318         // A shader id is index in this array.
319         // The first position contains a dummy shader.
320         std::vector<ShaderInfo> m_shaderinfo_cache;
321         // The former container is behind this mutex
322         std::mutex m_shaderinfo_cache_mutex;
323
324         // Queued shader fetches (to be processed by the main thread)
325         RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
326
327         // Global constant setter factories
328         std::vector<IShaderConstantSetterFactory *> m_setter_factories;
329
330         // Shader callbacks
331         std::vector<ShaderCallback *> m_callbacks;
332 };
333
334 IWritableShaderSource *createShaderSource()
335 {
336         return new ShaderSource();
337 }
338
339 /*
340         Generate shader given the shader name.
341 */
342 ShaderInfo generate_shader(const std::string &name,
343                 u8 material_type, u8 drawtype, std::vector<ShaderCallback *> &callbacks,
344                 const std::vector<IShaderConstantSetterFactory *> &setter_factories,
345                 SourceShaderCache *sourcecache);
346
347 /*
348         Load shader programs
349 */
350 void load_shaders(std::string name, SourceShaderCache *sourcecache,
351                 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
352                 std::string &vertex_program, std::string &pixel_program,
353                 std::string &geometry_program, bool &is_highlevel);
354
355 ShaderSource::ShaderSource()
356 {
357         m_main_thread = std::this_thread::get_id();
358
359         // Add a dummy ShaderInfo as the first index, named ""
360         m_shaderinfo_cache.push_back(ShaderInfo());
361
362         // Add main global constant setter
363         addShaderConstantSetterFactory(new MainShaderConstantSetterFactory());
364 }
365
366 ShaderSource::~ShaderSource()
367 {
368         for (std::vector<ShaderCallback *>::iterator iter = m_callbacks.begin();
369                         iter != m_callbacks.end(); ++iter) {
370                 delete *iter;
371         }
372         for (std::vector<IShaderConstantSetterFactory *>::iterator iter = m_setter_factories.begin();
373                         iter != m_setter_factories.end(); ++iter) {
374                 delete *iter;
375         }
376 }
377
378 u32 ShaderSource::getShader(const std::string &name,
379                 const u8 material_type, const u8 drawtype)
380 {
381         /*
382                 Get shader
383         */
384
385         if (std::this_thread::get_id() == m_main_thread) {
386                 return getShaderIdDirect(name, material_type, drawtype);
387         } else {
388                 /*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/
389
390                 // We're gonna ask the result to be put into here
391
392                 static ResultQueue<std::string, u32, u8, u8> result_queue;
393
394                 // Throw a request in
395                 m_get_shader_queue.add(name, 0, 0, &result_queue);
396
397                 /* infostream<<"Waiting for shader from main thread, name=\""
398                                 <<name<<"\""<<std::endl;*/
399
400                 while(true) {
401                         GetResult<std::string, u32, u8, u8>
402                                 result = result_queue.pop_frontNoEx();
403
404                         if (result.key == name) {
405                                 return result.item;
406                         }
407                         else {
408                                 errorstream << "Got shader with invalid name: " << result.key << std::endl;
409                         }
410                 }
411
412         }
413
414         infostream<<"getShader(): Failed"<<std::endl;
415
416         return 0;
417 }
418
419 /*
420         This method generates all the shaders
421 */
422 u32 ShaderSource::getShaderIdDirect(const std::string &name,
423                 const u8 material_type, const u8 drawtype)
424 {
425         //infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
426
427         // Empty name means shader 0
428         if(name == ""){
429                 infostream<<"getShaderIdDirect(): name is empty"<<std::endl;
430                 return 0;
431         }
432
433         // Check if already have such instance
434         for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
435                 ShaderInfo *info = &m_shaderinfo_cache[i];
436                 if(info->name == name && info->material_type == material_type &&
437                         info->drawtype == drawtype)
438                         return i;
439         }
440
441         /*
442                 Calling only allowed from main thread
443         */
444         if (std::this_thread::get_id() != m_main_thread) {
445                 errorstream<<"ShaderSource::getShaderIdDirect() "
446                                 "called not from main thread"<<std::endl;
447                 return 0;
448         }
449
450         ShaderInfo info = generate_shader(name, material_type, drawtype,
451                         m_callbacks, m_setter_factories, &m_sourcecache);
452
453         /*
454                 Add shader to caches (add dummy shaders too)
455         */
456
457         MutexAutoLock lock(m_shaderinfo_cache_mutex);
458
459         u32 id = m_shaderinfo_cache.size();
460         m_shaderinfo_cache.push_back(info);
461
462         infostream<<"getShaderIdDirect(): "
463                         <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;
464
465         return id;
466 }
467
468
469 ShaderInfo ShaderSource::getShaderInfo(u32 id)
470 {
471         MutexAutoLock lock(m_shaderinfo_cache_mutex);
472
473         if(id >= m_shaderinfo_cache.size())
474                 return ShaderInfo();
475
476         return m_shaderinfo_cache[id];
477 }
478
479 void ShaderSource::processQueue()
480 {
481
482
483 }
484
485 void ShaderSource::insertSourceShader(const std::string &name_of_shader,
486                 const std::string &filename, const std::string &program)
487 {
488         /*infostream<<"ShaderSource::insertSourceShader(): "
489                         "name_of_shader=\""<<name_of_shader<<"\", "
490                         "filename=\""<<filename<<"\""<<std::endl;*/
491
492         sanity_check(std::this_thread::get_id() == m_main_thread);
493
494         m_sourcecache.insert(name_of_shader, filename, program, true);
495 }
496
497 void ShaderSource::rebuildShaders()
498 {
499         MutexAutoLock lock(m_shaderinfo_cache_mutex);
500
501         /*// Oh well... just clear everything, they'll load sometime.
502         m_shaderinfo_cache.clear();
503         m_name_to_id.clear();*/
504
505         /*
506                 FIXME: Old shader materials can't be deleted in Irrlicht,
507                 or can they?
508                 (This would be nice to do in the destructor too)
509         */
510
511         // Recreate shaders
512         for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
513                 ShaderInfo *info = &m_shaderinfo_cache[i];
514                 if(info->name != ""){
515                         *info = generate_shader(info->name, info->material_type,
516                                         info->drawtype, m_callbacks,
517                                         m_setter_factories, &m_sourcecache);
518                 }
519         }
520 }
521
522
523 ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtype,
524                 std::vector<ShaderCallback *> &callbacks,
525                 const std::vector<IShaderConstantSetterFactory *> &setter_factories,
526                 SourceShaderCache *sourcecache)
527 {
528         ShaderInfo shaderinfo;
529         shaderinfo.name = name;
530         shaderinfo.material_type = material_type;
531         shaderinfo.drawtype = drawtype;
532         shaderinfo.material = video::EMT_SOLID;
533         switch (material_type) {
534         case TILE_MATERIAL_OPAQUE:
535         case TILE_MATERIAL_LIQUID_OPAQUE:
536                 shaderinfo.base_material = video::EMT_SOLID;
537                 break;
538         case TILE_MATERIAL_ALPHA:
539         case TILE_MATERIAL_LIQUID_TRANSPARENT:
540                 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
541                 break;
542         case TILE_MATERIAL_BASIC:
543         case TILE_MATERIAL_WAVING_LEAVES:
544         case TILE_MATERIAL_WAVING_PLANTS:
545                 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
546                 break;
547         }
548
549         bool enable_shaders = g_settings->getBool("enable_shaders");
550         if (!enable_shaders)
551                 return shaderinfo;
552
553         video::IVideoDriver *driver = RenderingEngine::get_video_driver();
554
555         video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
556         if(!gpu){
557                 errorstream<<"generate_shader(): "
558                                 "failed to generate \""<<name<<"\", "
559                                 "GPU programming not supported."
560                                 <<std::endl;
561                 return shaderinfo;
562         }
563
564         // Choose shader language depending on driver type and settings
565         // Then load shaders
566         std::string vertex_program;
567         std::string pixel_program;
568         std::string geometry_program;
569         bool is_highlevel;
570         load_shaders(name, sourcecache, driver->getDriverType(),
571                         enable_shaders, vertex_program, pixel_program,
572                         geometry_program, is_highlevel);
573         // Check hardware/driver support
574         if(vertex_program != "" &&
575                         !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
576                         !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
577                 infostream<<"generate_shader(): vertex shaders disabled "
578                                 "because of missing driver/hardware support."
579                                 <<std::endl;
580                 vertex_program = "";
581         }
582         if(pixel_program != "" &&
583                         !driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
584                         !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
585                 infostream<<"generate_shader(): pixel shaders disabled "
586                                 "because of missing driver/hardware support."
587                                 <<std::endl;
588                 pixel_program = "";
589         }
590         if(geometry_program != "" &&
591                         !driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
592                 infostream<<"generate_shader(): geometry shaders disabled "
593                                 "because of missing driver/hardware support."
594                                 <<std::endl;
595                 geometry_program = "";
596         }
597
598         // If no shaders are used, don't make a separate material type
599         if(vertex_program == "" && pixel_program == "" && geometry_program == "")
600                 return shaderinfo;
601
602         // Create shaders header
603         std::string shaders_header = "#version 120\n";
604
605         static const char* drawTypes[] = {
606                 "NDT_NORMAL",
607                 "NDT_AIRLIKE",
608                 "NDT_LIQUID",
609                 "NDT_FLOWINGLIQUID",
610                 "NDT_GLASSLIKE",
611                 "NDT_ALLFACES",
612                 "NDT_ALLFACES_OPTIONAL",
613                 "NDT_TORCHLIKE",
614                 "NDT_SIGNLIKE",
615                 "NDT_PLANTLIKE",
616                 "NDT_FENCELIKE",
617                 "NDT_RAILLIKE",
618                 "NDT_NODEBOX",
619                 "NDT_GLASSLIKE_FRAMED",
620                 "NDT_FIRELIKE",
621                 "NDT_GLASSLIKE_FRAMED_OPTIONAL",
622                 "NDT_PLANTLIKE_ROOTED",
623         };
624
625         for (int i = 0; i < 14; i++){
626                 shaders_header += "#define ";
627                 shaders_header += drawTypes[i];
628                 shaders_header += " ";
629                 shaders_header += itos(i);
630                 shaders_header += "\n";
631         }
632
633         static const char* materialTypes[] = {
634                 "TILE_MATERIAL_BASIC",
635                 "TILE_MATERIAL_ALPHA",
636                 "TILE_MATERIAL_LIQUID_TRANSPARENT",
637                 "TILE_MATERIAL_LIQUID_OPAQUE",
638                 "TILE_MATERIAL_WAVING_LEAVES",
639                 "TILE_MATERIAL_WAVING_PLANTS",
640                 "TILE_MATERIAL_OPAQUE"
641         };
642
643         for (int i = 0; i < 7; 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(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 != "" || pixel_program != "" || geometry_program != ""){
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 }