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