]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/shader.cpp
Mapgen V6: Respect water_level setting
[dragonfireclient.git] / src / shader.cpp
index ba0b8600af3ff5fa9497e1d54f197b5dda2d2fdf..4bf10ce31f1c36cf7e58faf9b07d67fc5304ccb6 100644 (file)
@@ -1,19 +1,19 @@
 /*
-Minetest-c55
-Copyright (C) 2012 celeron55, Perttu Ahola <celeron55@gmail.com>
-Copyright (C) 2012 Kahrl <kahrl@gmx.net>
+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 General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+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 General Public License for more details.
+GNU Lesser General Public License for more details.
 
-You should have received a copy of the GNU General Public License along
+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.
 */
@@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "EShaderTypes.h"
 #include "log.h"
 #include "gamedef.h"
+#include "strfnd.h" // trim()
 
 /*
        A cache from shader name to shader path
@@ -124,10 +125,10 @@ class SourceShaderCache
                        const std::string &filename)
        {
                std::string combined = name_of_shader + DIR_DELIM + filename;
-               core::map<std::string, std::string>::Node *n;
+               std::map<std::string, std::string>::iterator n;
                n = m_programs.find(combined);
-               if(n)
-                       return n->getValue();
+               if(n != m_programs.end())
+                       return n->second;
                return "";
        }
        // Primarily fetches from cache, secondarily tries to read from filesystem
@@ -135,10 +136,10 @@ class SourceShaderCache
                        const std::string &filename)
        {
                std::string combined = name_of_shader + DIR_DELIM + filename;
-               core::map<std::string, std::string>::Node *n;
+               std::map<std::string, std::string>::iterator n;
                n = m_programs.find(combined);
-               if(n)
-                       return n->getValue();
+               if(n != m_programs.end())
+                       return n->second;
                std::string path = getShaderPath(name_of_shader, filename);
                if(path == ""){
                        infostream<<"SourceShaderCache::getOrLoad(): No path found for \""
@@ -155,7 +156,7 @@ class SourceShaderCache
                return "";
        }
 private:
-       core::map<std::string, std::string> m_programs;
+       std::map<std::string, std::string> m_programs;
        std::string readFile(const std::string &path)
        {
                std::ifstream is(path.c_str(), std::ios::binary);
@@ -171,10 +172,24 @@ class SourceShaderCache
        ShaderCallback: Sets constants that can be used in shaders
 */
 
+class IShaderConstantSetterRegistry
+{
+public:
+       virtual ~IShaderConstantSetterRegistry(){};
+       virtual void onSetConstants(video::IMaterialRendererServices *services,
+                       bool is_highlevel, const std::string &name) = 0;
+};
+
 class ShaderCallback : public video::IShaderConstantSetCallBack
 {
+       IShaderConstantSetterRegistry *m_scsr;
+       std::string m_name;
+
 public:
-       ShaderCallback(IrrlichtDevice *device): m_device(device) {}
+       ShaderCallback(IShaderConstantSetterRegistry *scsr, const std::string &name):
+               m_scsr(scsr),
+               m_name(name)
+       {}
        ~ShaderCallback() {}
 
        virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData)
@@ -184,6 +199,28 @@ class ShaderCallback : public video::IShaderConstantSetCallBack
 
                bool is_highlevel = userData;
 
