]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/shader.cpp
fix infinite spawners
[dragonfireclient.git] / src / shader.cpp
index d29c9d3a707e9166bd2a2a0ee26b471b2ddb254e..ea2de3f1e85e4bfe4010bd5af646341d668bdf36 100644 (file)
@@ -18,15 +18,15 @@ 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 "debug.h"
-#include "main.h" // for g_settings
 #include "filesys.h"
 #include "util/container.h"
 #include "util/thread.h"
 #include "settings.h"
-#include <iterator>
 #include <ICameraSceneNode.h>
 #include <IGPUProgrammingServices.h>
 #include <IMaterialRenderer.h>
@@ -36,6 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "log.h"
 #include "gamedef.h"
 #include "strfnd.h" // trim()
+#include "client/tile.h"
 
 /*
        A cache from shader name to shader path
@@ -195,7 +196,7 @@ class ShaderCallback : public video::IShaderConstantSetCallBack
        virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData)
        {
                video::IVideoDriver *driver = services->getVideoDriver();
-               assert(driver);
+               sanity_check(driver != NULL);
 
                bool is_highlevel = userData;
 
@@ -210,8 +211,7 @@ class ShaderCallback : public video::IShaderConstantSetCallBack
 class MainShaderConstantSetter : public IShaderConstantSetter
 {
 public:
-       MainShaderConstantSetter(IrrlichtDevice *device):
-               m_device(device)
+       MainShaderConstantSetter(IrrlichtDevice *device)
        {}
        ~MainShaderConstantSetter() {}
 
@@ -219,7 +219,7 @@ class MainShaderConstantSetter : public IShaderConstantSetter
                        bool is_highlevel)
        {
                video::IVideoDriver *driver = services->getVideoDriver();
-               assert(driver);
+               sanity_check(driver);
 
                // set inverted world matrix
                core::matrix4 invWorld = driver->getTransform(video::ETS_WORLD);
@@ -240,16 +240,21 @@ class MainShaderConstantSetter : public IShaderConstantSetter
                        services->setVertexShaderConstant(worldViewProj.pointer(), 4, 4);
 
                // set transposed world matrix
+               core::matrix4 transWorld = driver->getTransform(video::ETS_WORLD);
+               transWorld = transWorld.getTransposed();
+               if(is_highlevel)
+                       services->setVertexShaderConstant("mTransWorld", transWorld.pointer(), 16);
+               else
+                       services->setVertexShaderConstant(transWorld.pointer(), 8, 4);
+
+               // set world matrix
                core::matrix4 world = driver->getTransform(video::ETS_WORLD);
-               world = world.getTransposed();
                if(is_highlevel)
-                       services->setVertexShaderConstant("mTransWorld", world.pointer(), 16);
+                       services->setVertexShaderConstant("mWorld", world.pointer(), 16);
                else
                        services->setVertexShaderConstant(world.pointer(), 8, 4);
-       }
 
-private:
-       IrrlichtDevice *m_device;
+       }
 };
 
 /*
@@ -262,13 +267,6 @@ class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterR
        ShaderSource(IrrlichtDevice *device);
        ~ShaderSource();
 
-       /*
-               Gets a shader material id from cache or
-               - if main thread, from getShaderIdDirect
-               - if other thread, adds to request queue and waits for main thread
-       */
-       u32 getShaderId(const std::string &name);
-
        /*
                - If shader material specified by name is found from cache,
                  return the cached id.
@@ -276,26 +274,23 @@ class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterR
 
                The id 0 points to a null shader. Its material is EMT_SOLID.
        */
-       u32 getShaderIdDirect(const std::string &name);
-
-       // Finds out the name of a cached shader.
-       std::string getShaderName(u32 id);
+       u32 getShaderIdDirect(const std::string &name, 
+               const u8 material_type, const u8 drawtype);
 
        /*
                If shader specified by the name pointed by the id doesn't
-               exist, create it, then return the cached shader.
+               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.
        */
