123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829 |
- /*
- Minetest
- Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
- Copyright (C) 2013 Kahrl <kahrl@gmx.net>
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
- #include <fstream>
- #include <iterator>
- #include "shader.h"
- #include "irrlichttypes_extrabloated.h"
- #include "irr_ptr.h"
- #include "debug.h"
- #include "filesys.h"
- #include "util/container.h"
- #include "util/thread.h"
- #include "settings.h"
- #include <ICameraSceneNode.h>
- #include <IGPUProgrammingServices.h>
- #include <IMaterialRenderer.h>
- #include <IMaterialRendererServices.h>
- #include <IShaderConstantSetCallBack.h>
- #include "client/renderingengine.h"
- #include "EShaderTypes.h"
- #include "log.h"
- #include "gamedef.h"
- #include "client/tile.h"
- #include "config.h"
- #include <mt_opengl.h>
- /*
- A cache from shader name to shader path
- */
- MutexedMap<std::string, std::string> g_shadername_to_path_cache;
- /*
- Gets the path to a shader by first checking if the file
- name_of_shader/filename
- exists in shader_path and if not, using the data path.
- If not found, returns "".
- Utilizes a thread-safe cache.
- */
- std::string getShaderPath(const std::string &name_of_shader,
- const std::string &filename)
- {
- std::string combined = name_of_shader + DIR_DELIM + filename;
- std::string fullpath;
- /*
- Check from cache
- */
- bool incache = g_shadername_to_path_cache.get(combined, &fullpath);
- if(incache)
- return fullpath;
- /*
- Check from shader_path
- */
- std::string shader_path = g_settings->get("shader_path");
- if (!shader_path.empty()) {
- std::string testpath = shader_path + DIR_DELIM + combined;
- if(fs::PathExists(testpath))
- fullpath = testpath;
- }
- /*
- Check from default data directory
- */
- if (fullpath.empty()) {
- std::string rel_path = std::string("client") + DIR_DELIM
- + "shaders" + DIR_DELIM
- + name_of_shader + DIR_DELIM
- + filename;
- std::string testpath = porting::path_share + DIR_DELIM + rel_path;
- if(fs::PathExists(testpath))
- fullpath = testpath;
- }
- // Add to cache (also an empty result is cached)
- g_shadername_to_path_cache.set(combined, fullpath);
- // Finally return it
- return fullpath;
- }
- /*
- SourceShaderCache: A cache used for storing source shaders.
- */
- class SourceShaderCache
- {
- public:
- void insert(const std::string &name_of_shader, const std::string &filename,
- const std::string &program, bool prefer_local)
- {
- std::string combined = name_of_shader + DIR_DELIM + filename;
- // Try to use local shader instead if asked to
- if(prefer_local){
- std::string path = getShaderPath(name_of_shader, filename);
- if(!path.empty()){
- std::string p = readFile(path);
- if (!p.empty()) {
- m_programs[combined] = p;
- return;
- }
- }
- }
- m_programs[combined] = program;
- }
- std::string get(const std::string &name_of_shader,
- const std::string &filename)
- {
- std::string combined = name_of_shader + DIR_DELIM + filename;
- StringMap::iterator n = m_programs.find(combined);
- if (n != m_programs.end())
- return n->second;
- return "";
- }
- // Primarily fetches from cache, secondarily tries to read from filesystem
- std::string getOrLoad(const std::string &name_of_shader,
- const std::string &filename)
- {
- std::string combined = name_of_shader + DIR_DELIM + filename;
- StringMap::iterator n = m_programs.find(combined);
- if (n != m_programs.end())
- return n->second;
- std::string path = getShaderPath(name_of_shader, filename);
- if (path.empty()) {
- infostream << "SourceShaderCache::getOrLoad(): No path found for \""
- << combined << "\"" << std::endl;
- return "";
- }
- infostream << "SourceShaderCache::getOrLoad(): Loading path \""
- << path << "\"" << std::endl;
- std::string p = readFile(path);
- if (!p.empty()) {
- m_programs[combined] = p;
- return p;
- }
- return "";
- }
- private:
- StringMap m_programs;
- std::string readFile(const std::string &path)
- {
- std::ifstream is(path.c_str(), std::ios::binary);
- if(!is.is_open())
- return "";
- std::ostringstream tmp_os;
- tmp_os << is.rdbuf();
- return tmp_os.str();
- }
- };
- /*
- ShaderCallback: Sets constants that can be used in shaders
- */
- class ShaderCallback : public video::IShaderConstantSetCallBack
- {
- std::vector<std::unique_ptr<IShaderConstantSetter>> m_setters;
- public:
- template <typename Factories>
- ShaderCallback(const Factories &factories)
- {
- for (auto &&factory : factories)
- m_setters.push_back(std::unique_ptr<IShaderConstantSetter>(factory->create()));
- }
- virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData) override
- {
- video::IVideoDriver *driver = services->getVideoDriver();
- sanity_check(driver != NULL);
- for (auto &&setter : m_setters)
- setter->onSetConstants(services);
- }
- virtual void OnSetMaterial(const video::SMaterial& material) override
- {
- for (auto &&setter : m_setters)
- setter->onSetMaterial(material);
- }
- };
- /*
- MainShaderConstantSetter: Set basic constants required for almost everything
- */
- class MainShaderConstantSetter : public IShaderConstantSetter
- {
- CachedVertexShaderSetting<f32, 16> m_world_view_proj;
- CachedVertexShaderSetting<f32, 16> m_world;
- // Shadow-related
- CachedPixelShaderSetting<f32, 16> m_shadow_view_proj;
- CachedPixelShaderSetting<f32, 3> m_light_direction;
- CachedPixelShaderSetting<f32> m_texture_res;
- CachedPixelShaderSetting<f32> m_shadow_strength;
- CachedPixelShaderSetting<f32> m_time_of_day;
- CachedPixelShaderSetting<f32> m_shadowfar;
- CachedPixelShaderSetting<f32, 4> m_camera_pos;
- CachedPixelShaderSetting<s32> m_shadow_texture;
- CachedVertexShaderSetting<f32> m_perspective_bias0_vertex;
- CachedPixelShaderSetting<f32> m_perspective_bias0_pixel;
- CachedVertexShaderSetting<f32> m_perspective_bias1_vertex;
- CachedPixelShaderSetting<f32> m_perspective_bias1_pixel;
- CachedVertexShaderSetting<f32> m_perspective_zbias_vertex;
- CachedPixelShaderSetting<f32> m_perspective_zbias_pixel;
- #if ENABLE_GLES
- // Modelview matrix
- CachedVertexShaderSetting<float, 16> m_world_view;
- // Texture matrix
- CachedVertexShaderSetting<float, 16> m_texture;
- // Normal matrix
- CachedVertexShaderSetting<float, 9> m_normal;
- #endif
- public:
- MainShaderConstantSetter() :
- m_world_view_proj("mWorldViewProj")
- , m_world("mWorld")
- , m_shadow_view_proj("m_ShadowViewProj")
- , m_light_direction("v_LightDirection")
- , m_texture_res("f_textureresolution")
- , m_shadow_strength("f_shadow_strength")
- , m_time_of_day("f_timeofday")
- , m_shadowfar("f_shadowfar")
- , m_camera_pos("CameraPos")
- , m_shadow_texture("ShadowMapSampler")
- , m_perspective_bias0_vertex("xyPerspectiveBias0")
- , m_perspective_bias0_pixel("xyPerspectiveBias0")
- , m_perspective_bias1_vertex("xyPerspectiveBias1")
- , m_perspective_bias1_pixel("xyPerspectiveBias1")
- , m_perspective_zbias_vertex("zPerspectiveBias")
- , m_perspective_zbias_pixel("zPerspectiveBias")
- #if ENABLE_GLES
- , m_world_view("mWorldView")
- , m_texture("mTexture")
- , m_normal("mNormal")
- #endif
- {}
- ~MainShaderConstantSetter() = default;
- virtual void onSetConstants(video::IMaterialRendererServices *services) override
- {
- video::IVideoDriver *driver = services->getVideoDriver();
- sanity_check(driver);
- // Set world matrix
- core::matrix4 world = driver->getTransform(video::ETS_WORLD);
- m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
- // Set clip matrix
- core::matrix4 worldView;
- worldView = driver->getTransform(video::ETS_VIEW);
- worldView *= world;
- core::matrix4 worldViewProj;
- worldViewProj = driver->getTransform(video::ETS_PROJECTION);
- worldViewProj *= worldView;
- m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
- #if ENABLE_GLES
- core::matrix4 texture = driver->getTransform(video::ETS_TEXTURE_0);
- m_world_view.set(*reinterpret_cast<float(*)[16]>(worldView.pointer()), services);
- m_texture.set(*reinterpret_cast<float(*)[16]>(texture.pointer()), services);
- core::matrix4 normal;
- worldView.getTransposed(normal);
- sanity_check(normal.makeInverse());
- float m[9] = {
- normal[0], normal[1], normal[2],
- normal[4], normal[5], normal[6],
- normal[8], normal[9], normal[10],
- };
- m_normal.set(m, services);
- #endif
- // Set uniforms for Shadow shader
- if (ShadowRenderer *shadow = RenderingEngine::get_shadow_renderer()) {
- const auto &light = shadow->getDirectionalLight();
- core::matrix4 shadowViewProj = light.getProjectionMatrix();
- shadowViewProj *= light.getViewMatrix();
- m_shadow_view_proj.set(shadowViewProj.pointer(), services);
- f32 v_LightDirection[3];
- light.getDirection().getAs3Values(v_LightDirection);
- m_light_direction.set(v_LightDirection, services);
- f32 TextureResolution = light.getMapResolution();
- m_texture_res.set(&TextureResolution, services);
- f32 ShadowStrength = shadow->getShadowStrength();
- m_shadow_strength.set(&ShadowStrength, services);
- f32 timeOfDay = shadow->getTimeOfDay();
- m_time_of_day.set(&timeOfDay, services);
- f32 shadowFar = shadow->getMaxShadowFar();
- m_shadowfar.set(&shadowFar, services);
- f32 cam_pos[4];
- shadowViewProj.transformVect(cam_pos, light.getPlayerPos());
- m_camera_pos.set(cam_pos, services);
- // I dont like using this hardcoded value. maybe something like
- // MAX_TEXTURE - 1 or somthing like that??
- s32 TextureLayerID = 3;
- m_shadow_texture.set(&TextureLayerID, services);
- f32 bias0 = shadow->getPerspectiveBiasXY();
- m_perspective_bias0_vertex.set(&bias0, services);
- m_perspective_bias0_pixel.set(&bias0, services);
- f32 bias1 = 1.0f - bias0 + 1e-5f;
- m_perspective_bias1_vertex.set(&bias1, services);
- m_perspective_bias1_pixel.set(&bias1, services);
- f32 zbias = shadow->getPerspectiveBiasZ();
- m_perspective_zbias_vertex.set(&zbias, services);
- m_perspective_zbias_pixel.set(&zbias, services);
- }
- }
- };
- class MainShaderConstantSetterFactory : public IShaderConstantSetterFactory
- {
- public:
- virtual IShaderConstantSetter* create()
- { return new MainShaderConstantSetter(); }
- };
- /*
- ShaderSource
- */
- class ShaderSource : public IWritableShaderSource
- {
- public:
- ShaderSource();
- /*
- - If shader material specified by name is found from cache,
- return the cached id.
- - Otherwise generate the shader material, add to cache and return id.
- The id 0 points to a null shader. Its material is EMT_SOLID.
- */
- u32 getShaderIdDirect(const std::string &name,
- MaterialType material_type, NodeDrawType drawtype) override;
- /*
- If shader specified by the name pointed by the id doesn't
- exist, create it, then return id.
- Can be called from any thread. If called from some other thread
- and not found in cache, the call is queued to the main thread
- for processing.
- */
- u32 getShader(const std::string &name,
- MaterialType material_type, NodeDrawType drawtype) override;
- ShaderInfo getShaderInfo(u32 id) override;
- // Processes queued shader requests from other threads.
- // Shall be called from the main thread.
- void processQueue() override;
- // Insert a shader program into the cache without touching the
- // filesystem. Shall be called from the main thread.
- void insertSourceShader(const std::string &name_of_shader,
- const std::string &filename, const std::string &program) override;
- // Rebuild shaders from the current set of source shaders
- // Shall be called from the main thread.
- void rebuildShaders() override;
- void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter) override
- {
- m_setter_factories.push_back(std::unique_ptr<IShaderConstantSetterFactory>(setter));
- }
- private:
- // The id of the thread that is allowed to use irrlicht directly
- std::thread::id m_main_thread;
- // Cache of source shaders
- // This should be only accessed from the main thread
- SourceShaderCache m_sourcecache;
- // A shader id is index in this array.
- // The first position contains a dummy shader.
- std::vector<ShaderInfo> m_shaderinfo_cache;
- // The former container is behind this mutex
- std::mutex m_shaderinfo_cache_mutex;
- // Queued shader fetches (to be processed by the main thread)
- RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
- // Global constant setter factories
- std::vector<std::unique_ptr<IShaderConstantSetterFactory>> m_setter_factories;
- // Generate shader given the shader name.
- ShaderInfo generateShader(const std::string &name,
- MaterialType material_type, NodeDrawType drawtype);
- };
- IWritableShaderSource *createShaderSource()
- {
- return new ShaderSource();
- }
- ShaderSource::ShaderSource()
- {
- m_main_thread = std::this_thread::get_id();
- // Add a dummy ShaderInfo as the first index, named ""
- m_shaderinfo_cache.emplace_back();
- // Add main global constant setter
- addShaderConstantSetterFactory(new MainShaderConstantSetterFactory());
- }
- u32 ShaderSource::getShader(const std::string &name,
- MaterialType material_type, NodeDrawType drawtype)
- {
- /*
- Get shader
- */
- if (std::this_thread::get_id() == m_main_thread) {
- return getShaderIdDirect(name, material_type, drawtype);
- }
- /*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/
- // We're gonna ask the result to be put into here
- static ResultQueue<std::string, u32, u8, u8> result_queue;
- // Throw a request in
- m_get_shader_queue.add(name, 0, 0, &result_queue);
- /* infostream<<"Waiting for shader from main thread, name=\""
- <<name<<"\""<<std::endl;*/
- while(true) {
- GetResult<std::string, u32, u8, u8>
- result = result_queue.pop_frontNoEx();
- if (result.key == name) {
- return result.item;
- }
- errorstream << "Got shader with invalid name: " << result.key << std::endl;
- }
- infostream << "getShader(): Failed" << std::endl;
- return 0;
- }
- /*
- This method generates all the shaders
- */
- u32 ShaderSource::getShaderIdDirect(const std::string &name,
- MaterialType material_type, NodeDrawType drawtype)
- {
- //infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
- // Empty name means shader 0
- if (name.empty()) {
- infostream<<"getShaderIdDirect(): name is empty"<<std::endl;
- return 0;
- }
- // Check if already have such instance
- for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
- ShaderInfo *info = &m_shaderinfo_cache[i];
- if(info->name == name && info->material_type == material_type &&
- info->drawtype == drawtype)
- return i;
- }
- /*
- Calling only allowed from main thread
- */
- if (std::this_thread::get_id() != m_main_thread) {
- errorstream<<"ShaderSource::getShaderIdDirect() "
- "called not from main thread"<<std::endl;
- return 0;
- }
- ShaderInfo info = generateShader(name, material_type, drawtype);
- /*
- Add shader to caches (add dummy shaders too)
- */
- MutexAutoLock lock(m_shaderinfo_cache_mutex);
- u32 id = m_shaderinfo_cache.size();
- m_shaderinfo_cache.push_back(info);
- infostream<<"getShaderIdDirect(): "
- <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;
- return id;
- }
- ShaderInfo ShaderSource::getShaderInfo(u32 id)
- {
- MutexAutoLock lock(m_shaderinfo_cache_mutex);
- if(id >= m_shaderinfo_cache.size())
- return ShaderInfo();
- return m_shaderinfo_cache[id];
- }
- void ShaderSource::processQueue()
- {
- }
- void ShaderSource::insertSourceShader(const std::string &name_of_shader,
- const std::string &filename, const std::string &program)
- {
- /*infostream<<"ShaderSource::insertSourceShader(): "
- "name_of_shader=\""<<name_of_shader<<"\", "
- "filename=\""<<filename<<"\""<<std::endl;*/
- sanity_check(std::this_thread::get_id() == m_main_thread);
- m_sourcecache.insert(name_of_shader, filename, program, true);
- }
- void ShaderSource::rebuildShaders()
- {
- MutexAutoLock lock(m_shaderinfo_cache_mutex);
- /*// Oh well... just clear everything, they'll load sometime.
- m_shaderinfo_cache.clear();
- m_name_to_id.clear();*/
- /*
- FIXME: Old shader materials can't be deleted in Irrlicht,
- or can they?
- (This would be nice to do in the destructor too)
- */
- // Recreate shaders
- for (ShaderInfo &i : m_shaderinfo_cache) {
- ShaderInfo *info = &i;
- if (!info->name.empty()) {
- *info = generateShader(info->name, info->material_type, info->drawtype);
- }
- }
- }
- ShaderInfo ShaderSource::generateShader(const std::string &name,
- MaterialType material_type, NodeDrawType drawtype)
- {
- ShaderInfo shaderinfo;
- shaderinfo.name = name;
- shaderinfo.material_type = material_type;
- shaderinfo.drawtype = drawtype;
- switch (material_type) {
- case TILE_MATERIAL_OPAQUE:
- case TILE_MATERIAL_LIQUID_OPAQUE:
- case TILE_MATERIAL_WAVING_LIQUID_OPAQUE:
- shaderinfo.base_material = video::EMT_SOLID;
- break;
- case TILE_MATERIAL_ALPHA:
- case TILE_MATERIAL_PLAIN_ALPHA:
- case TILE_MATERIAL_LIQUID_TRANSPARENT:
- case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
- shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
- break;
- case TILE_MATERIAL_BASIC:
- case TILE_MATERIAL_PLAIN:
- case TILE_MATERIAL_WAVING_LEAVES:
- case TILE_MATERIAL_WAVING_PLANTS:
- case TILE_MATERIAL_WAVING_LIQUID_BASIC:
- shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
- break;
- }
- shaderinfo.material = shaderinfo.base_material;
- bool enable_shaders = g_settings->getBool("enable_shaders");
- if (!enable_shaders)
- return shaderinfo;
- video::IVideoDriver *driver = RenderingEngine::get_video_driver();
- if (!driver->queryFeature(video::EVDF_ARB_GLSL)) {
- errorstream << "Shaders are enabled but GLSL is not supported by the driver\n";
- return shaderinfo;
- }
- video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
- // Create shaders header
- bool use_gles = false;
- #if ENABLE_GLES
- use_gles = driver->getDriverType() == video::EDT_OGLES2;
- #endif
- std::stringstream shaders_header;
- shaders_header
- << std::noboolalpha
- << std::showpoint // for GLSL ES
- ;
- std::string vertex_header, fragment_header, geometry_header;
- if (use_gles) {
- shaders_header << R"(
- #version 100
- )";
- vertex_header = R"(
- precision mediump float;
- uniform highp mat4 mWorldView;
- uniform highp mat4 mWorldViewProj;
- uniform mediump mat4 mTexture;
- uniform mediump mat3 mNormal;
- attribute highp vec4 inVertexPosition;
- attribute lowp vec4 inVertexColor;
- attribute mediump vec4 inTexCoord0;
- attribute mediump vec3 inVertexNormal;
- attribute mediump vec4 inVertexTangent;
- attribute mediump vec4 inVertexBinormal;
- )";
- fragment_header = R"(
- precision mediump float;
- )";
- } else {
- shaders_header << R"(
- #version 120
- #define lowp
- #define mediump
- #define highp
- )";
- vertex_header = R"(
- #define mWorldView gl_ModelViewMatrix
- #define mWorldViewProj gl_ModelViewProjectionMatrix
- #define mTexture (gl_TextureMatrix[0])
- #define mNormal gl_NormalMatrix
- #define inVertexPosition gl_Vertex
- #define inVertexColor gl_Color
- #define inTexCoord0 gl_MultiTexCoord0
- #define inVertexNormal gl_Normal
- #define inVertexTangent gl_MultiTexCoord1
- #define inVertexBinormal gl_MultiTexCoord2
- )";
- }
- // Since this is the first time we're using the GL bindings be extra careful.
- // This should be removed before 5.6.0 or similar.
- if (!GL.GetString) {
- errorstream << "OpenGL procedures were not loaded correctly, "
- "please open a bug report with details about your platform/OS." << std::endl;
- abort();
- }
- bool use_discard = use_gles;
- // For renderers that should use discard instead of GL_ALPHA_TEST
- const char *renderer = reinterpret_cast<const char*>(GL.GetString(GL.RENDERER));
- if (strstr(renderer, "GC7000"))
- use_discard = true;
- if (use_discard) {
- if (shaderinfo.base_material == video::EMT_TRANSPARENT_ALPHA_CHANNEL)
- shaders_header << "#define USE_DISCARD 1\n";
- else if (shaderinfo.base_material == video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF)
- shaders_header << "#define USE_DISCARD_REF 1\n";
- }
- #define PROVIDE(constant) shaders_header << "#define " #constant " " << (int)constant << "\n"
- PROVIDE(NDT_NORMAL);
- PROVIDE(NDT_AIRLIKE);
- PROVIDE(NDT_LIQUID);
- PROVIDE(NDT_FLOWINGLIQUID);
- PROVIDE(NDT_GLASSLIKE);
- PROVIDE(NDT_ALLFACES);
- PROVIDE(NDT_ALLFACES_OPTIONAL);
- PROVIDE(NDT_TORCHLIKE);
- PROVIDE(NDT_SIGNLIKE);
- PROVIDE(NDT_PLANTLIKE);
- PROVIDE(NDT_FENCELIKE);
- PROVIDE(NDT_RAILLIKE);
- PROVIDE(NDT_NODEBOX);
- PROVIDE(NDT_GLASSLIKE_FRAMED);
- PROVIDE(NDT_FIRELIKE);
- PROVIDE(NDT_GLASSLIKE_FRAMED_OPTIONAL);
- PROVIDE(NDT_PLANTLIKE_ROOTED);
- PROVIDE(TILE_MATERIAL_BASIC);
- PROVIDE(TILE_MATERIAL_ALPHA);
- PROVIDE(TILE_MATERIAL_LIQUID_TRANSPARENT);
- PROVIDE(TILE_MATERIAL_LIQUID_OPAQUE);
- PROVIDE(TILE_MATERIAL_WAVING_LEAVES);
- PROVIDE(TILE_MATERIAL_WAVING_PLANTS);
- PROVIDE(TILE_MATERIAL_OPAQUE);
- PROVIDE(TILE_MATERIAL_WAVING_LIQUID_BASIC);
- PROVIDE(TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT);
- PROVIDE(TILE_MATERIAL_WAVING_LIQUID_OPAQUE);
- PROVIDE(TILE_MATERIAL_PLAIN);
- PROVIDE(TILE_MATERIAL_PLAIN_ALPHA);
- #undef PROVIDE
- shaders_header << "#define MATERIAL_TYPE " << (int)material_type << "\n";
- shaders_header << "#define DRAW_TYPE " << (int)drawtype << "\n";
- bool enable_waving_water = g_settings->getBool("enable_waving_water");
- shaders_header << "#define ENABLE_WAVING_WATER " << enable_waving_water << "\n";
- if (enable_waving_water) {
- shaders_header << "#define WATER_WAVE_HEIGHT " << g_settings->getFloat("water_wave_height") << "\n";
- shaders_header << "#define WATER_WAVE_LENGTH " << g_settings->getFloat("water_wave_length") << "\n";
- shaders_header << "#define WATER_WAVE_SPEED " << g_settings->getFloat("water_wave_speed") << "\n";
- }
- shaders_header << "#define ENABLE_WAVING_LEAVES " << g_settings->getBool("enable_waving_leaves") << "\n";
- shaders_header << "#define ENABLE_WAVING_PLANTS " << g_settings->getBool("enable_waving_plants") << "\n";
- shaders_header << "#define ENABLE_TONE_MAPPING " << g_settings->getBool("tone_mapping") << "\n";
- shaders_header << "#define FOG_START " << core::clamp(g_settings->getFloat("fog_start"), 0.0f, 0.99f) << "\n";
- if (g_settings->getBool("enable_dynamic_shadows")) {
- shaders_header << "#define ENABLE_DYNAMIC_SHADOWS 1\n";
- if (g_settings->getBool("shadow_map_color"))
- shaders_header << "#define COLORED_SHADOWS 1\n";
- if (g_settings->getBool("shadow_poisson_filter"))
- shaders_header << "#define POISSON_FILTER 1\n";
- s32 shadow_filter = g_settings->getS32("shadow_filters");
- shaders_header << "#define SHADOW_FILTER " << shadow_filter << "\n";
- float shadow_soft_radius = g_settings->getFloat("shadow_soft_radius");
- if (shadow_soft_radius < 1.0f)
- shadow_soft_radius = 1.0f;
- shaders_header << "#define SOFTSHADOWRADIUS " << shadow_soft_radius << "\n";
- }
- shaders_header << "#line 0\n"; // reset the line counter for meaningful diagnostics
- std::string common_header = shaders_header.str();
- std::string vertex_shader = m_sourcecache.getOrLoad(name, "opengl_vertex.glsl");
- std::string fragment_shader = m_sourcecache.getOrLoad(name, "opengl_fragment.glsl");
- std::string geometry_shader = m_sourcecache.getOrLoad(name, "opengl_geometry.glsl");
- vertex_shader = common_header + vertex_header + vertex_shader;
- fragment_shader = common_header + fragment_header + fragment_shader;
- const char *geometry_shader_ptr = nullptr; // optional
- if (!geometry_shader.empty()) {
- geometry_shader = common_header + geometry_header + geometry_shader;
- geometry_shader_ptr = geometry_shader.c_str();
- }
- irr_ptr<ShaderCallback> cb{new ShaderCallback(m_setter_factories)};
- infostream<<"Compiling high level shaders for "<<name<<std::endl;
- s32 shadermat = gpu->addHighLevelShaderMaterial(
- vertex_shader.c_str(), nullptr, video::EVST_VS_1_1,
- fragment_shader.c_str(), nullptr, video::EPST_PS_1_1,
- geometry_shader_ptr, nullptr, video::EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLES, 0,
- cb.get(), shaderinfo.base_material, 1);
- if (shadermat == -1) {
- errorstream<<"generate_shader(): "
- "failed to generate \""<<name<<"\", "
- "addHighLevelShaderMaterial failed."
- <<std::endl;
- dumpShaderProgram(warningstream, "Vertex", vertex_shader);
- dumpShaderProgram(warningstream, "Fragment", fragment_shader);
- dumpShaderProgram(warningstream, "Geometry", geometry_shader);
- return shaderinfo;
- }
- // Apply the newly created material type
- shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
- return shaderinfo;
- }
- void dumpShaderProgram(std::ostream &output_stream,
- const std::string &program_type, const std::string &program)
- {
- output_stream << program_type << " shader program:" << std::endl <<
- "----------------------------------" << std::endl;
- size_t pos = 0;
- size_t prev = 0;
- s16 line = 1;
- while ((pos = program.find('\n', prev)) != std::string::npos) {
- output_stream << line++ << ": "<< program.substr(prev, pos - prev) <<
- std::endl;
- prev = pos + 1;
- }
- output_stream << line << ": " << program.substr(prev) << std::endl <<
- "End of " << program_type << " shader program." << std::endl <<
- " " << std::endl;
- }
|