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