]> git.lizzy.rs Git - dragonfireclient.git/blob - src/shader.cpp
Add firelike drawtype
[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                 "NDT_FIRELIKE"
649         };
650         
651         for (int i = 0; i < 14; i++){
652                 shaders_header += "#define ";
653                 shaders_header += drawTypes[i];
654                 shaders_header += " ";
655                 shaders_header += itos(i);
656                 shaders_header += "\n";
657         }
658
659         static const char* materialTypes[] = {
660                 "TILE_MATERIAL_BASIC",
661                 "TILE_MATERIAL_ALPHA",
662                 "TILE_MATERIAL_LIQUID_TRANSPARENT",
663                 "TILE_MATERIAL_LIQUID_OPAQUE",
664                 "TILE_MATERIAL_WAVING_LEAVES",
665                 "TILE_MATERIAL_WAVING_PLANTS"
666         };
667
668         for (int i = 0; i < 6; i++){
669                 shaders_header += "#define ";
670                 shaders_header += materialTypes[i];
671                 shaders_header += " ";
672                 shaders_header += itos(i);
673                 shaders_header += "\n";
674         }
675
676         shaders_header += "#define MATERIAL_TYPE ";
677         shaders_header += itos(material_type);
678         shaders_header += "\n";
679         shaders_header += "#define DRAW_TYPE ";
680         shaders_header += itos(drawtype);
681         shaders_header += "\n";
682
683         if (g_settings->getBool("generate_normalmaps")){
684                 shaders_header += "#define GENERATE_NORMALMAPS\n";
685                 shaders_header += "#define NORMALMAPS_STRENGTH ";
686                 shaders_header += ftos(g_settings->getFloat("normalmaps_strength"));
687                 shaders_header += "\n";
688                 float sample_step;
689                 int smooth = (int)g_settings->getFloat("normalmaps_smooth");
690                 switch (smooth){
691                 case 0:
692                         sample_step = 0.0078125; // 1.0 / 128.0
693                         break;
694                 case 1:
695                         sample_step = 0.00390625; // 1.0 / 256.0
696                         break;
697                 case 2:
698                         sample_step = 0.001953125; // 1.0 / 512.0
699                         break;
700                 default:
701                         sample_step = 0.0078125;
702                         break;
703                 }
704                 shaders_header += "#define SAMPLE_STEP ";
705                 shaders_header += ftos(sample_step);
706                 shaders_header += "\n";
707         }
708
709         if (g_settings->getBool("enable_bumpmapping"))
710                 shaders_header += "#define ENABLE_BUMPMAPPING\n";
711
712         if (g_settings->getBool("enable_parallax_occlusion")){
713                 shaders_header += "#define ENABLE_PARALLAX_OCCLUSION\n";
714                 shaders_header += "#define PARALLAX_OCCLUSION_SCALE ";
715                 shaders_header += ftos(g_settings->getFloat("parallax_occlusion_scale"));
716                 shaders_header += "\n";
717                 shaders_header += "#define PARALLAX_OCCLUSION_BIAS ";
718                 shaders_header += ftos(g_settings->getFloat("parallax_occlusion_bias"));
719                 shaders_header += "\n";
720         }
721
722         if (g_settings->getBool("enable_bumpmapping") || g_settings->getBool("enable_parallax_occlusion"))
723                 shaders_header += "#define USE_NORMALMAPS\n";
724
725         if (g_settings->getBool("enable_waving_water")){
726                 shaders_header += "#define ENABLE_WAVING_WATER 1\n";
727                 shaders_header += "#define WATER_WAVE_HEIGHT ";
728                 shaders_header += ftos(g_settings->getFloat("water_wave_height"));
729                 shaders_header += "\n";
730                 shaders_header += "#define WATER_WAVE_LENGTH ";
731                 shaders_header += ftos(g_settings->getFloat("water_wave_length"));
732                 shaders_header += "\n";
733                 shaders_header += "#define WATER_WAVE_SPEED ";
734                 shaders_header += ftos(g_settings->getFloat("water_wave_speed"));
735                 shaders_header += "\n";
736         } else{
737                 shaders_header += "#define ENABLE_WAVING_WATER 0\n";
738         }
739
740         shaders_header += "#define ENABLE_WAVING_LEAVES ";
741         if (g_settings->getBool("enable_waving_leaves"))
742                 shaders_header += "1\n";
743         else    
744                 shaders_header += "0\n";
745
746         shaders_header += "#define ENABLE_WAVING_PLANTS ";              
747         if (g_settings->getBool("enable_waving_plants"))
748                 shaders_header += "1\n";
749         else
750                 shaders_header += "0\n";
751
752         if(pixel_program != "")
753                 pixel_program = shaders_header + pixel_program;
754         if(vertex_program != "")
755                 vertex_program = shaders_header + vertex_program;
756         if(geometry_program != "")
757                 geometry_program = shaders_header + geometry_program;
758
759         // Call addHighLevelShaderMaterial() or addShaderMaterial()
760         const c8* vertex_program_ptr = 0;
761         const c8* pixel_program_ptr = 0;
762         const c8* geometry_program_ptr = 0;
763         if(vertex_program != "")
764                 vertex_program_ptr = vertex_program.c_str();
765         if(pixel_program != "")
766                 pixel_program_ptr = pixel_program.c_str();
767         if(geometry_program != "")
768                 geometry_program_ptr = geometry_program.c_str();
769         s32 shadermat = -1;
770         if(is_highlevel){
771                 infostream<<"Compiling high level shaders for "<<name<<std::endl;
772                 shadermat = gpu->addHighLevelShaderMaterial(
773                         vertex_program_ptr,   // Vertex shader program
774                         "vertexMain",         // Vertex shader entry point
775                         video::EVST_VS_1_1,   // Vertex shader version
776                         pixel_program_ptr,    // Pixel shader program
777                         "pixelMain",          // Pixel shader entry point
778                         video::EPST_PS_1_1,   // Pixel shader version
779                         geometry_program_ptr, // Geometry shader program
780                         "geometryMain",       // Geometry shader entry point
781                         video::EGST_GS_4_0,   // Geometry shader version
782                         scene::EPT_TRIANGLES,      // Geometry shader input
783                         scene::EPT_TRIANGLE_STRIP, // Geometry shader output
784                         0,                         // Support maximum number of vertices
785                         callback,                  // Set-constant callback
786                         shaderinfo.base_material,  // Base material
787                         1                          // Userdata passed to callback
788                         );
789                 if(shadermat == -1){
790                         errorstream<<"generate_shader(): "
791                                         "failed to generate \""<<name<<"\", "
792                                         "addHighLevelShaderMaterial failed."
793                                         <<std::endl;
794                         return shaderinfo;
795                 }
796         }
797         else{
798                 infostream<<"Compiling assembly shaders for "<<name<<std::endl;
799                 shadermat = gpu->addShaderMaterial(
800                         vertex_program_ptr,   // Vertex shader program
801                         pixel_program_ptr,    // Pixel shader program
802                         callback,             // Set-constant callback
803                         shaderinfo.base_material,  // Base material
804                         0                     // Userdata passed to callback
805                         );
806
807                 if(shadermat == -1){
808                         errorstream<<"generate_shader(): "
809                                         "failed to generate \""<<name<<"\", "
810                                         "addShaderMaterial failed."
811                                         <<std::endl;
812                         return shaderinfo;
813                 }
814         }
815
816         // HACK, TODO: investigate this better
817         // Grab the material renderer once more so minetest doesn't crash on exit
818         driver->getMaterialRenderer(shadermat)->grab();
819
820         // Apply the newly created material type
821         shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
822         return shaderinfo;
823 }
824
825 void load_shaders(std::string name, SourceShaderCache *sourcecache,
826                 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
827                 std::string &vertex_program, std::string &pixel_program,
828                 std::string &geometry_program, bool &is_highlevel)
829 {
830         vertex_program = "";
831         pixel_program = "";
832         geometry_program = "";
833         is_highlevel = false;
834
835         if(enable_shaders){
836                 // Look for high level shaders
837                 if(drivertype == video::EDT_DIRECT3D9){
838                         // Direct3D 9: HLSL
839                         // (All shaders in one file)
840                         vertex_program = sourcecache->getOrLoad(name, "d3d9.hlsl");
841                         pixel_program = vertex_program;
842                         geometry_program = vertex_program;
843                 }
844                 else if(drivertype == video::EDT_OPENGL){
845                         // OpenGL: GLSL
846                         vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.glsl");
847                         pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.glsl");
848                         geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl");
849                 }
850                 if(vertex_program != "" || pixel_program != "" || geometry_program != ""){
851                         is_highlevel = true;
852                         return;
853                 }
854         }
855
856 }