Implement a global shader parameter passing system and useful shaders
authorPerttu Ahola <celeron55@gmail.com>
Sat, 1 Dec 2012 01:02:16 +0000 (03:02 +0200)
committerPerttu Ahola <celeron55@gmail.com>
Sat, 1 Dec 2012 22:46:18 +0000 (00:46 +0200)
15 files changed:
client/shaders/test_shader_1/base.txt [new file with mode: 0644]
client/shaders/test_shader_1/opengl_fragment.glsl [new file with mode: 0644]
client/shaders/test_shader_1/opengl_vertex.glsl [new file with mode: 0644]
client/shaders/test_shader_2/.opengl_fragment.glsl.swo [new file with mode: 0644]
client/shaders/test_shader_2/base.txt [new file with mode: 0644]
client/shaders/test_shader_2/opengl_fragment.glsl [new file with mode: 0644]
client/shaders/test_shader_2/opengl_vertex.glsl [new file with mode: 0644]
client/shaders/the_darkness_of_light/opengl_fragment.asm [deleted file]
client/shaders/the_darkness_of_light/opengl_fragment.glsl [deleted file]
client/shaders/the_darkness_of_light/opengl_vertex.asm [deleted file]
client/shaders/the_darkness_of_light/opengl_vertex.glsl [deleted file]
src/game.cpp
src/mapblock_mesh.cpp
src/shader.cpp
src/shader.h