-       ShaderInfo getShader(u32 id);
-
-       ShaderInfo getShader(const std::string &name)
-       {
-               return getShader(getShaderId(name));
-       }
-
+       
+       u32 getShader(const std::string &name,
+               const u8 material_type, const u8 drawtype);
+       
+       ShaderInfo getShaderInfo(u32 id);
+       
        // Processes queued shader requests from other threads.
        // Shall be called from the main thread.
        void processQueue();
@@ -333,9 +328,7 @@ class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterR
        // A shader id is index in this array.
        // The first position contains a dummy shader.
        std::vector<ShaderInfo> m_shaderinfo_cache;
-       // Maps a shader name to an index in the former.
-       std::map<std::string, u32> m_name_to_id;
-       // The two former containers are behind this mutex
+       // The former container is behind this mutex
        JMutex m_shaderinfo_cache_mutex;
 
        // Queued shader fetches (to be processed by the main thread)
@@ -354,7 +347,9 @@ IWritableShaderSource* createShaderSource(IrrlichtDevice *device)
 /*
        Generate shader given the shader name.
 */
-ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
+ShaderInfo generate_shader(std::string name,
+               u8 material_type, u8 drawtype,
+               IrrlichtDevice *device,
                video::IShaderConstantSetCallBack *callback,
                SourceShaderCache *sourcecache);
 