+               m_scsr->onSetConstants(services, is_highlevel, m_name);
+       }
+};
+
+/*
+       MainShaderConstantSetter: Set basic constants required for almost everything
+*/
+
+class MainShaderConstantSetter : public IShaderConstantSetter
+{
+public:
+       MainShaderConstantSetter(IrrlichtDevice *device):
+               m_device(device)
+       {}
+       ~MainShaderConstantSetter() {}
+
+       virtual void onSetConstants(video::IMaterialRendererServices *services,
+                       bool is_highlevel)
+       {
+               video::IVideoDriver *driver = services->getVideoDriver();
+               assert(driver);
+
                // set inverted world matrix
                core::matrix4 invWorld = driver->getTransform(video::ETS_WORLD);
                invWorld.makeInverse();
@@ -219,7 +256,7 @@ class ShaderCallback : public video::IShaderConstantSetCallBack
        ShaderSource
 */
 
-class ShaderSource : public IWritableShaderSource
+class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterRegistry
 {
 public:
        ShaderSource(IrrlichtDevice *device);
@@ -272,6 +309,14 @@ class ShaderSource : public IWritableShaderSource
        // Shall be called from the main thread.
        void rebuildShaders();
 
+       void addGlobalConstantSetter(IShaderConstantSetter *setter)
+       {
+               m_global_setters.push_back(setter);
+       }
+
+       void onSetConstants(video::IMaterialRendererServices *services,
+                       bool is_highlevel, const std::string &name);
+
 private:
 
        // The id of the thread that is allowed to use irrlicht directly
@@ -287,14 +332,18 @@ class ShaderSource : public IWritableShaderSource
 
        // A shader id is index in this array.
        // The first position contains a dummy shader.
-       core::array<ShaderInfo> m_shaderinfo_cache;
+       std::vector<ShaderInfo> m_shaderinfo_cache;
        // Maps a shader name to an index in the former.
-       core::map<std::string, u32> m_name_to_id;
+       std::map<std::string, u32> m_name_to_id;
        // The two former containers are behind this mutex
        JMutex 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 setters
+       // TODO: Delete these in the destructor
+       std::vector<IShaderConstantSetter*> m_global_setters;
 };
 
 IWritableShaderSource* createShaderSource(IrrlichtDevice *device)
@@ -313,7 +362,7 @@ ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
        Load shader programs
 */
 void load_shaders(std::string name, SourceShaderCache *sourcecache,
-               video::E_DRIVER_TYPE drivertype, s32 enable_shaders,
+               video::E_DRIVER_TYPE drivertype, bool enable_shaders,
                std::string &vertex_program, std::string &pixel_program,
                std::string &geometry_program, bool &is_highlevel);
 
@@ -322,7 +371,7 @@ ShaderSource::ShaderSource(IrrlichtDevice *device):
 {
        assert(m_device);
 
-       m_shader_callback = new ShaderCallback(device);
+       m_shader_callback = new ShaderCallback(this, "default");
 
        m_shaderinfo_cache_mutex.Init();
 
@@ -331,11 +380,20 @@ ShaderSource::ShaderSource(IrrlichtDevice *device):
        // Add a dummy ShaderInfo as the first index, named ""
        m_shaderinfo_cache.push_back(ShaderInfo());
        m_name_to_id[""] = 0;
+
+       // Add main global constant setter
+       addGlobalConstantSetter(new MainShaderConstantSetter(device));
 }
 
 ShaderSource::~ShaderSource()
 {
        //m_shader_callback->drop();
+
+       for (std::vector<IShaderConstantSetter*>::iterator iter = m_global_setters.begin();
+                       iter != m_global_setters.end(); iter++) {
+               delete *iter;
+       }
+       m_global_setters.clear();
 }
 
 u32 ShaderSource::getShaderId(const std::string &name)
@@ -347,10 +405,10 @@ u32 ShaderSource::getShaderId(const std::string &name)
                        See if shader already exists
                */
                JMutexAutoLock lock(m_shaderinfo_cache_mutex);
-               core::map<std::string, u32>::Node *n;
+               std::map<std::string, u32>::iterator n;
                n = m_name_to_id.find(name);
-               if(n != NULL)
-                       return n->getValue();
+               if(n != m_name_to_id.end())
+                       return n->second;
        }
 
        /*
@@ -359,29 +417,31 @@ u32 ShaderSource::getShaderId(const std::string &name)
        if(get_current_thread_id() == m_main_thread){
                return getShaderIdDirect(name);
        } else {
-               infostream<<"getShaderId(): Queued: name=\""<<name<<"\""<<std::endl;
+               /*errorstream<<"getShaderId(): Queued: name=\""<<name<<"\""<<std::endl;*/
 
                // We're gonna ask the result to be put into here
-               ResultQueue<std::string, u32, u8, u8> result_queue;
+
+               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;
+               /* infostream<<"Waiting for shader from main thread, name=\""
+                               <<name<<"\""<<std::endl;*/
 
                try{
-                       // Wait result for a second
-                       GetResult<std::string, u32, u8, u8>
+                       while(true) {
+                               // Wait result for a second
+                               GetResult<std::string, u32, u8, u8>
                                        result = result_queue.pop_front(1000);
 
-                       // Check that at least something worked OK
-                       assert(result.key == name);
-
-                       return result.item;
+                               if (result.key == name) {
+                                       return result.item;
+                               }
+                       }
                }
                catch(ItemNotFoundException &e){
-                       infostream<<"Waiting for shader timed out."<<std::endl;
+                       errorstream<<"Waiting for shader " << name << " timed out."<<std::endl;
                        return 0;
                }
        }
@@ -419,12 +479,12 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name)
        {
                JMutexAutoLock lock(m_shaderinfo_cache_mutex);
 
-               core::map<std::string, u32>::Node *n;
+               std::map<std::string, u32>::iterator n;
                n = m_name_to_id.find(name);
-               if(n != NULL){
+               if(n != m_name_to_id.end()){
                        /*infostream<<"getShaderIdDirect(): \""<<name
                                        <<"\" found in cache"<<std::endl;*/
-                       return n->getValue();
+                       return n->second;
                }
        }
 
@@ -442,7 +502,7 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name)
 
        u32 id = m_shaderinfo_cache.size();
        m_shaderinfo_cache.push_back(info);