diff --git a/client/shaders/test_shader_1/base.txt b/client/shaders/test_shader_1/base.txt
new file mode 100644 (file)
index 0000000..080df30
--- /dev/null
@@ -0,0 +1 @@
+trans_alphach_ref
diff --git a/client/shaders/test_shader_1/opengl_fragment.glsl b/client/shaders/test_shader_1/opengl_fragment.glsl
new file mode 100644 (file)
index 0000000..ebf943c
--- /dev/null
@@ -0,0 +1,25 @@
+\r
+uniform sampler2D myTexture;\r
+uniform vec4 skyBgColor;\r
+uniform float fogDistance;\r
+\r
+varying vec3 vPosition;\r
+\r
+void main (void)\r
+{\r
+    //vec4 col = vec4(1.0, 0.0, 0.0, 1.0);\r
+    vec4 col = texture2D(myTexture, vec2(gl_TexCoord[0]));\r
+       float a = col.a;\r
+    col *= gl_Color;\r
+       col = col * col; // SRGB -> Linear\r
+       col *= 1.8;\r
+       col.r = 1.0 - exp(1.0 - col.r) / exp(1.0);\r
+       col.g = 1.0 - exp(1.0 - col.g) / exp(1.0);\r
+       col.b = 1.0 - exp(1.0 - col.b) / exp(1.0);\r
+       col = sqrt(col); // Linear -> SRGB\r
+       if(fogDistance != 0.0){\r
+               float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));\r
+               col = mix(col, skyBgColor, d);\r
+       }\r
+    gl_FragColor = vec4(col.r, col.g, col.b, a);\r
+}\r
diff --git a/client/shaders/test_shader_1/opengl_vertex.glsl b/client/shaders/test_shader_1/opengl_vertex.glsl
new file mode 100644 (file)
index 0000000..4980850
--- /dev/null
@@ -0,0 +1,25 @@
+\r
+uniform mat4 mWorldViewProj;\r
+uniform mat4 mInvWorld;\r
+uniform mat4 mTransWorld;\r
+\r
+varying vec3 vPosition;\r
+\r
+void main(void)\r
+{\r
+       gl_Position = mWorldViewProj * gl_Vertex;\r
+\r
+       vPosition = (mWorldViewProj * gl_Vertex).xyz;\r
+\r
+       if(gl_Normal.y > 0.5)\r
+               gl_FrontColor = gl_BackColor = gl_Color;\r
+       else\r
+               gl_FrontColor = gl_BackColor = gl_Color * 0.7;\r
+\r
+       /*if(gl_Normal.y > 0.5)\r
+               gl_FrontColor = gl_BackColor = vec4(1.0, 1.0, 1.0, 1.0);\r
+       else\r
+               gl_FrontColor = gl_BackColor = vec4(1.0, 1.0, 1.0, 1.0) * 0.7;*/\r
+\r
+       gl_TexCoord[0] = gl_MultiTexCoord0;\r
+}\r
diff --git a/client/shaders/test_shader_2/.opengl_fragment.glsl.swo b/client/shaders/test_shader_2/.opengl_fragment.glsl.swo
new file mode 100644 (file)
index 0000000..e1cac62
Binary files /dev/null and b/client/shaders/test_shader_2/.opengl_fragment.glsl.swo differ
diff --git a/client/shaders/test_shader_2/base.txt b/client/shaders/test_shader_2/base.txt
new file mode 100644 (file)
index 0000000..1c26471
--- /dev/null
@@ -0,0 +1 @@
+trans_alphach
diff --git a/client/shaders/test_shader_2/opengl_fragment.glsl b/client/shaders/test_shader_2/opengl_fragment.glsl
new file mode 100644 (file)
index 0000000..38bc943
--- /dev/null
@@ -0,0 +1,23 @@
+\r
+uniform sampler2D myTexture;\r
+uniform float fogDistance;\r
+\r
+varying vec3 vPosition;\r
+\r
+void main (void)\r
+{\r
+    vec4 col = texture2D(myTexture, vec2(gl_TexCoord[0]));\r
+    col *= gl_Color;\r
+       float a = gl_Color.a;\r
+       col = col * col; // SRGB -> Linear\r
+       col *= 1.8;\r
+       col.r = 1.0 - exp(1.0 - col.r) / exp(1.0);\r
+       col.g = 1.0 - exp(1.0 - col.g) / exp(1.0);\r
+       col.b = 1.0 - exp(1.0 - col.b) / exp(1.0);\r
+       col = sqrt(col); // Linear -> SRGB\r
+       if(fogDistance != 0.0){\r
+               float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));\r
+               a = mix(a, 0.0, d);\r
+       }\r
+       gl_FragColor = vec4(col.r, col.g, col.b, a);\r
+}\r
diff --git a/client/shaders/test_shader_2/opengl_vertex.glsl b/client/shaders/test_shader_2/opengl_vertex.glsl
new file mode 100644 (file)
index 0000000..6286fc0
--- /dev/null
@@ -0,0 +1,20 @@
+\r
+uniform mat4 mWorldViewProj;\r
+uniform mat4 mInvWorld;\r
+uniform mat4 mTransWorld;\r
+\r
+varying vec3 vPosition;\r
+\r
+void main(void)\r
+{\r
+       vec4 pos = gl_Vertex;\r
+       pos.y -= 2.0;\r
+       gl_Position = mWorldViewProj * pos;\r
+\r
+       vPosition = (mWorldViewProj * gl_Vertex).xyz;\r
+\r
+       gl_FrontColor = gl_BackColor = gl_Color;\r
+       //gl_FrontColor = gl_BackColor = vec4(1.0, 1.0, 1.0, 1.0);\r
+\r
+       gl_TexCoord[0] = gl_MultiTexCoord0;\r
+}\r
diff --git a/client/shaders/the_darkness_of_light/opengl_fragment.asm b/client/shaders/the_darkness_of_light/opengl_fragment.asm
deleted file mode 100644 (file)
index 8297f8e..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-!!ARBfp1.0\r
-\r
-#Input\r
-ATTRIB inTexCoord = fragment.texcoord;      # texture coordinates\r
-ATTRIB inColor = fragment.color.primary; # interpolated diffuse color\r
-\r
-#Output\r
-OUTPUT outColor = result.color;\r
-\r
-TEMP texelColor;\r
-TXP texelColor, inTexCoord, texture, 2D; \r
-MUL texelColor, texelColor, inColor;  # multiply with color   \r
-SUB outColor, {1.0,1.0,1.0,1.0}, texelColor;\r
-MOV outColor.w, 1.0;\r
-\r
-END\r
-\r
diff --git a/client/shaders/the_darkness_of_light/opengl_fragment.glsl b/client/shaders/the_darkness_of_light/opengl_fragment.glsl
deleted file mode 100644 (file)
index e447918..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-\r
-uniform sampler2D myTexture;\r
-\r
-void main (void)\r
-{\r
-    vec4 col = texture2D(myTexture, vec2(gl_TexCoord[0]));\r
-    col *= gl_Color;\r
-    gl_FragColor = vec4(1.0-col.r, 1.0-col.g, 1.0-col.b, 1.0);\r
-}\r
diff --git a/client/shaders/the_darkness_of_light/opengl_vertex.asm b/client/shaders/the_darkness_of_light/opengl_vertex.asm
deleted file mode 100644 (file)
index adfee13..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-!!ARBvp1.0\r
-\r
-#input\r
-ATTRIB InPos = vertex.position;\r
-ATTRIB InColor = vertex.color;\r
-ATTRIB InNormal = vertex.normal;\r
-ATTRIB InTexCoord = vertex.texcoord;\r
-\r
-#output\r
-OUTPUT OutPos = result.position;\r
-OUTPUT OutColor = result.color;\r
-OUTPUT OutTexCoord = result.texcoord;\r
-\r
-PARAM MVP[4] = { state.matrix.mvp }; # modelViewProjection matrix.\r
-TEMP Temp;\r
-TEMP TempColor;\r
-TEMP TempCompare;\r
-\r
-#transform position to clip space \r
-DP4 Temp.x, MVP[0], InPos;\r
-DP4 Temp.y, MVP[1], InPos;\r
-DP4 Temp.z, MVP[2], InPos;\r
-DP4 Temp.w, MVP[3], InPos;\r
-\r
-# check if normal.y > 0.5\r
-SLT TempCompare, InNormal, {0.5,0.5,0.5,0.5};\r
-MUL TempCompare.z, TempCompare.y, 0.5;\r
-SUB TempCompare.x, 1.0, TempCompare.z;\r
-MOV TempCompare.y, TempCompare.x;\r
-MOV TempCompare.z, TempCompare.x;\r
-\r
-# calculate light color\r
-MUL OutColor, InColor, TempCompare;\r
-MOV OutColor.w, 1.0;          # we want alpha to be always 1\r
-MOV OutTexCoord, InTexCoord; # store texture coordinate\r
-MOV OutPos, Temp;\r
-\r
-END\r
diff --git a/client/shaders/the_darkness_of_light/opengl_vertex.glsl b/client/shaders/the_darkness_of_light/opengl_vertex.glsl
deleted file mode 100644 (file)
index 0182c85..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-\r
-uniform mat4 mWorldViewProj;\r
-uniform mat4 mInvWorld;\r
-uniform mat4 mTransWorld;\r
-\r
-void main(void)\r
-{\r
-       gl_Position = mWorldViewProj * gl_Vertex;\r
-       \r
-       if(gl_Normal.y > 0.5)\r
-               gl_FrontColor = gl_BackColor = gl_Color;\r
-       else\r
-               gl_FrontColor = gl_BackColor = gl_Color * 0.5;\r
-\r
-       gl_TexCoord[0] = gl_MultiTexCoord0;\r
-}\r
index 1339afbf0a7d594c461ef78d942ffbe50621c501..0c1a2137008bdcec0b3265ffe37a93db5219085c 100644 (file)
@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include <IGUIButton.h>
 #include <IGUIStaticText.h>
 #include <IGUIFont.h>