@@ -369,7 +364,7 @@ void load_shaders(std::string name, SourceShaderCache *sourcecache,
 ShaderSource::ShaderSource(IrrlichtDevice *device):
                m_device(device)
 {
-       assert(m_device);
+       assert(m_device); // Pre-condition
 
        m_shader_callback = new ShaderCallback(this, "default");
 
@@ -377,7 +372,6 @@ 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));
@@ -385,37 +379,29 @@ ShaderSource::ShaderSource(IrrlichtDevice *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)
-{
-       //infostream<<"getShaderId(): \""<<name<<"\""<<std::endl;
 
-       {
-               /*
-                       See if shader already exists
-               */
-               JMutexAutoLock lock(m_shaderinfo_cache_mutex);
-               std::map<std::string, u32>::iterator n;
-               n = m_name_to_id.find(name);
-               if(n != m_name_to_id.end())
-                       return n->second;
+       if (m_shader_callback) {
+               m_shader_callback->drop();
+               m_shader_callback = NULL;
        }
+}
 
+u32 ShaderSource::getShader(const std::string &name, 
+               const u8 material_type, const u8 drawtype)
+{
        /*
                Get shader
        */
+
        if(get_current_thread_id() == m_main_thread){
-               return getShaderIdDirect(name);
+               return getShaderIdDirect(name, material_type, drawtype);
        } else {
-               /*errorstream<<"getShaderId(): Queued: name=\""<<name<<"\""<<std::endl;*/
+               /*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/
 
                // We're gonna ask the result to be put into here
 
@@ -441,7 +427,7 @@ u32 ShaderSource::getShaderId(const std::string &name)
 
        }
 
-       infostream<<"getShaderId(): Failed"<<std::endl;
+       infostream<<"getShader(): Failed"<<std::endl;
 
        return 0;
 }
@@ -449,7 +435,8 @@ u32 ShaderSource::getShaderId(const std::string &name)
 /*
        This method generates all the shaders
 */
-u32 ShaderSource::getShaderIdDirect(const std::string &name)
+u32 ShaderSource::getShaderIdDirect(const std::string &name, 
+               const u8 material_type, const u8 drawtype)
 {
        //infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
 
@@ -459,6 +446,14 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name)
                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
        */
@@ -468,25 +463,7 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name)
                return 0;
        }
 
-       /*
-               See if shader already exists
-       */
-       {
-               JMutexAutoLock lock(m_shaderinfo_cache_mutex);
-
-               std::map<std::string, u32>::iterator n;
-               n = m_name_to_id.find(name);
-               if(n != m_name_to_id.end()){
-                       /*infostream<<"getShaderIdDirect(): \""<<name
-                                       <<"\" found in cache"<<std::endl;*/
-                       return n->second;
-               }
-       }
-
-       /*infostream<<"getShaderIdDirect(): \""<<name
-                       <<"\" NOT found in cache. Creating it."<<std::endl;*/
-
-       ShaderInfo info = generate_shader(name, m_device,
+       ShaderInfo info = generate_shader(name, material_type, drawtype, m_device,
                        m_shader_callback, &m_sourcecache);
 
        /*
@@ -497,29 +474,15 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name)
 
        u32 id = m_shaderinfo_cache.size();
        m_shaderinfo_cache.push_back(info);
-       m_name_to_id[name] = id;
 
-       /*infostream<<"getShaderIdDirect(): "
-                       <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;*/
+       infostream<<"getShaderIdDirect(): "
+                       <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;
 
        return id;
 }
 
-std::string ShaderSource::getShaderName(u32 id)
-{
-       JMutexAutoLock lock(m_shaderinfo_cache_mutex);
-
-       if(id >= m_shaderinfo_cache.size()){
-               errorstream<<"ShaderSource::getShaderName(): id="<<id
-                               <<" >= m_shaderinfo_cache.size()="
-                               <<m_shaderinfo_cache.size()<<std::endl;
-               return "";
-       }
-
-       return m_shaderinfo_cache[id].name;
-}
 
-ShaderInfo ShaderSource::getShader(u32 id)
+ShaderInfo ShaderSource::getShaderInfo(u32 id)
 {
        JMutexAutoLock lock(m_shaderinfo_cache_mutex);
 
@@ -531,21 +494,8 @@ ShaderInfo ShaderSource::getShader(u32 id)
 
 void ShaderSource::processQueue()
 {
-       /*
-               Fetch shaders
-       */
-       //NOTE this is only thread safe for ONE consumer thread!
-       if(!m_get_shader_queue.empty()){
-               GetRequest<std::string, u32, u8, u8>
-                               request = m_get_shader_queue.pop();
-
-               /**errorstream<<"ShaderSource::processQueue(): "
-                               <<"got shader request with "
-                               <<"name=\""<<request.key<<"\""
-                               <<std::endl;**/
 
-               m_get_shader_queue.pushResult(request,getShaderIdDirect(request.key));
-       }
 }
 
 void ShaderSource::insertSourceShader(const std::string &name_of_shader,
@@ -555,7 +505,7 @@ void ShaderSource::insertSourceShader(const std::string &name_of_shader,
                        "name_of_shader=\""<<name_of_shader<<"\", "
                        "filename=\""<<filename<<"\""<<std::endl;*/
 
-       assert(get_current_thread_id() == m_main_thread);
+       sanity_check(get_current_thread_id() == m_main_thread);
 
        m_sourcecache.insert(name_of_shader, filename, program, true);
 }
@@ -578,8 +528,8 @@ void ShaderSource::rebuildShaders()
        for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
                ShaderInfo *info = &m_shaderinfo_cache[i];
                if(info->name != ""){
-                       *info = generate_shader(info->name, m_device,
-                                       m_shader_callback, &m_sourcecache);
+                       *info = generate_shader(info->name, info->material_type,
+                                       info->drawtype, m_device, m_shader_callback, &m_sourcecache);
                }
        }
 }
@@ -593,35 +543,42 @@ void ShaderSource::onSetConstants(video::IMaterialRendererServices *services,
        }
 }
 
-ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
-               video::IShaderConstantSetCallBack *callback,
+ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
+               IrrlichtDevice *device, video::IShaderConstantSetCallBack *callback,
                SourceShaderCache *sourcecache)
 {
-       /*infostream<<"generate_shader(): "
-                       "\""<<name<<"\""<<std::endl;*/
-
        ShaderInfo shaderinfo;
        shaderinfo.name = name;
+       shaderinfo.material_type = material_type;
+       shaderinfo.drawtype = drawtype;
        shaderinfo.material = video::EMT_SOLID;
-
-       /*
-               Get the base material
-       */
-       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;
+       switch(material_type){
+               case TILE_MATERIAL_BASIC:
+                       shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
                        break;
-               }
+               case TILE_MATERIAL_ALPHA:
+                       shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+                       break;
+               case TILE_MATERIAL_LIQUID_TRANSPARENT:
+                       shaderinfo.base_material = video::EMT_TRANSPARENT_VERTEX_ALPHA;
+                       break;
+               case TILE_MATERIAL_LIQUID_OPAQUE:
+                       shaderinfo.base_material = video::EMT_SOLID;
+                       break;
+               case TILE_MATERIAL_WAVING_LEAVES:
+                       shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
+                       break;
+               case TILE_MATERIAL_WAVING_PLANTS:
+                       shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
+               break;
        }
-
+       
        bool enable_shaders = g_settings->getBool("enable_shaders");
        if(!enable_shaders)
                return shaderinfo;
 
        video::IVideoDriver* driver = device->getVideoDriver();
-       assert(driver);
+       sanity_check(driver);
 
        video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
        if(!gpu){
@@ -641,7 +598,6 @@ ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
        load_shaders(name, sourcecache, driver->getDriverType(),
                        enable_shaders, vertex_program, pixel_program,
                        geometry_program, is_highlevel);
-
        // Check hardware/driver support
        if(vertex_program != "" &&
                        !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
@@ -673,7 +629,84 @@ ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
 
        // Create shaders header
        std::string shaders_header = "#version 120\n";
+
+       static const char* drawTypes[] = {
+               "NDT_NORMAL",
+               "NDT_AIRLIKE",
+               "NDT_LIQUID",
+               "NDT_FLOWINGLIQUID",
+               "NDT_GLASSLIKE",
+               "NDT_ALLFACES",
+               "NDT_ALLFACES_OPTIONAL",
+               "NDT_TORCHLIKE",
+               "NDT_SIGNLIKE",
+               "NDT_PLANTLIKE",
+               "NDT_FENCELIKE",
+               "NDT_RAILLIKE",
+               "NDT_NODEBOX",
+               "NDT_GLASSLIKE_FRAMED",
+               "NDT_FIRELIKE",
+               "NDT_GLASSLIKE_FRAMED_OPTIONAL"
+       };
        
+       for (int i = 0; i < 14; i++){
+               shaders_header += "#define ";
+               shaders_header += drawTypes[i];
+               shaders_header += " ";
+               shaders_header += itos(i);
+               shaders_header += "\n";
+       }
+
+       static const char* materialTypes[] = {
+               "TILE_MATERIAL_BASIC",
+               "TILE_MATERIAL_ALPHA",
+               "TILE_MATERIAL_LIQUID_TRANSPARENT",
+               "TILE_MATERIAL_LIQUID_OPAQUE",
+               "TILE_MATERIAL_WAVING_LEAVES",
+               "TILE_MATERIAL_WAVING_PLANTS"
+       };
+
+       for (int i = 0; i < 6; i++){
+               shaders_header += "#define ";
+               shaders_header += materialTypes[i];
+               shaders_header += " ";
+               shaders_header += itos(i);
+               shaders_header += "\n";
+       }
+
+       shaders_header += "#define MATERIAL_TYPE ";
+       shaders_header += itos(material_type);
+       shaders_header += "\n";
+       shaders_header += "#define DRAW_TYPE ";
+       shaders_header += itos(drawtype);
+       shaders_header += "\n";
+
+       if (g_settings->getBool("generate_normalmaps")){
+               shaders_header += "#define GENERATE_NORMALMAPS\n";
+               shaders_header += "#define NORMALMAPS_STRENGTH ";
+               shaders_header += ftos(g_settings->getFloat("normalmaps_strength"));
+               shaders_header += "\n";
+               float sample_step;
+               int smooth = (int)g_settings->getFloat("normalmaps_smooth");
+               switch (smooth){
+               case 0:
+                       sample_step = 0.0078125; // 1.0 / 128.0
+                       break;
+               case 1:
+                       sample_step = 0.00390625; // 1.0 / 256.0
+                       break;
+               case 2:
+                       sample_step = 0.001953125; // 1.0 / 512.0
+                       break;
+               default:
+                       sample_step = 0.0078125;
+                       break;
+               }
+               shaders_header += "#define SAMPLE_STEP ";
+               shaders_header += ftos(sample_step);
+               shaders_header += "\n";
+       }
+
        if (g_settings->getBool("enable_bumpmapping"))
                shaders_header += "#define ENABLE_BUMPMAPPING\n";
 
@@ -685,13 +718,13 @@ ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
                shaders_header += "#define PARALLAX_OCCLUSION_BIAS ";
                shaders_header += ftos(g_settings->getFloat("parallax_occlusion_bias"));
                shaders_header += "\n";
-               }
+       }
 
        if (g_settings->getBool("enable_bumpmapping") || g_settings->getBool("enable_parallax_occlusion"))
                shaders_header += "#define USE_NORMALMAPS\n";
 
        if (g_settings->getBool("enable_waving_water")){
-               shaders_header += "#define ENABLE_WAVING_WATER\n";
+               shaders_header += "#define ENABLE_WAVING_WATER 1\n";
                shaders_header += "#define WATER_WAVE_HEIGHT ";
                shaders_header += ftos(g_settings->getFloat("water_wave_height"));
                shaders_header += "\n";
@@ -701,13 +734,21 @@ ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
                shaders_header += "#define WATER_WAVE_SPEED ";
                shaders_header += ftos(g_settings->getFloat("water_wave_speed"));
                shaders_header += "\n";
+       } else{
+               shaders_header += "#define ENABLE_WAVING_WATER 0\n";
        }
 
