Line data Source code
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 1 : 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 29 : std::string getShaderPath(const std::string &name_of_shader,
56 : const std::string &filename)
57 : {
58 58 : std::string combined = name_of_shader + DIR_DELIM + filename;
59 29 : std::string fullpath = "";
60 : /*
61 : Check from cache
62 : */
63 29 : bool incache = g_shadername_to_path_cache.get(combined, &fullpath);
64 29 : if(incache)
65 23 : return fullpath;
66 :
67 : /*
68 : Check from shader_path
69 : */
70 12 : std::string shader_path = g_settings->get("shader_path");
71 6 : if(shader_path != "")
72 : {
73 0 : std::string testpath = shader_path + DIR_DELIM + combined;
74 0 : if(fs::PathExists(testpath))
75 0 : fullpath = testpath;
76 : }
77 :
78 : /*
79 : Check from default data directory
80 : */
81 6 : if(fullpath == "")
82 : {
83 18 : std::string rel_path = std::string("client") + DIR_DELIM
84 12 : + "shaders" + DIR_DELIM
85 12 : + name_of_shader + DIR_DELIM
86 18 : + filename;
87 12 : std::string testpath = porting::path_share + DIR_DELIM + rel_path;
88 6 : if(fs::PathExists(testpath))
89 4 : fullpath = testpath;
90 : }
91 :
92 : // Add to cache (also an empty result is cached)
93 6 : g_shadername_to_path_cache.set(combined, fullpath);
94 :
95 : // Finally return it
96 6 : return fullpath;
97 : }
98 :
99 : /*
100 : SourceShaderCache: A cache used for storing source shaders.
101 : */
102 :
103 2 : class SourceShaderCache
104 : {
105 : public:
106 0 : void insert(const std::string &name_of_shader, const std::string &filename,
107 : const std::string &program, bool prefer_local)
108 : {
109 0 : std::string combined = name_of_shader + DIR_DELIM + filename;
110 : // Try to use local shader instead if asked to
111 0 : if(prefer_local){
112 0 : std::string path = getShaderPath(name_of_shader, filename);
113 0 : if(path != ""){
114 0 : std::string p = readFile(path);
115 0 : if(p != ""){
116 0 : m_programs[combined] = p;
117 0 : return;
118 : }
119 : }
120 : }
121 0 : 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 75 : std::string getOrLoad(const std::string &name_of_shader,
136 : const std::string &filename)
137 : {
138 150 : std::string combined = name_of_shader + DIR_DELIM + filename;
139 75 : StringMap::iterator n = m_programs.find(combined);
140 75 : if (n != m_programs.end())
141 46 : return n->second;
142 58 : std::string path = getShaderPath(name_of_shader, filename);
143 29 : if (path == "") {
144 25 : infostream << "SourceShaderCache::getOrLoad(): No path found for \""
145 25 : << combined << "\"" << std::endl;
146 25 : return "";
147 : }
148 4 : infostream << "SourceShaderCache::getOrLoad(): Loading path \""
149 4 : << path << "\"" << std::endl;
150 8 : std::string p = readFile(path);
151 4 : if (p != "") {
152 4 : m_programs[combined] = p;
153 4 : return p;
154 : }
155 0 : return "";
156 : }
157 : private:
158 : StringMap m_programs;
159 :
160 4 : std::string readFile(const std::string &path)
161 : {
162 8 : std::ifstream is(path.c_str(), std::ios::binary);
163 4 : if(!is.is_open())
164 0 : return "";
165 8 : std::ostringstream tmp_os;
166 4 : tmp_os << is.rdbuf();
167 4 : return tmp_os.str();
168 : }
169 : };
170 :
171 : /*
172 : ShaderCallback: Sets constants that can be used in shaders
173 : */
174 :
175 1 : class IShaderConstantSetterRegistry
176 : {
177 : public:
178 1 : 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 1 : ShaderCallback(IShaderConstantSetterRegistry *scsr, const std::string &name):
190 : m_scsr(scsr),
191 1 : m_name(name)
192 1 : {}
193 0 : ~ShaderCallback() {}
194 :
195 1426078 : virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData)
196 : {
197 1426078 : video::IVideoDriver *driver = services->getVideoDriver();
198 1426078 : sanity_check(driver != NULL);
199 :
200 1426078 : bool is_highlevel = userData;
201 :
202 1426078 : m_scsr->onSetConstants(services, is_highlevel, m_name);
203 1426078 : }
204 : };
205 :
206 : /*
207 : MainShaderConstantSetter: Set basic constants required for almost everything
208 : */
209 :
210 : class MainShaderConstantSetter : public IShaderConstantSetter
211 : {
212 : public:
213 1 : MainShaderConstantSetter(IrrlichtDevice *device)
214 1 : {}
215 2 : ~MainShaderConstantSetter() {}
216 :
217 1426078 : virtual void onSetConstants(video::IMaterialRendererServices *services,
218 : bool is_highlevel)
219 : {
220 1426078 : video::IVideoDriver *driver = services->getVideoDriver();
221 1426078 : sanity_check(driver);
222 :
223 : // set inverted world matrix
224 1426078 : core::matrix4 invWorld = driver->getTransform(video::ETS_WORLD);
225 1426078 : invWorld.makeInverse();
226 1426078 : if(is_highlevel)
227 1426078 : services->setVertexShaderConstant("mInvWorld", invWorld.pointer(), 16);
228 : else
229 0 : services->setVertexShaderConstant(invWorld.pointer(), 0, 4);
230 :
231 : // set clip matrix
232 1426078 : core::matrix4 worldViewProj;
233 1426078 : worldViewProj = driver->getTransform(video::ETS_PROJECTION);
234 1426078 : worldViewProj *= driver->getTransform(video::ETS_VIEW);
235 1426078 : worldViewProj *= driver->getTransform(video::ETS_WORLD);
236 1426078 : if(is_highlevel)
237 1426078 : services->setVertexShaderConstant("mWorldViewProj", worldViewProj.pointer(), 16);
238 : else
239 0 : services->setVertexShaderConstant(worldViewProj.pointer(), 4, 4);
240 :
241 : // set transposed world matrix
242 1426078 : core::matrix4 transWorld = driver->getTransform(video::ETS_WORLD);
243 1426078 : transWorld = transWorld.getTransposed();
244 1426078 : if(is_highlevel)
245 1426078 : services->setVertexShaderConstant("mTransWorld", transWorld.pointer(), 16);
246 : else
247 0 : services->setVertexShaderConstant(transWorld.pointer(), 8, 4);
248 :
249 : // set world matrix
250 1426078 : core::matrix4 world = driver->getTransform(video::ETS_WORLD);
251 1426078 : if(is_highlevel)
252 1426078 : services->setVertexShaderConstant("mWorld", world.pointer(), 16);
253 : else
254 0 : services->setVertexShaderConstant(world.pointer(), 8, 4);
255 :
256 1426078 : }
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 2 : void addGlobalConstantSetter(IShaderConstantSetter *setter)
307 : {
308 2 : m_global_setters.push_back(setter);
309 2 : }
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 1 : IWritableShaderSource* createShaderSource(IrrlichtDevice *device)
342 : {
343 1 : 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 1 : ShaderSource::ShaderSource(IrrlichtDevice *device):
364 1 : m_device(device)
365 : {
366 : assert(m_device); // Pre-condition
367 :
368 1 : m_shader_callback = new ShaderCallback(this, "default");
369 :
370 1 : m_main_thread = get_current_thread_id();
371 :
372 : // Add a dummy ShaderInfo as the first index, named ""
373 1 : m_shaderinfo_cache.push_back(ShaderInfo());
374 :
375 : // Add main global constant setter
376 1 : addGlobalConstantSetter(new MainShaderConstantSetter(device));
377 1 : }
378 :
379 3 : ShaderSource::~ShaderSource()
380 : {
381 9 : for (std::vector<IShaderConstantSetter*>::iterator iter = m_global_setters.begin();
382 6 : iter != m_global_setters.end(); iter++) {
383 2 : delete *iter;
384 : }
385 1 : m_global_setters.clear();
386 :
387 1 : if (m_shader_callback) {
388 1 : m_shader_callback->drop();
389 1 : m_shader_callback = NULL;
390 : }
391 2 : }
392 :
393 31171 : u32 ShaderSource::getShader(const std::string &name,
394 : const u8 material_type, const u8 drawtype)
395 : {
396 : /*
397 : Get shader
398 : */
399 :
400 31171 : if(get_current_thread_id() == m_main_thread){
401 31171 : 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 0 : static ResultQueue<std::string, u32, u8, u8> result_queue;
408 :
409 : // Throw a request in
410 0 : 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 0 : while(true) {
416 : GetResult<std::string, u32, u8, u8>
417 0 : result = result_queue.pop_frontNoEx();
418 :
419 0 : if (result.key == name) {
420 0 : return result.item;
421 : }
422 : else {
423 0 : 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 31171 : 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 31171 : if(name == ""){
444 0 : infostream<<"getShaderIdDirect(): name is empty"<<std::endl;
445 0 : return 0;
446 : }
447 :
448 : // Check if already have such instance
449 215703 : for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
450 215678 : ShaderInfo *info = &m_shaderinfo_cache[i];
451 331916 : if(info->name == name && info->material_type == material_type &&
452 116238 : info->drawtype == drawtype)
453 31146 : return i;
454 : }
455 :
456 : /*
457 : Calling only allowed from main thread
458 : */
459 25 : if(get_current_thread_id() != m_main_thread){
460 : errorstream<<"ShaderSource::getShaderIdDirect() "
461 0 : "called not from main thread"<<std::endl;
462 0 : return 0;
463 : }
464 :
465 : ShaderInfo info = generate_shader(name, material_type, drawtype, m_device,
466 50 : m_shader_callback, &m_sourcecache);
467 :
468 : /*
469 : Add shader to caches (add dummy shaders too)
470 : */
471 :
472 50 : JMutexAutoLock lock(m_shaderinfo_cache_mutex);
473 :
474 25 : u32 id = m_shaderinfo_cache.size();
475 25 : m_shaderinfo_cache.push_back(info);
476 :
477 25 : infostream<<"getShaderIdDirect(): "
478 25 : <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;
479 :
480 25 : return id;
481 : }
482 :
483 :
484 31066 : ShaderInfo ShaderSource::getShaderInfo(u32 id)
485 : {
486 62132 : JMutexAutoLock lock(m_shaderinfo_cache_mutex);
487 :
488 31066 : if(id >= m_shaderinfo_cache.size())
489 0 : return ShaderInfo();
490 :
491 31066 : return m_shaderinfo_cache[id];
492 : }
493 :
494 1168 : void ShaderSource::processQueue()
495 : {
496 :
497 :
498 1168 : }
499 :
500 0 : 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 0 : sanity_check(get_current_thread_id() == m_main_thread);
508 :
509 0 : m_sourcecache.insert(name_of_shader, filename, program, true);
510 0 : }
511 :
512 1 : void ShaderSource::rebuildShaders()
513 : {
514 2 : 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 2 : for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
528 1 : ShaderInfo *info = &m_shaderinfo_cache[i];
529 1 : if(info->name != ""){
530 0 : *info = generate_shader(info->name, info->material_type,
531 0 : info->drawtype, m_device, m_shader_callback, &m_sourcecache);
532 : }
533 : }
534 1 : }
535 :
536 1426078 : void ShaderSource::onSetConstants(video::IMaterialRendererServices *services,
537 : bool is_highlevel, const std::string &name)
538 : {
539 4278234 : for(u32 i=0; i<m_global_setters.size(); i++){
540 2852156 : IShaderConstantSetter *setter = m_global_setters[i];
541 2852156 : setter->onSetConstants(services, is_highlevel);
542 : }
543 1426078 : }
544 :
545 25 : ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
546 : IrrlichtDevice *device, video::IShaderConstantSetCallBack *callback,
547 : SourceShaderCache *sourcecache)
548 : {
549 25 : ShaderInfo shaderinfo;
550 25 : shaderinfo.name = name;
551 25 : shaderinfo.material_type = material_type;
552 25 : shaderinfo.drawtype = drawtype;
553 25 : shaderinfo.material = video::EMT_SOLID;
554 25 : switch(material_type){
555 : case TILE_MATERIAL_BASIC:
556 12 : shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
557 12 : break;
558 : case TILE_MATERIAL_ALPHA:
559 6 : shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
560 6 : break;
561 : case TILE_MATERIAL_LIQUID_TRANSPARENT:
562 3 : shaderinfo.base_material = video::EMT_TRANSPARENT_VERTEX_ALPHA;
563 3 : break;
564 : case TILE_MATERIAL_LIQUID_OPAQUE:
565 2 : shaderinfo.base_material = video::EMT_SOLID;
566 2 : break;
567 : case TILE_MATERIAL_WAVING_LEAVES:
568 1 : shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
569 1 : break;
570 : case TILE_MATERIAL_WAVING_PLANTS:
571 1 : shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
572 1 : break;
573 : }
574 :
575 25 : bool enable_shaders = g_settings->getBool("enable_shaders");
576 25 : if(!enable_shaders)
577 0 : return shaderinfo;
578 :
579 25 : video::IVideoDriver* driver = device->getVideoDriver();
580 25 : sanity_check(driver);
581 :
582 25 : video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
583 25 : if(!gpu){
584 : errorstream<<"generate_shader(): "
585 0 : "failed to generate \""<<name<<"\", "
586 0 : "GPU programming not supported."
587 0 : <<std::endl;
588 0 : return shaderinfo;
589 : }
590 :
591 : // Choose shader language depending on driver type and settings
592 : // Then load shaders
593 50 : std::string vertex_program;
594 50 : std::string pixel_program;
595 50 : std::string geometry_program;
596 : bool is_highlevel;
597 50 : load_shaders(name, sourcecache, driver->getDriverType(),
598 : enable_shaders, vertex_program, pixel_program,
599 25 : geometry_program, is_highlevel);
600 : // Check hardware/driver support
601 75 : if(vertex_program != "" &&
602 25 : !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
603 0 : !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
604 : infostream<<"generate_shader(): vertex shaders disabled "
605 0 : "because of missing driver/hardware support."
606 0 : <<std::endl;
607 0 : vertex_program = "";
608 : }
609 75 : if(pixel_program != "" &&
610 25 : !driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
611 0 : !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
612 : infostream<<"generate_shader(): pixel shaders disabled "
613 0 : "because of missing driver/hardware support."
614 0 : <<std::endl;
615 0 : pixel_program = "";
616 : }
617 25 : if(geometry_program != "" &&
618 0 : !driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
619 : infostream<<"generate_shader(): geometry shaders disabled "
620 0 : "because of missing driver/hardware support."
621 0 : <<std::endl;
622 0 : geometry_program = "";
623 : }
624 :
625 : // If no shaders are used, don't make a separate material type
626 25 : if(vertex_program == "" && pixel_program == "" && geometry_program == "")
627 0 : return shaderinfo;
628 :
629 : // Create shaders header
630 50 : 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 375 : for (int i = 0; i < 14; i++){
652 350 : shaders_header += "#define ";
653 350 : shaders_header += drawTypes[i];
654 350 : shaders_header += " ";
655 350 : shaders_header += itos(i);
656 350 : 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 175 : for (int i = 0; i < 6; i++){
669 150 : shaders_header += "#define ";
670 150 : shaders_header += materialTypes[i];
671 150 : shaders_header += " ";
672 150 : shaders_header += itos(i);
673 150 : shaders_header += "\n";
674 : }
675 :
676 25 : shaders_header += "#define MATERIAL_TYPE ";
677 25 : shaders_header += itos(material_type);
678 25 : shaders_header += "\n";
679 25 : shaders_header += "#define DRAW_TYPE ";
680 25 : shaders_header += itos(drawtype);
681 25 : shaders_header += "\n";
682 :
683 25 : if (g_settings->getBool("generate_normalmaps")) {
684 25 : shaders_header += "#define GENERATE_NORMALMAPS 1\n";
685 : } else {
686 0 : shaders_header += "#define GENERATE_NORMALMAPS 0\n";
687 : }
688 25 : shaders_header += "#define NORMALMAPS_STRENGTH ";
689 25 : shaders_header += ftos(g_settings->getFloat("normalmaps_strength"));
690 25 : shaders_header += "\n";
691 : float sample_step;
692 25 : int smooth = (int)g_settings->getFloat("normalmaps_smooth");
693 25 : switch (smooth){
694 : case 0:
695 0 : sample_step = 0.0078125; // 1.0 / 128.0
696 0 : break;
697 : case 1:
698 25 : sample_step = 0.00390625; // 1.0 / 256.0
699 25 : break;
700 : case 2:
701 0 : sample_step = 0.001953125; // 1.0 / 512.0
702 0 : break;
703 : default:
704 0 : sample_step = 0.0078125;
705 0 : break;
706 : }
707 25 : shaders_header += "#define SAMPLE_STEP ";
708 25 : shaders_header += ftos(sample_step);
709 25 : shaders_header += "\n";
710 :
711 25 : if (g_settings->getBool("enable_bumpmapping"))
712 0 : shaders_header += "#define ENABLE_BUMPMAPPING\n";
713 :
714 25 : if (g_settings->getBool("enable_parallax_occlusion")){
715 25 : int mode = g_settings->getFloat("parallax_occlusion_mode");
716 25 : float scale = g_settings->getFloat("parallax_occlusion_scale");
717 25 : float bias = g_settings->getFloat("parallax_occlusion_bias");
718 25 : int iterations = g_settings->getFloat("parallax_occlusion_iterations");
719 25 : shaders_header += "#define ENABLE_PARALLAX_OCCLUSION\n";
720 25 : shaders_header += "#define PARALLAX_OCCLUSION_MODE ";
721 25 : shaders_header += itos(mode);
722 25 : shaders_header += "\n";
723 25 : shaders_header += "#define PARALLAX_OCCLUSION_SCALE ";
724 25 : shaders_header += ftos(scale);
725 25 : shaders_header += "\n";
726 25 : shaders_header += "#define PARALLAX_OCCLUSION_BIAS ";
727 25 : shaders_header += ftos(bias);
728 25 : shaders_header += "\n";
729 25 : shaders_header += "#define PARALLAX_OCCLUSION_ITERATIONS ";
730 25 : shaders_header += itos(iterations);
731 25 : shaders_header += "\n";
732 : }
733 :
734 25 : if (g_settings->getBool("enable_bumpmapping") || g_settings->getBool("enable_parallax_occlusion"))
735 25 : shaders_header += "#define USE_NORMALMAPS\n";
736 :
737 25 : if (g_settings->getBool("enable_waving_water")){
738 25 : shaders_header += "#define ENABLE_WAVING_WATER 1\n";
739 25 : shaders_header += "#define WATER_WAVE_HEIGHT ";
740 25 : shaders_header += ftos(g_settings->getFloat("water_wave_height"));
741 25 : shaders_header += "\n";
742 25 : shaders_header += "#define WATER_WAVE_LENGTH ";
743 25 : shaders_header += ftos(g_settings->getFloat("water_wave_length"));
744 25 : shaders_header += "\n";
745 25 : shaders_header += "#define WATER_WAVE_SPEED ";
746 25 : shaders_header += ftos(g_settings->getFloat("water_wave_speed"));
747 25 : shaders_header += "\n";
748 : } else{
749 0 : shaders_header += "#define ENABLE_WAVING_WATER 0\n";
750 : }
751 :
752 25 : shaders_header += "#define ENABLE_WAVING_LEAVES ";
753 25 : if (g_settings->getBool("enable_waving_leaves"))
754 25 : shaders_header += "1\n";
755 : else
756 0 : shaders_header += "0\n";
757 :
758 25 : shaders_header += "#define ENABLE_WAVING_PLANTS ";
759 25 : if (g_settings->getBool("enable_waving_plants"))
760 25 : shaders_header += "1\n";
761 : else
762 0 : shaders_header += "0\n";
763 :
764 25 : if(pixel_program != "")
765 25 : pixel_program = shaders_header + pixel_program;
766 25 : if(vertex_program != "")
767 25 : vertex_program = shaders_header + vertex_program;
768 25 : if(geometry_program != "")
769 0 : geometry_program = shaders_header + geometry_program;
770 : // Call addHighLevelShaderMaterial() or addShaderMaterial()
771 25 : const c8* vertex_program_ptr = 0;
772 25 : const c8* pixel_program_ptr = 0;
773 25 : const c8* geometry_program_ptr = 0;
774 25 : if(vertex_program != "")
775 25 : vertex_program_ptr = vertex_program.c_str();
776 25 : if(pixel_program != "")
777 25 : pixel_program_ptr = pixel_program.c_str();
778 25 : if(geometry_program != "")
779 0 : geometry_program_ptr = geometry_program.c_str();
780 25 : s32 shadermat = -1;
781 25 : if(is_highlevel){
782 25 : infostream<<"Compiling high level shaders for "<<name<<std::endl;
783 25 : shadermat = gpu->addHighLevelShaderMaterial(
784 : vertex_program_ptr, // Vertex shader program
785 : "vertexMain", // Vertex shader entry point
786 : video::EVST_VS_1_1, // Vertex shader version
787 : pixel_program_ptr, // Pixel shader program
788 : "pixelMain", // Pixel shader entry point
789 : video::EPST_PS_1_1, // Pixel shader version
790 : geometry_program_ptr, // Geometry shader program
791 : "geometryMain", // Geometry shader entry point
792 : video::EGST_GS_4_0, // Geometry shader version
793 : scene::EPT_TRIANGLES, // Geometry shader input
794 : scene::EPT_TRIANGLE_STRIP, // Geometry shader output
795 : 0, // Support maximum number of vertices
796 : callback, // Set-constant callback
797 : shaderinfo.base_material, // Base material
798 : 1 // Userdata passed to callback
799 50 : );
800 25 : if(shadermat == -1){
801 : errorstream<<"generate_shader(): "
802 0 : "failed to generate \""<<name<<"\", "
803 0 : "addHighLevelShaderMaterial failed."
804 0 : <<std::endl;
805 0 : return shaderinfo;
806 : }
807 : }
808 : else{
809 0 : infostream<<"Compiling assembly shaders for "<<name<<std::endl;
810 0 : shadermat = gpu->addShaderMaterial(
811 : vertex_program_ptr, // Vertex shader program
812 : pixel_program_ptr, // Pixel shader program
813 : callback, // Set-constant callback
814 : shaderinfo.base_material, // Base material
815 : 0 // Userdata passed to callback
816 0 : );
817 :
818 0 : if(shadermat == -1){
819 : errorstream<<"generate_shader(): "
820 0 : "failed to generate \""<<name<<"\", "
821 0 : "addShaderMaterial failed."
822 0 : <<std::endl;
823 0 : return shaderinfo;
824 : }
825 : }
826 :
827 : // HACK, TODO: investigate this better
828 : // Grab the material renderer once more so minetest doesn't crash on exit
829 25 : driver->getMaterialRenderer(shadermat)->grab();
830 :
831 : // Apply the newly created material type
832 25 : shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
833 25 : return shaderinfo;
834 : }
835 :
836 25 : void load_shaders(std::string name, SourceShaderCache *sourcecache,
837 : video::E_DRIVER_TYPE drivertype, bool enable_shaders,
838 : std::string &vertex_program, std::string &pixel_program,
839 : std::string &geometry_program, bool &is_highlevel)
840 : {
841 25 : vertex_program = "";
842 25 : pixel_program = "";
843 25 : geometry_program = "";
844 25 : is_highlevel = false;
845 :
846 25 : if(enable_shaders){
847 : // Look for high level shaders
848 25 : if(drivertype == video::EDT_DIRECT3D9){
849 : // Direct3D 9: HLSL
850 : // (All shaders in one file)
851 0 : vertex_program = sourcecache->getOrLoad(name, "d3d9.hlsl");
852 0 : pixel_program = vertex_program;
853 0 : geometry_program = vertex_program;
854 : }
855 25 : else if(drivertype == video::EDT_OPENGL){
856 : // OpenGL: GLSL
857 25 : vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.glsl");
858 25 : pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.glsl");
859 25 : geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl");
860 : }
861 25 : if(vertex_program != "" || pixel_program != "" || geometry_program != ""){
862 25 : is_highlevel = true;
863 25 : return;
864 : }
865 : }
866 :
867 3 : }
|