+#include <IMaterialRendererServices.h>
 #include "client.h"
 #include "server.h"
 #include "guiPauseMenu.h"
@@ -835,6 +836,49 @@ public:
        }
 };
 
+class GameGlobalShaderConstantSetter : public IShaderConstantSetter
+{
+       Sky *m_sky;
+       bool *m_force_fog_off;
+       f32 *m_fog_range;
+
+public:
+       GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off,
+                       f32 *fog_range):
+               m_sky(sky),
+               m_force_fog_off(force_fog_off),
+               m_fog_range(fog_range)
+       {}
+       ~GameGlobalShaderConstantSetter() {}
+
+       virtual void onSetConstants(video::IMaterialRendererServices *services,
+                       bool is_highlevel)
+       {
+               if(!is_highlevel)
+                       return;
+
+               // Background color
+               video::SColor bgcolor = m_sky->getBgColor();
+               video::SColorf bgcolorf(bgcolor);
+               float bgcolorfa[4] = {
+                       bgcolorf.r,
+                       bgcolorf.g,
+                       bgcolorf.b,
+                       bgcolorf.a,
+               };
+               services->setPixelShaderConstant("skyBgColor", bgcolorfa, 4);
+
+               // Fog distance
+               float fog_distance = *m_fog_range;
+               if(*m_force_fog_off)
+                       fog_distance = 10000*BS;
+               services->setPixelShaderConstant("fogDistance", &fog_distance, 1);
+       }
+
+private:
+       IrrlichtDevice *m_device;
+};
+
 void the_game(
        bool &kill,
        bool random_input,
@@ -1250,6 +1294,7 @@ void the_game(
        bool show_hud = true;
        bool show_chat = true;
        bool force_fog_off = false;
+       f32 fog_range = 100*BS;
        bool disable_camera_update = false;
        bool show_debug = g_settings->getBool("show_debug");
        bool show_profiler_graph = false;
@@ -1259,6 +1304,12 @@ void the_game(
        float time_of_day = 0;
        float time_of_day_smooth = 0;
 
+       /*
+               Shader constants
+       */
+       shsrc->addGlobalConstantSetter(
+                       new GameGlobalShaderConstantSetter(sky, &force_fog_off, &fog_range));
+
        /*
                Main loop
        */
@@ -2434,7 +2485,6 @@ void the_game(
                        Fog range
                */
        
-               f32 fog_range;
                if(farmesh)
                {
                        fog_range = BS*farmesh_range;
index cbc38ddb5114ada20836ab6612c8a64ba24a8973..c871b6dbe460c3fd0af4d5594f1099ab39204474 100644 (file)
@@ -1012,8 +1012,11 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
                Convert MeshCollector to SMesh
                Also store animation info
        */
-       video::E_MATERIAL_TYPE shadermat = m_gamedef->getShaderSource()->
-                       getShader("the_darkness_of_light").material;
+       bool enable_shaders = (g_settings->getS32("enable_shaders") > 0);
+       video::E_MATERIAL_TYPE shadermat1 = m_gamedef->getShaderSource()->
+                       getShader("test_shader_1").material;
+       video::E_MATERIAL_TYPE shadermat2 = m_gamedef->getShaderSource()->
+                       getShader("test_shader_2").material;
        for(u32 i = 0; i < collector.prebuffers.size(); i++)
        {
                PreMeshBuffer &p = collector.prebuffers[i];
@@ -1080,8 +1083,12 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
                material.setTexture(0, p.tile.texture.atlas);
                p.tile.applyMaterialOptions(material);
 
-               //if(material.MaterialType == video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF)
-                       material.MaterialType = shadermat;
+               if(enable_shaders){
+                       if(material.MaterialType == video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF)
+                               material.MaterialType = shadermat1;
+                       if(material.MaterialType == video::EMT_TRANSPARENT_VERTEX_ALPHA)
+                               material.MaterialType = shadermat2;
+               }
 
                // Create meshbuffer
 
index ba0b8600af3ff5fa9497e1d54f197b5dda2d2fdf..9e1a51f23cec789a167400e0a9e3d7da6ac7e389 100644 (file)
@@ -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
@@ -171,10 +172,24 @@ private:
        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 @@ public:
 
                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 @@ private:
        ShaderSource
 */
 
-class ShaderSource : public IWritableShaderSource
+class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterRegistry
 {
 public:
        ShaderSource(IrrlichtDevice *device);
@@ -272,6 +309,14 @@ public:
        // 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
@@ -295,6 +340,10 @@ private:
 
        // 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
+       core::array<IShaderConstantSetter*> m_global_setters;
 };
 
 IWritableShaderSource* createShaderSource(IrrlichtDevice *device)
@@ -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,6 +380,9 @@ 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()
@@ -531,6 +583,15 @@ void ShaderSource::rebuildShaders()
                                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,
@@ -546,7 +607,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;
index d6a425311e283fb1b60cba6ebe2226c171b600d0..774a17b204cc9e8e0d18d3aa917a547885502927 100644 (file)
@@ -51,6 +51,22 @@ struct ShaderInfo
        ShaderInfo(): name(""), material(video::EMT_SOLID) {}
 };
 
+/*
+       Setter of constants for shaders
+*/
+
+namespace irr { namespace video {
+       class IMaterialRendererServices;
+} }
+
+class IShaderConstantSetter
+{
+public:
+       virtual ~IShaderConstantSetter(){};
+       virtual void onSetConstants(video::IMaterialRendererServices *services,
+                       bool is_highlevel) = 0;
+};
+
 /*
        ShaderSource creates and caches shaders.
 */
@@ -82,6 +98,7 @@ public:
        virtual void insertSourceShader(const std::string &name_of_shader,
                const std::string &filename, const std::string &program)=0;
        virtual void rebuildShaders()=0;
+       virtual void addGlobalConstantSetter(IShaderConstantSetter *setter)=0;
 };
 
 IWritableShaderSource* createShaderSource(IrrlichtDevice *device);