+       shaders_header += "#define ENABLE_WAVING_LEAVES ";
        if (g_settings->getBool("enable_waving_leaves"))
-               shaders_header += "#define ENABLE_WAVING_LEAVES\n";
+               shaders_header += "1\n";
+       else    
+               shaders_header += "0\n";
 
+       shaders_header += "#define ENABLE_WAVING_PLANTS ";              
        if (g_settings->getBool("enable_waving_plants"))
-               shaders_header += "#define ENABLE_WAVING_PLANTS\n";
+               shaders_header += "1\n";
+       else
+               shaders_header += "0\n";
 
        if(pixel_program != "")
                pixel_program = shaders_header + pixel_program;
@@ -742,11 +783,10 @@ ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
                        scene::EPT_TRIANGLES,      // Geometry shader input
                        scene::EPT_TRIANGLE_STRIP, // Geometry shader output
                        0,                         // Support maximum number of vertices
-                       callback,             // Set-constant callback
-                       shaderinfo.material,  // Base material
-                       1                     // Userdata passed to callback
+                       callback,                  // Set-constant callback
+                       shaderinfo.base_material,  // Base material
+                       1                          // Userdata passed to callback
                        );
-
                if(shadermat == -1){
                        errorstream<<"generate_shader(): "
                                        "failed to generate \""<<name<<"\", "
@@ -761,7 +801,7 @@ ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
                        vertex_program_ptr,   // Vertex shader program
                        pixel_program_ptr,    // Pixel shader program
                        callback,             // Set-constant callback
-                       shaderinfo.material,  // Base material
+                       shaderinfo.base_material,  // Base material
                        0                     // Userdata passed to callback
                        );