]> git.lizzy.rs Git - minetest.git/blob - src/shader.cpp
dofile error reporting for syntax errors
[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 <fstream>
22 #include <iterator>
23 #include "shader.h"
24 #include "irrlichttypes_extrabloated.h"
25 #include "debug.h"
26 #include "filesys.h"
27 #include "util/container.h"
28 #include "util/thread.h"
29 #include "settings.h"
30 #include <ICameraSceneNode.h>
31 #include <IGPUProgrammingServices.h>
32 #include <IMaterialRenderer.h>
33 #include <IMaterialRendererServices.h>
34 #include <IShaderConstantSetCallBack.h>
35 #include "EShaderTypes.h"
36 #include "log.h"
37 #include "gamedef.h"
38 #include "strfnd.h" // trim()
39 #include "client/tile.h"
40
41 /*
42         A cache from shader name to shader path
43 */
44 MutexedMap<std::string, std::string> g_shadername_to_path_cache;
45
46 /*
47         Gets the path to a shader by first checking if the file
48           name_of_shader/filename
49         exists in shader_path and if not, using the data path.
50
51         If not found, returns "".
52
53         Utilizes a thread-safe cache.
54 */
55 std::string getShaderPath(const std::string &name_of_shader,
56                 const std::string &filename)
57 {
58         std::string combined = name_of_shader + DIR_DELIM + filename;
59         std::string fullpath = "";
60         /*
61                 Check from cache
62         */
63         bool incache = g_shadername_to_path_cache.get(combined, &fullpath);
64         if(incache)
65                 return fullpath;
66
67         /*
68                 Check from shader_path
69         */
70         std::string shader_path = g_settings->get("shader_path");
71         if(shader_path != "")
72         {
73                 std::string testpath = shader_path + DIR_DELIM + combined;
74                 if(fs::PathExists(testpath))
75                         fullpath = testpath;
76         }
77
78         /*
79                 Check from default data directory
80         */
81         if(fullpath == "")
82         {
83                 std::string rel_path = std::string("client") + DIR_DELIM
84                                 + "shaders" + DIR_DELIM
85                                 + name_of_shader + DIR_DELIM
86                                 + filename;
87                 std::string testpath = porting::path_share + DIR_DELIM + rel_path;
88                 if(fs::PathExists(testpath))
89                         fullpath = testpath;
90         }
91
92         // Add to cache (also an empty result is cached)
93         g_shadername_to_path_cache.set(combined, fullpath);
94
95         // Finally return it
96         return fullpath;
97 }
98
99 /*
100         SourceShaderCache: A cache used for storing source shaders.
101 */
102
103 class SourceShaderCache
104 {
105 public:
106         void insert(const std::string &name_of_shader, const std::string &filename,
107                 const std::string &program, bool prefer_local)
108         {
109                 std::string combined = name_of_shader + DIR_DELIM + filename;
110                 // Try to use local shader instead if asked to
111                 if(prefer_local){
112                         std::string path = getShaderPath(name_of_shader, filename);
113                         if(path != ""){
114                                 std::string p = readFile(path);
115                                 if(p != ""){
116                                         m_programs[combined] = p;
117                                         return;
118                                 }
119                         }
120                 }
121                 m_programs[combined] = program;
122         }
123
124         std::string get(const std::string &name_of_shader,
125                 const std::string &filename)
126         {
127                 std::string combined = name_of_shader + DIR_DELIM + filename;
128                 StringMap::iterator n = m_programs.find(combined);
129                 if (n != m_programs.end())
130                         return n->second;
131                 return "";
132         }
133
134         // Primarily fetches from cache, secondarily tries to read from filesystem
135         std::string getOrLoad(const std::string &name_of_shader,
136                 const std::string &filename)
137         {
138                 std::string combined = name_of_shader + DIR_DELIM + filename;
139                 StringMap::iterator n = m_programs.find(combined);
140                 if (n != m_programs.end())
141                         return n->second;
142                 std::string path = getShaderPath(name_of_shader, filename);
143                 if (path == "") {
144                         infostream << "SourceShaderCache::getOrLoad(): No path found for \""
145                                 << combined << "\"" << std::endl;
146                         return "";
147                 }
148                 infostream << "SourceShaderCache::getOrLoad(): Loading path \""
149                         << path << "\"" << std::endl;
150                 std::string p = readFile(path);
151                 if (p != "") {
152                         m_programs[combined] = p;
153                         return p;
154                 }
155                 return "";
156         }
157 private:
158         StringMap m_programs;
159
160         std::string readFile(const std::string &path)
161         {
162                 std::ifstream is(path.c_str(), std::ios::binary);
163                 if(!is.is_open())
164                         return "";
165                 std::ostringstream tmp_os;
166                 tmp_os << is.rdbuf();
167                 return tmp_os.str();
168         }
169 };
170
171 /*
172         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                 sanity_check(driver != NULL);
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                 sanity_check(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                 - If shader material specified by name is found from cache,
271                   return the cached id.
272                 - Otherwise generate the shader material, add to cache and return id.
273
274                 The id 0 points to a null shader. Its material is EMT_SOLID.
275         */
276         u32 getShaderIdDirect(const std::string &name,
277                 const u8 material_type, const u8 drawtype);
278
279         /*
280                 If shader specified by the name pointed by the id doesn't
281                 exist, create it, then return id.
282
283                 Can be called from any thread. If called from some other thread
284                 and not found in cache, the call is queued to the main thread
285                 for processing.
286         */
287
288         u32 getShader(const std::string &name,
289                 const u8 material_type, const u8 drawtype);
290
291         ShaderInfo getShaderInfo(u32 id);
292
293         // Processes queued shader requests from other threads.
294         // Shall be called from the main thread.
295         void processQueue();
296
297         // Insert a shader program into the cache without touching the
298         // filesystem. Shall be called from the main thread.
299         void insertSourceShader(const std::string &name_of_shader,
300                 const std::string &filename, const std::string &program);
301
302         // Rebuild shaders from the current set of source shaders
303         // Shall be called from the main thread.
304         void rebuildShaders();
305
306         void addGlobalConstantSetter(IShaderConstantSetter *setter)
307         {
308                 m_global_setters.push_back(setter);
309         }
310
311         void onSetConstants(video::IMaterialRendererServices *services,
312                         bool is_highlevel, const std::string &name);
313
314 private:
315
316         // The id of the thread that is allowed to use irrlicht directly
317         threadid_t m_main_thread;
318         // The irrlicht device
319         IrrlichtDevice *m_device;
320         // The set-constants callback
321         ShaderCallback *m_shader_callback;
322
323         // Cache of source shaders
324         // This should be only accessed from the main thread
325         SourceShaderCache m_sourcecache;
326
327         // A shader id is index in this array.
328         // The first position contains a dummy shader.
329         std::vector<ShaderInfo> m_shaderinfo_cache;
330         // The former container is behind this mutex
331         JMutex m_shaderinfo_cache_mutex;
332
333         // Queued shader fetches (to be processed by the main thread)
334         RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
335
336         // Global constant setters
337         // TODO: Delete these in the destructor
338         std::vector<IShaderConstantSetter*> m_global_setters;
339 };
340
341 IWritableShaderSource* createShaderSource(IrrlichtDevice *device)
342 {
343         return new ShaderSource(device);
344 }
345
346 /*
347         Generate shader given the shader name.
348 */
349 ShaderInfo generate_shader(std::string name,
350                 u8 material_type, u8 drawtype,
351                 IrrlichtDevice *device,
352                 video::IShaderConstantSetCallBack *callback,
353                 SourceShaderCache *sourcecache);
354
355 /*
356         Load shader programs
357 */
358 void load_shaders(std::string name, SourceShaderCache *sourcecache,
359                 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
360                 std::string &vertex_program, std::string &pixel_program,
361                 std::string &geometry_program, bool &is_highlevel);
362
363 ShaderSource::ShaderSource(IrrlichtDevice *device):
364                 m_device(device)
365 {
366         assert(m_device); // Pre-condition
367
368         m_shader_callback = new ShaderCallback(this, "default");
369
370         m_main_thread = get_current_thread_id();
371
372         // Add a dummy ShaderInfo as the first index, named ""
373         m_shaderinfo_cache.push_back(ShaderInfo());
374
375         // Add main global constant setter
376         addGlobalConstantSetter(new MainShaderConstantSetter(device));
377 }
378
379 ShaderSource::~ShaderSource()
380 {
381         for (std::vector<IShaderConstantSetter*>::iterator iter = m_global_setters.begin();
382                         iter != m_global_setters.end(); iter++) {
383                 delete *iter;
384         }
385         m_global_setters.clear();
386
387         if (m_shader_callback) {
388                 m_shader_callback->drop();
389                 m_shader_callback = NULL;
390         }
391 }
392
393 u32 ShaderSource::getShader(const std::string &name,
394                 const u8 material_type, const u8 drawtype)
395 {
396         /*
397                 Get shader
398         */
399
400         if(get_current_thread_id() == m_main_thread){
401                 return getShaderIdDirect(name, material_type, drawtype);
402         } else {
403                 /*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/
404
405                 // We're gonna ask the result to be put into here
406
407                 static ResultQueue<std::string, u32, u8, u8> result_queue;
408
409                 // Throw a request in
410                 m_get_shader_queue.add(name, 0, 0, &result_queue);
411
412                 /* infostream<<"Waiting for shader from main thread, name=\""
413                                 <<name<<"\""<<std::endl;*/
414
415                 while(true) {
416                         GetResult<std::string, u32, u8, u8>
417                                 result = result_queue.pop_frontNoEx();
418
419                         if (result.key == name) {
420                                 return result.item;
421                         }
422                         else {
423                                 errorstream << "Got shader with invalid name: " << result.key << std::endl;
424                         }
425                 }
426
427         }
428
429         infostream<<"getShader(): Failed"<<std::endl;
430
431         return 0;
432 }
433
434 /*
435         This method generates all the shaders
436 */
437 u32 ShaderSource::getShaderIdDirect(const std::string &name,
438                 const u8 material_type, const u8 drawtype)
439 {
440         //infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
441
442         // Empty name means shader 0
443         if(name == ""){
444                 infostream<<"getShaderIdDirect(): name is empty"<<std::endl;
445                 return 0;
446         }
447
448         // Check if already have such instance
449         for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
450                 ShaderInfo *info = &m_shaderinfo_cache[i];
451                 if(info->name == name && info->material_type == material_type &&
452                         info->drawtype == drawtype)
453                         return i;
454         }
455
456         /*
457                 Calling only allowed from main thread
458         */
459         if(get_current_thread_id() != m_main_thread){
460                 errorstream<<"ShaderSource::getShaderIdDirect() "
461                                 "called not from main thread"<<std::endl;
462                 return 0;
463         }
464
465         ShaderInfo info = generate_shader(name, material_type, drawtype, m_device,
466                         m_shader_callback, &m_sourcecache);
467
468         /*
469                 Add shader to caches (add dummy shaders too)
470         */
471
472         JMutexAutoLock lock(m_shaderinfo_cache_mutex);
473
474         u32 id = m_shaderinfo_cache.size();
475         m_shaderinfo_cache.push_back(info);
476
477         infostream<<"getShaderIdDirect(): "
478                         <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;
479
480         return id;
481 }
482
483
484 ShaderInfo ShaderSource::getShaderInfo(u32 id)
485 {
486         JMutexAutoLock lock(m_shaderinfo_cache_mutex);
487
488         if(id >= m_shaderinfo_cache.size())
489                 return ShaderInfo();
490
491         return m_shaderinfo_cache[id];
492 }
493
494 void ShaderSource::processQueue()
495 {
496
497
498 }
499
500 void ShaderSource::insertSourceShader(const std::string &name_of_shader,
501                 const std::string &filename, const std::string &program)
502 {
503         /*infostream<<"ShaderSource::insertSourceShader(): "
504                         "name_of_shader=\""<<name_of_shader<<"\", "
505                         "filename=\""<<filename<<"\""<<std::endl;*/
506
507         sanity_check(get_current_thread_id() == m_main_thread);
508
509         m_sourcecache.insert(name_of_shader, filename, program, true);
510 }
511
512 void ShaderSource::rebuildShaders()
513 {
514         JMutexAutoLock lock(m_shaderinfo_cache_mutex);
515
516         /*// Oh well... just clear everything, they'll load sometime.
517         m_shaderinfo_cache.clear();
518         m_name_to_id.clear();*/
519
520         /*
521                 FIXME: Old shader materials can't be deleted in Irrlicht,
522                 or can they?
523                 (This would be nice to do in the destructor too)
524         */
525
526         // Recreate shaders
527         for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
528                 ShaderInfo *info = &m_shaderinfo_cache[i];
529                 if(info->name != ""){
530                         *info = generate_shader(info->name, info->material_type,
531                                         info->drawtype, m_device, m_shader_callback, &m_sourcecache);
532                 }
533         }
534 }
535
536 void ShaderSource::onSetConstants(video::IMaterialRendererServices *services,
537                 bool is_highlevel, const std::string &name)
538 {
539         for(u32 i=0; i<m_global_setters.size(); i++){
540                 IShaderConstantSetter *setter = m_global_setters[i];
541                 setter->onSetConstants(services, is_highlevel);
542         }
543 }
544
545 ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
546                 IrrlichtDevice *device, video::IShaderConstantSetCallBack *callback,
547                 SourceShaderCache *sourcecache)
548 {
549         ShaderInfo shaderinfo;
550         shaderinfo.name = name;
551         shaderinfo.material_type = material_type;
552         shaderinfo.drawtype = drawtype;
553         shaderinfo.material = video::EMT_SOLID;
554         switch(material_type){
555                 case TILE_MATERIAL_BASIC:
556                         shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
557                         break;
558                 case TILE_MATERIAL_ALPHA:
559                         shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
560                         break;
561                 case TILE_MATERIAL_LIQUID_TRANSPARENT:
562                         shaderinfo.base_material = video::EMT_TRANSPARENT_VERTEX_ALPHA;
563                         break;
564                 case TILE_MATERIAL_LIQUID_OPAQUE:
565                         shaderinfo.base_material = video::EMT_SOLID;
566                         break;
567                 case TILE_MATERIAL_WAVING_LEAVES:
568                         shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
569                         break;
570                 case TILE_MATERIAL_WAVING_PLANTS:
571                         shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
572                 break;
573         }
574
575         bool enable_shaders = g_settings->getBool("enable_shaders");
576         if(!enable_shaders)
577                 return shaderinfo;
578
579         video::IVideoDriver* driver = device->getVideoDriver();
580         sanity_check(driver);
581
582         video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
583         if(!gpu){
584                 errorstream<<"generate_shader(): "
585                                 "failed to generate \""<<name<<"\", "
586                                 "GPU programming not supported."
587                                 <<std::endl;
588                 return shaderinfo;
589         }
590
591         // Choose shader language depending on driver type and settings
592         // Then load shaders
593         std::string vertex_program;
594         std::string pixel_program;
595         std::string geometry_program;
596         bool is_highlevel;
597         load_shaders(name, sourcecache, driver->getDriverType(),
598                         enable_shaders, vertex_program, pixel_program,
599                         geometry_program, is_highlevel);
600         // Check hardware/driver support
601         if(vertex_program != "" &&
602                         !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
603                         !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
604                 infostream<<"generate_shader(): vertex shaders disabled "
605                                 "because of missing driver/hardware support."
606                                 <<std::endl;
607                 vertex_program = "";
608         }
609         if(pixel_program != "" &&
610                         !driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
611                         !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
612                 infostream<<"generate_shader(): pixel shaders disabled "
613                                 "because of missing driver/hardware support."
614                                 <<std::endl;
615                 pixel_program = "";
616         }
617         if(geometry_program != "" &&
618                         !driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
619                 infostream<<"generate_shader(): geometry shaders disabled "
620                                 "because of missing driver/hardware support."
621                                 <<std::endl;
622                 geometry_program = "";
623         }
624
625         // If no shaders are used, don't make a separate material type
626         if(vertex_program == "" && pixel_program == "" && geometry_program == "")
627                 return shaderinfo;
628
629         // Create shaders header
630         std::string shaders_header = "#version 120\n";
631
632         static const char* drawTypes[] = {
633                 "NDT_NORMAL",
634                 "NDT_AIRLIKE",
635                 "NDT_LIQUID",
636                 "NDT_FLOWINGLIQUID",
637                 "NDT_GLASSLIKE",
638                 "NDT_ALLFACES",
639                 "NDT_ALLFACES_OPTIONAL",
640                 "NDT_TORCHLIKE",
641                 "NDT_SIGNLIKE",
642                 "NDT_PLANTLIKE",
643                 "NDT_FENCELIKE",
644                 "NDT_RAILLIKE",
645                 "NDT_NODEBOX",
646                 "NDT_GLASSLIKE_FRAMED",
647                 "NDT_FIRELIKE",
648                 "NDT_GLASSLIKE_FRAMED_OPTIONAL"
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 }