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