-       m_name_to_id.insert(name, id);
+       m_name_to_id[name] = id;
 
        /*infostream<<"getShaderIdDirect(): "
                        <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;*/
@@ -479,22 +539,16 @@ void ShaderSource::processQueue()
        /*
                Fetch shaders
        */
-       if(m_get_shader_queue.size() > 0){
+       if(!m_get_shader_queue.empty()){
                GetRequest<std::string, u32, u8, u8>
                                request = m_get_shader_queue.pop();
 
-               /*infostream<<"ShaderSource::processQueue(): "
+               /**errorstream<<"ShaderSource::processQueue(): "
                                <<"got shader request with "
                                <<"name=\""<<request.key<<"\""
-                               <<std::endl;*/
+                               <<std::endl;**/
 
-               GetResult<std::string, u32, u8, u8>
-                               result;
-               result.key = request.key;
-               result.callers = request.callers;
-               result.item = getShaderIdDirect(request.key);
-
-               request.dest->push_back(result);
+               m_get_shader_queue.pushResult(request,getShaderIdDirect(request.key));
        }
 }
 
@@ -527,11 +581,22 @@ void ShaderSource::rebuildShaders()
        // Recreate shaders
        for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
                ShaderInfo *info = &m_shaderinfo_cache[i];
-               *info = generate_shader(info->name, m_device,
-                               m_shader_callback, &m_sourcecache);
+               if(info->name != ""){
+                       *info = generate_shader(info->name, m_device,
+                                       m_shader_callback, &m_sourcecache);
+               }
        }
 }
+
+void ShaderSource::onSetConstants(video::IMaterialRendererServices *services,
+               bool is_highlevel, const std::string &name)
+{
+       for(u32 i=0; i<m_global_setters.size(); i++){
+               IShaderConstantSetter *setter = m_global_setters[i];
+               setter->onSetConstants(services, is_highlevel);
+       }
+}
+
 ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
                video::IShaderConstantSetCallBack *callback,
                SourceShaderCache *sourcecache)
@@ -546,7 +611,8 @@ ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
        /*
                Get the base material
        */
-       std::string base_material_name = sourcecache->getOrLoad(name, "base.txt");
+       std::string base_material_name =
+               trim(sourcecache->getOrLoad(name, "base.txt"));
        for(s32 i = 0; video::sBuiltInMaterialTypeNames[i] != 0; i++){
                if(video::sBuiltInMaterialTypeNames[i] == base_material_name){
                        shaderinfo.material = (video::E_MATERIAL_TYPE) i;
@@ -554,9 +620,8 @@ ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
                }
        }
 
-       // 0 = off, 1 = assembly shaders only, 2 = highlevel or assembly
-       s32 enable_shaders = g_settings->getS32("enable_shaders");
-       if(enable_shaders <= 0)
+       bool enable_shaders = g_settings->getBool("enable_shaders");
+       if(!enable_shaders)
                return shaderinfo;
 
        video::IVideoDriver* driver = device->getVideoDriver();
@@ -678,7 +743,7 @@ ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
 }
 
 void load_shaders(std::string name, SourceShaderCache *sourcecache,
-               video::E_DRIVER_TYPE drivertype, s32 enable_shaders,
+               video::E_DRIVER_TYPE drivertype, bool enable_shaders,
                std::string &vertex_program, std::string &pixel_program,
                std::string &geometry_program, bool &is_highlevel)
 {
@@ -687,7 +752,7 @@ void load_shaders(std::string name, SourceShaderCache *sourcecache,
        geometry_program = "";
        is_highlevel = false;
 
-       if(enable_shaders >= 2){
+       if(enable_shaders){
                // Look for high level shaders
                if(drivertype == video::EDT_DIRECT3D9){
                        // Direct3D 9: HLSL
@@ -708,24 +773,4 @@ void load_shaders(std::string name, SourceShaderCache *sourcecache,
                }
        }
 
-       if(enable_shaders >= 1){
-               // Look for assembly shaders
-               if(drivertype == video::EDT_DIRECT3D8){
-                       // Direct3D 8 assembly shaders
-                       vertex_program = sourcecache->getOrLoad(name, "d3d8_vertex.asm");
-                       pixel_program = sourcecache->getOrLoad(name, "d3d8_pixel.asm");
-               }
-               else if(drivertype == video::EDT_DIRECT3D9){
-                       // Direct3D 9 assembly shaders
-                       vertex_program = sourcecache->getOrLoad(name, "d3d9_vertex.asm");
-                       pixel_program = sourcecache->getOrLoad(name, "d3d9_pixel.asm");
-               }
-               else if(drivertype == video::EDT_OPENGL){
-                       // OpenGL assembly shaders
-                       vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.asm");
-                       pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.asm");
-               }
-               if(vertex_program != "" || pixel_program != "")
-                       return;
-       }
 }