Redesign depth and stencil test and blend state management
authorMikko Rasa <tdb@tdb.fi>
Wed, 18 Aug 2021 14:33:59 +0000 (17:33 +0300)
committerMikko Rasa <tdb@tdb.fi>
Wed, 18 Aug 2021 15:27:55 +0000 (18:27 +0300)
25 files changed:
blender/io_mspgl/export_scene.py
demos/desertpillars/data/exported/Desert.seq
demos/desertpillars/source/desertpillars.cpp
source/builders/sequencebuilder.cpp
source/builders/sequencetemplate.cpp
source/builders/sequencetemplate.h
source/core/blend.cpp
source/core/blend.h
source/core/depthtest.cpp [new file with mode: 0644]
source/core/depthtest.h [new file with mode: 0644]
source/core/pipelinestate.cpp
source/core/pipelinestate.h
source/core/stencil.cpp [deleted file]
source/core/stencil.h [deleted file]
source/core/stenciltest.cpp [new file with mode: 0644]
source/core/stenciltest.h [new file with mode: 0644]
source/core/tests.cpp
source/core/tests.h
source/effects/shadowmap.cpp
source/effects/shadowmap.h
source/render/renderer.cpp
source/render/renderer.h
source/render/sequence.cpp
source/render/sequence.h
tools/viewer.cpp

index 3f0509ab6d7ec18007a3b8f4b5edb9213efe3f86..7bb32efeeb927ab6c083d0bc387d7ccbf885e358 100644 (file)
@@ -108,7 +108,7 @@ class SceneExporter:
                        resources[lighting_name] = lighting_res
 
        def export_sequence(self, scene, resources):
-               from .datafile import Resource, Statement
+               from .datafile import Resource, Statement, Token
                seq_res = Resource(scene.name+".seq", "sequence")
 
                if scene.use_hdr:
@@ -119,7 +119,7 @@ class SceneExporter:
                        content = resources[scene.name+".wrapper.scene"]
 
                ss = Statement("pass", "", "content")
-               ss.sub.append(Statement("depth_test", "lequal"))
+               ss.sub.append(Statement("depth_test", Token("LEQUAL")))
                ss.sub.append(seq_res.create_reference_statement("lighting", resources[scene.name+".lightn"]))
                ss.sub.append(seq_res.create_reference_statement("scene", content))
                seq_res.statements.append(ss)
index 347f662dd7b126a4c5f12963b377b678a7d436fa..8000033c9fbeba789855caa362b29ebd578c0111 100644 (file)
@@ -1,7 +1,7 @@
 hdr true;
 pass "" "content"
 {
-       depth_test "lequal";
+       depth_test LEQUAL;
        lighting "Desert.lightn";
        scene "Desert.wrapper.scene";
 };
index 124df81cfb14e4cb41271c98ee9df943919bf7bd..dee2c490148c2ea2ad95325785e1be05137edb88 100644 (file)
@@ -42,7 +42,7 @@ DesertPillars::DesertPillars(int, char **):
        shadow_seq = make_unique<GL::Sequence>(shadow_size, shadow_size);
        shadow_seq->set_debug_name("Shadow sequence");
        GL::Sequence::Step *step = &shadow_seq->add_step("shadow", content);
-       step->set_depth_test(&GL::DepthTest::lequal());
+       step->set_depth_test(GL::LEQUAL);
 
        shadow_map = make_unique<GL::ShadowMap>(shadow_size, *sky, sun, *shadow_seq);
        shadow_map->set_debug_name("Shadow map");
@@ -58,7 +58,7 @@ DesertPillars::DesertPillars(int, char **):
        env_seq->set_debug_name("Environment sequence");
        step = &env_seq->add_step("", *shadow_map);
        step->set_lighting(&resources.get<GL::Lighting>("Desert.lightn"));
-       step->set_depth_test(&GL::DepthTest::lequal());
+       step->set_depth_test(GL::LEQUAL);
 
        env_map = make_unique<GL::EnvironmentMap>(256, GL::RGB16F, 7, sphere, *env_seq);
        env_map->set_debug_name("Environment map");
index 9bb8f1dcd6b05def0558b6f81cfa7767dd5061e7..12e7bdf3df96ea43c415e3674c5ffdf19d7cf764 100644 (file)
@@ -67,8 +67,9 @@ void SequenceBuilder::build(Sequence &sequence) const
                        continue;
 
                Sequence::Step &step = sequence.add_step(i->tag, *renderable);
-               step.set_blend(i->blend.get());
-               step.set_depth_test(i->depth_test.get());
+               step.set_blend(i->blend);
+               step.set_depth_test(i->depth_test);
+               step.set_stencil_test(i->stencil_test);
                step.set_lighting(i->lighting);
        }
 
index 3ad973139010ae60b6e5cc5d602a9a0e1aca8aef..18a328e1b270775a77b2686a7471addcf3faa64a 100644 (file)
@@ -140,13 +140,14 @@ SequenceTemplate::Step::Loader::Loader(Step &p, Collection &c):
 void SequenceTemplate::Step::Loader::init()
 {
        add("blend", &Loader::blend);
-       add("blend", &Loader::blend_predefined);
+       add("blend", &Loader::blend_factors);
        add("depth_test", &Loader::depth_test);
-       add("depth_test", &Loader::depth_test_predefined);
+       add("depth_test", &Loader::depth_compare);
        add("lighting", &Loader::lighting);
        add("lighting", &Loader::lighting_inline);
        add("object", &Loader::object);
        add("scene", &Loader::scene);
+       add("stencil_test", &Loader::stencil_test);
 }
 
 void SequenceTemplate::Step::Loader::set_inline_base_name(const string &n)
@@ -154,42 +155,24 @@ void SequenceTemplate::Step::Loader::set_inline_base_name(const string &n)
        inline_base_name = n;
 }
 
-void SequenceTemplate::Step::Loader::blend_predefined(const string &name)
+void SequenceTemplate::Step::Loader::blend()
 {
-       const Blend *bln = 0;
-       if(name=="alpha")
-               bln = &Blend::alpha();
-       else if(name=="additive")
-               bln = &Blend::additive();
-       else if(name=="additive_alpha")
-               bln = &Blend::additive_alpha();
-       else
-               throw key_error(name);
-
-       obj.blend = bln;
-       obj.blend.keep();
+       load_sub(obj.blend);
 }
 
-void SequenceTemplate::Step::Loader::blend(BlendFactor src, BlendFactor dest)
+void SequenceTemplate::Step::Loader::blend_factors(BlendFactor src, BlendFactor dest)
 {
-       obj.blend = new Blend(src, dest);
+       obj.blend = Blend(src, dest);
 }
 
-void SequenceTemplate::Step::Loader::depth_test_predefined(const string &name)
+void SequenceTemplate::Step::Loader::depth_test()
 {
-       const DepthTest *dtest = 0;
-       if(name=="lequal")
-               dtest = &DepthTest::lequal();
-       else
-               throw key_error(name);
-
-       obj.depth_test = dtest;
-       obj.depth_test.keep();
+       load_sub(obj.depth_test);
 }
 
-void SequenceTemplate::Step::Loader::depth_test(Predicate pred)
+void SequenceTemplate::Step::Loader::depth_compare(Predicate c)
 {
-       obj.depth_test = new DepthTest(pred);
+       obj.depth_test = DepthTest(c);
 }
 
 void SequenceTemplate::Step::Loader::lighting_inline()
@@ -215,5 +198,10 @@ void SequenceTemplate::Step::Loader::scene(const string &name)
        obj.default_renderable = &get_collection().get<Scene>(name);
 }
 
+void SequenceTemplate::Step::Loader::stencil_test()
+{
+       load_sub(obj.stencil_test);
+}
+
 } // namespace GL
 } // namespace Msp
index 32736d8ee7645e255255d9275abb6156db354b1a..061fdfc39928f1b4ce8e2634ffe3e1d933ec1086 100644 (file)
@@ -6,13 +6,14 @@
 #include <msp/core/typeregistry.h>
 #include <msp/datafile/objectloader.h>
 #include "blend.h"
+#include "depthtest.h"
 #include "postprocessor.h"
 #include "predicate.h"
+#include "stenciltest.h"
 
 namespace Msp {
 namespace GL {
 
-class DepthTest;
 class Lighting;
 class Renderable;
 
@@ -77,20 +78,22 @@ public:
                        void set_inline_base_name(const std::string &);
 
                private:
-                       void blend(BlendFactor, BlendFactor);
-                       void blend_predefined(const std::string &);
-                       void depth_test(Predicate);
-                       void depth_test_predefined(const std::string &);
+                       void blend();
+                       void blend_factors(BlendFactor, BlendFactor);
+                       void depth_test();
+                       void depth_compare(Predicate);
                        void lighting(const std::string &);
                        void lighting_inline();
                        void object(const std::string &);
                        void scene(const std::string &);
+                       void stencil_test();
                };
 
                std::string tag;
                const Lighting *lighting;
-               RefPtr<const DepthTest> depth_test;
-               RefPtr<const Blend> blend;
+               DepthTest depth_test;
+               StencilTest stencil_test;
+               Blend blend;
                std::string slot_name;
                Renderable *default_renderable;
 
index 3327885c74c1ef34b7a5c1d111f22935a8639de0..a5e8f44d2917ffc8c7fc2e48cb784b28b3ec01fd 100644 (file)
@@ -9,61 +9,120 @@ namespace Msp {
 namespace GL {
 
 Blend::Blend():
-       eq(ADD),
+       enabled(false),
+       equation(ADD),
        src_factor(ONE),
-       dst_factor(ZERO)
+       dst_factor(ZERO),
+       constant(0.0f, 0.0f, 0.0f, 0.0f)
 { }
 
 Blend::Blend(BlendFactor sf, BlendFactor df):
-       eq(ADD),
+       enabled(true),
+       equation(ADD),
        src_factor(sf),
-       dst_factor(df)
+       dst_factor(df),
+       constant(0.0f, 0.0f, 0.0f, 0.0f)
 { }
 
 Blend::Blend(BlendEquation e, BlendFactor sf, BlendFactor df):
-       eq(e),
+       enabled(true),
+       equation(e),
        src_factor(sf),
-       dst_factor(df)
+       dst_factor(df),
+       constant(0.0f, 0.0f, 0.0f, 0.0f)
+{ }
+
+
+Blend::Loader::Loader(Blend &b):
+       ObjectLoader<Blend>(b)
 {
-       if(eq==MIN || eq==MAX)
-               static Require _req(EXT_blend_minmax);
-       else if(eq==SUBTRACT || eq==REVERSE_SUBTRACT)
-               static Require _req(EXT_blend_subtract);
+       add("equation", &Loader::equation);
+       add("factors", &Loader::factors);
+       add("constant", &Loader::constant);
 }
 
-void Blend::bind() const
+void Blend::Loader::constant(float r, float g, float b, float a)
 {
-       if(set_current(this))
-       {
-               glEnable(GL_BLEND);
-               if(EXT_blend_minmax)
-                       glBlendEquation(eq);
-               glBlendFunc(src_factor, dst_factor);
-       }
+       obj.constant = Color(r, g, b, a);
 }
 
-void Blend::unbind()
+void Blend::Loader::equation(BlendEquation eq)
 {
-       if(set_current(0))
-               glDisable(GL_BLEND);
+       obj.enabled = true;
+       obj.equation = eq;
 }
 
-const Blend &Blend::alpha()
+void Blend::Loader::factors(BlendFactor sf, BlendFactor df)
 {
-       static Blend blend(SRC_ALPHA, ONE_MINUS_SRC_ALPHA);
-       return blend;
+       obj.enabled = true;
+       obj.src_factor = sf;
+       obj.dst_factor = df;
 }
 
-const Blend &Blend::additive()
+
+GLenum get_gl_blend_equation(BlendEquation eq)
 {
-       static Blend blend(ONE, ONE);
-       return blend;
+       switch(eq)
+       {
+       case ADD: return GL_FUNC_ADD;
+       case SUBTRACT: return GL_FUNC_SUBTRACT;
+       case REVERSE_SUBTRACT: return GL_FUNC_REVERSE_SUBTRACT;
+       case MIN: return GL_MIN;
+       case MAX: return GL_MAX;
+       default: throw invalid_argument("get_gl_blend_equation");
+       }
 }
 
-const Blend &Blend::additive_alpha()
+GLenum get_gl_blend_factor(BlendFactor factor)
 {
-       static Blend blend(SRC_ALPHA, ONE);
-       return blend;
+       switch(factor)
+       {
+       case ZERO: return GL_ZERO;
+       case ONE: return GL_ONE;
+       case SRC_COLOR: return GL_SRC_COLOR;
+       case ONE_MINUS_SRC_COLOR: return GL_ONE_MINUS_SRC_COLOR;
+       case SRC_ALPHA: return GL_SRC_ALPHA;
+       case ONE_MINUS_SRC_ALPHA: return GL_ONE_MINUS_SRC_ALPHA;
+       case DST_COLOR: return GL_DST_COLOR;
+       case ONE_MINUS_DST_COLOR: return GL_ONE_MINUS_DST_COLOR;
+       case DST_ALPHA: return GL_DST_ALPHA;
+       case ONE_MINUS_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA;
+       case CONSTANT_COLOR: return GL_CONSTANT_COLOR;
+       case ONE_MINUS_CONSTANT_COLOR: return GL_ONE_MINUS_CONSTANT_COLOR;
+       case CONSTANT_ALPHA: return GL_CONSTANT_ALPHA;
+       case ONE_MINUS_CONSTANT_ALPHA: return GL_ONE_MINUS_CONSTANT_ALPHA;
+       default: throw invalid_argument("get_gl_blend_factor");
+       }
+}
+
+void operator>>(const LexicalConverter &conv, BlendEquation &eq)
+{
+       const string &str = conv.get();
+       if(str=="ADD")
+               eq = ADD;
+       else if(str=="SUBTRACT")
+               eq = SUBTRACT;
+       else if(str=="REVERSE_SUBTRACT")
+               eq = REVERSE_SUBTRACT;
+       else if(str=="MIN")
+               eq = MIN;
+       else if(str=="MAX")
+               eq = MAX;
+       else
+               throw lexical_error(format("conversion of '%s' to BlendEquation", str));
+}
+
+void operator<<(LexicalConverter &conv, BlendEquation eq)
+{
+       switch(eq)
+       {
+       case ADD: conv.result("ADD"); break;
+       case SUBTRACT: conv.result("SUBTRACT"); break;
+       case REVERSE_SUBTRACT: conv.result("REVERSE_SUBTRACT"); break;
+       case MIN: conv.result("MIN"); break;
+       case MAX: conv.result("MAX"); break;
+       default: conv.result(format("BlendEquation(%#x)", static_cast<int>(eq)));
+       }
 }
 
 void operator>>(const LexicalConverter &conv, BlendFactor &factor)
index e7b291e617dab5c2044e787c99ee7a09a7dfcac5..986844c0e6a7e1f2caa15249a8c7d8531bd4bf09 100644 (file)
@@ -1,64 +1,73 @@
 #ifndef MSP_GL_BLEND_H_
 #define MSP_GL_BLEND_H_
 
+#include <msp/datafile/objectloader.h>
 #include <msp/strings/lexicalcast.h>
-#include "bindable.h"
+#include "color.h"
 #include "gl.h"
-#include <msp/gl/extensions/ext_blend_minmax.h>
 
 namespace Msp {
 namespace GL {
 
 enum BlendEquation
 {
-       ADD              = GL_FUNC_ADD,
-       SUBTRACT         = GL_FUNC_SUBTRACT,
-       REVERSE_SUBTRACT = GL_FUNC_REVERSE_SUBTRACT,
-       MIN              = GL_MIN,
-       MAX              = GL_MAX
+       ADD,
+       SUBTRACT,
+       REVERSE_SUBTRACT,
+       MIN,
+       MAX
 };
 
 enum BlendFactor
 {
-       ZERO = GL_ZERO,
-       ONE = GL_ONE,
-       SRC_COLOR = GL_SRC_COLOR,
-       ONE_MINUS_SRC_COLOR = GL_ONE_MINUS_SRC_COLOR,
-       SRC_ALPHA = GL_SRC_ALPHA,
-       ONE_MINUS_SRC_ALPHA = GL_ONE_MINUS_SRC_ALPHA,
-       DST_COLOR = GL_DST_COLOR,
-       ONE_MINUS_DST_COLOR = GL_ONE_MINUS_DST_COLOR,
-       DST_ALPHA = GL_DST_ALPHA,
-       ONE_MINUS_DST_ALPHA = GL_ONE_MINUS_DST_ALPHA,
-       CONSTANT_COLOR = GL_CONSTANT_COLOR,
-       ONE_MINUS_CONSTANT_COLOR = GL_ONE_MINUS_CONSTANT_COLOR,
-       CONSTANT_ALPHA = GL_CONSTANT_ALPHA,
-       ONE_MINUS_CONSTANT_ALPHA = GL_ONE_MINUS_CONSTANT_ALPHA
+       ZERO,
+       ONE,
+       SRC_COLOR,
+       ONE_MINUS_SRC_COLOR,
+       SRC_ALPHA,
+       ONE_MINUS_SRC_ALPHA,
+       DST_COLOR,
+       ONE_MINUS_DST_COLOR,
+       DST_ALPHA,
+       ONE_MINUS_DST_ALPHA,
+       CONSTANT_COLOR,
+       ONE_MINUS_CONSTANT_COLOR,
+       CONSTANT_ALPHA,
+       ONE_MINUS_CONSTANT_ALPHA
 };
 
 /**
 Blends incoming fragments with those already in the framebuffer.
 */
-class Blend: public Bindable<Blend>
+struct Blend
 {
-private:
-       BlendEquation eq;
+       class Loader: public DataFile::ObjectLoader<Blend>
+       {
+       public:
+               Loader(Blend &);
+
+       private:
+               void constant(float, float, float, float);
+               void equation(BlendEquation);
+               void factors(BlendFactor, BlendFactor);
+       };
+
+       bool enabled;
+       BlendEquation equation;
        BlendFactor src_factor;
        BlendFactor dst_factor;
+       Color constant;
 
-public:
        Blend();
        Blend(BlendFactor, BlendFactor);
        Blend(BlendEquation, BlendFactor, BlendFactor);
+};
 
-       void bind() const;
-
-       static void unbind();
+GLenum get_gl_blend_equation(BlendEquation);
+GLenum get_gl_blend_factor(BlendFactor);
 
-       static const Blend &alpha();
-       static const Blend &additive();
-       static const Blend &additive_alpha();
-};
+void operator>>(const LexicalConverter &, BlendEquation &);
+void operator<<(LexicalConverter &, BlendEquation);
 
 void operator>>(const LexicalConverter &, BlendFactor &);
 void operator<<(LexicalConverter &, BlendFactor);
diff --git a/source/core/depthtest.cpp b/source/core/depthtest.cpp
new file mode 100644 (file)
index 0000000..5ae4f72
--- /dev/null
@@ -0,0 +1,35 @@
+#include "depthtest.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+DepthTest::DepthTest():
+       enabled(false),
+       compare(LESS),
+       write(true)
+{ }
+
+DepthTest::DepthTest(Predicate c, bool w):
+       enabled(true),
+       compare(c),
+       write(w)
+{ }
+
+
+DepthTest::Loader::Loader(DepthTest &dt):
+       ObjectLoader<DepthTest>(dt)
+{
+       add("compare", &Loader::compare);
+       add("write", &DepthTest::write);
+}
+
+void DepthTest::Loader::compare(Predicate c)
+{
+       obj.enabled = true;
+       obj.compare = c;
+}
+
+} // namespace GL
+} // namespace Msp
diff --git a/source/core/depthtest.h b/source/core/depthtest.h
new file mode 100644 (file)
index 0000000..d79f06e
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef MSP_GL_DEPTHTEST_H_
+#define MSP_GL_DEPTHTEST_H_
+
+#include <msp/datafile/objectloader.h>
+#include "predicate.h"
+
+namespace Msp {
+namespace GL {
+
+/**
+Tests incoming fragment depth values against the depth buffer.  If the test
+fails, the fragment is discarded.
+*/
+struct DepthTest
+{
+       class Loader: public DataFile::ObjectLoader<DepthTest>
+       {
+       public:
+               Loader(DepthTest &);
+
+       private:
+               void compare(Predicate);
+       };
+
+       bool enabled;
+       Predicate compare;
+       bool write;
+
+       DepthTest();
+       DepthTest(Predicate, bool = true);
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
index 673fa701e6cb6c5d5860648bab880cda117a2a87..7a38eab5e4136a12e490e4bdcbb079872e181de1 100644 (file)
@@ -5,10 +5,13 @@
 #include <msp/gl/extensions/arb_shader_objects.h>
 #include <msp/gl/extensions/arb_uniform_buffer_object.h>
 #include <msp/gl/extensions/arb_vertex_array_object.h>
+#include "blend.h"
 #include "buffer.h"
 #include "deviceinfo.h"
+#include "depthtest.h"
 #include "pipelinestate.h"
 #include "program.h"
+#include "stenciltest.h"
 #include "texture.h"
 #include "uniformblock.h"
 #include "vertexsetup.h"
@@ -27,6 +30,9 @@ PipelineState::PipelineState():
        front_face(COUNTERCLOCKWISE),
        face_cull(NO_CULL),
        enabled_clip_planes(0),
+       depth_test(0),
+       stencil_test(0),
+       blend(0),
        changes(0)
 {
        if(!ARB_direct_state_access && bound_tex_targets.empty())
@@ -114,6 +120,21 @@ void PipelineState::set_uniform_block_(int binding, const UniformBlock *block)
        }
 }
 
+void PipelineState::set_depth_test(const DepthTest *dt)
+{
+       set(depth_test, dt, DEPTH_TEST);
+}
+
+void PipelineState::set_stencil_test(const StencilTest *st)
+{
+       set(stencil_test, st, STENCIL_TEST);
+}
+
+void PipelineState::set_blend(const Blend *b)
+{
+       set(blend, b, BLEND);
+}
+
 void PipelineState::apply() const
 {
        apply(this==last_applied ? changes : ~0U);
@@ -264,6 +285,44 @@ void PipelineState::apply(unsigned mask) const
                        }
        }
 
+       if(mask&DEPTH_TEST)
+       {
+               if(depth_test && depth_test->enabled)
+               {
+                       glEnable(GL_DEPTH_TEST);
+                       glDepthFunc(get_gl_predicate(depth_test->compare));
+               }
+               else
+                       glDisable(GL_DEPTH_TEST);
+
+               glDepthMask(!depth_test || depth_test->write);
+       }
+
+       if(mask&STENCIL_TEST)
+       {
+               if(stencil_test && stencil_test->enabled)
+               {
+                       glEnable(GL_STENCIL_TEST);
+                       glStencilFunc(get_gl_predicate(stencil_test->compare), stencil_test->reference, 0xFFFFFFFF);
+                       glStencilOp(get_gl_stencil_op(stencil_test->stencil_fail_op), get_gl_stencil_op(stencil_test->depth_fail_op), get_gl_stencil_op(stencil_test->depth_pass_op));
+               }
+               else
+                       glDisable(GL_STENCIL_TEST);
+       }
+
+       if(mask&BLEND)
+       {
+               if(blend && blend->enabled)
+               {
+                       glEnable(GL_BLEND);
+                       glBlendEquation(get_gl_blend_equation(blend->equation));
+                       glBlendFunc(get_gl_blend_factor(blend->src_factor), get_gl_blend_factor(blend->dst_factor));
+                       glBlendColor(blend->constant.r, blend->constant.g, blend->constant.b, blend->constant.a);
+               }
+               else
+                       glDisable(GL_BLEND);
+       }
+
        last_applied = this;
        changes &= ~mask;
 }
@@ -297,6 +356,11 @@ void PipelineState::clear()
                        if(i->block)
                                glBindBufferBase(GL_UNIFORM_BUFFER, i->binding, 0);
 
+               glDisable(GL_DEPTH_TEST);
+               glDepthMask(true);
+               glDisable(GL_STENCIL_TEST);
+               glDisable(GL_BLEND);
+
                last_applied = 0;
        }
 }
index 1d313c3b3eb1dea828bacce03d545a4e751748df..a931e25c406808232cd07809c44d616d15c5a7d4 100644 (file)
@@ -8,10 +8,13 @@
 namespace Msp {
 namespace GL {
 
+class Blend;
 class BufferBackedUniformBlock;
 class DefaultUniformBlock;
+class DepthTest;
 class Program;
 class Sampler;
+class StencilTest;
 class Texture;
 class UniformBlock;
 class VertexSetup;
@@ -46,7 +49,10 @@ private:
                FACE_CULL = 4,
                CLIP_PLANES = 8,
                TEXTURES = 16,
-               UNIFORMS = 32
+               UNIFORMS = 32,
+               DEPTH_TEST = 64,
+               STENCIL_TEST = 128,
+               BLEND = 256
        };
 
        const Program *shprog;
@@ -56,6 +62,9 @@ private:
        unsigned enabled_clip_planes;
        std::vector<BoundTexture> textures;
        std::vector<BoundUniformBlock> uniform_blocks;
+       const DepthTest *depth_test;
+       const StencilTest *stencil_test;
+       const Blend *blend;
        mutable unsigned changes;
 
        static const PipelineState *last_applied;
@@ -80,6 +89,9 @@ public:
 private:
        void set_uniform_block_(int, const UniformBlock *);
 public:
+       void set_depth_test(const DepthTest *);
+       void set_stencil_test(const StencilTest *);
+       void set_blend(const Blend *);
 
        const Program *get_shader_program() const { return shprog; }
        const VertexSetup *get_vertex_setup() const { return vertex_setup; }
diff --git a/source/core/stencil.cpp b/source/core/stencil.cpp
deleted file mode 100644 (file)
index 28d59f1..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#include "stencil.h"
-
-namespace Msp {
-namespace GL {
-
-void stencil_func(Predicate func, int ref, unsigned mask)
-{
-       glStencilFunc(get_gl_predicate(func), ref, mask);
-}
-
-void stencil_op(StencilOp sfail, StencilOp dfail, StencilOp dpass)
-{
-       glStencilOp(sfail, dfail, dpass);
-}
-
-} // namespace GL
-} // namespace Msp
diff --git a/source/core/stencil.h b/source/core/stencil.h
deleted file mode 100644 (file)
index 02f4ed3..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef MSP_GL_STENCIL_H_
-#define MSP_GL_STENCIL_H_
-
-#include "gl.h"
-#include "predicate.h"
-
-namespace Msp {
-namespace GL {
-
-enum
-{
-       STENCIL_TEST = GL_STENCIL_TEST
-};
-
-enum StencilOp
-{
-       KEEP      = GL_KEEP,
-       SET_ZERO  = GL_ZERO,
-       REPLACE   = GL_REPLACE,
-       INCR      = GL_INCR,
-       DECR      = GL_DECR,
-       INVERT    = GL_INVERT,
-       INCR_WRAP = GL_INCR_WRAP,
-       DECR_WRAP = GL_DECR_WRAP
-};
-
-void stencil_func(Predicate func, int ref, unsigned mask);
-void stencil_op(StencilOp sfail, StencilOp dfail, StencilOp dpass);
-
-} // namespace GL
-} // namespace Msp
-
-#endif
diff --git a/source/core/stenciltest.cpp b/source/core/stenciltest.cpp
new file mode 100644 (file)
index 0000000..7076f4d
--- /dev/null
@@ -0,0 +1,98 @@
+#include <stdexcept>
+#include <msp/strings/format.h>
+#include "stenciltest.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+StencilTest::StencilTest():
+       enabled(false),
+       compare(ALWAYS),
+       stencil_fail_op(KEEP),
+       depth_fail_op(KEEP),
+       depth_pass_op(KEEP),
+       reference(0)
+{ }
+
+
+StencilTest::Loader::Loader(StencilTest &st):
+       ObjectLoader<StencilTest>(st)
+{
+       add("compare", &Loader::compare);
+       add("actions", &Loader::actions);
+       add("reference", &StencilTest::reference);
+}
+
+void StencilTest::Loader::compare(Predicate c)
+{
+       obj.enabled = true;
+       obj.compare = c;
+}
+
+void StencilTest::Loader::actions(StencilOp sf, StencilOp df, StencilOp dp)
+{
+       obj.stencil_fail_op = sf;
+       obj.depth_fail_op = df;
+       obj.depth_pass_op = dp;
+}
+
+
+GLenum get_gl_stencil_op(StencilOp op)
+{
+       switch(op)
+       {
+       case KEEP: return GL_KEEP;
+       case SET_ZERO: return GL_ZERO;
+       case REPLACE: return GL_REPLACE;
+       case INCR: return GL_INCR;
+       case DECR: return GL_DECR;
+       case INVERT: return GL_INVERT;
+       case INCR_WRAP: return GL_INCR_WRAP;
+       case DECR_WRAP: return GL_DECR_WRAP;
+       default: throw invalid_argument("get_gl_stencil_op");
+       }
+}
+
+void operator>>(const LexicalConverter &conv, StencilOp &op)
+{
+       const string &str = conv.get();
+       if(str=="KEEP")
+               op = KEEP;
+       else if(str=="SET_ZERO")
+               op = SET_ZERO;
+       else if(str=="REPLACE")
+               op = REPLACE;
+       else if(str=="INCR")
+               op = INCR;
+       else if(str=="DECR")
+               op = DECR;
+       else if(str=="INVERT")
+               op = INVERT;
+       else if(str=="INCR_WRAP")
+               op = INCR_WRAP;
+       else if(str=="DECR_WRAP")
+               op = DECR_WRAP;
+       else
+               throw lexical_error(format("conversion of '%s' to StencilOp", str));
+}
+
+void operator<<(LexicalConverter &conv, StencilOp op)
+{
+       switch(op)
+       {
+       case KEEP: conv.result("KEEP"); break;
+       case SET_ZERO: conv.result("SET_ZERO"); break;
+       case REPLACE: conv.result("REPLACE"); break;
+       case INCR: conv.result("INCR"); break;
+       case DECR: conv.result("DECR"); break;
+       case INVERT: conv.result("INVERT"); break;
+       case INCR_WRAP: conv.result("INCR_WRAP"); break;
+       case DECR_WRAP: conv.result("DECR_WRAP"); break;
+       default: conv.result(format("StencilOp(%#x)", static_cast<int>(op)));
+       }
+}
+
+} // namespace GL
+} // namespace Msp
diff --git a/source/core/stenciltest.h b/source/core/stenciltest.h
new file mode 100644 (file)
index 0000000..cdc6138
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef MSP_GL_STENCILTEST_H_
+#define MSP_GL_STENCILTEST_H_
+
+#include <msp/datafile/objectloader.h>
+#include <msp/strings/lexicalcast.h>
+#include "predicate.h"
+
+namespace Msp {
+namespace GL {
+
+enum StencilOp
+{
+       KEEP,
+       SET_ZERO,
+       REPLACE,
+       INCR,
+       DECR,
+       INVERT,
+       INCR_WRAP,
+       DECR_WRAP
+};
+
+/**
+Tests values in the stencil buffer against a reference.  If the test fails, the
+incoming fragment is discarded.  The stencil buffer may be modified according
+to results of the stencil test and the depth test.
+*/
+struct StencilTest
+{
+       class Loader: public DataFile::ObjectLoader<StencilTest>
+       {
+       public:
+               Loader(StencilTest &);
+
+       private:
+               void compare(Predicate);
+               void actions(StencilOp, StencilOp, StencilOp);
+       };
+
+       bool enabled;
+       Predicate compare;
+       StencilOp stencil_fail_op;
+       StencilOp depth_fail_op;
+       StencilOp depth_pass_op;
+       unsigned reference;
+
+       StencilTest();
+};
+
+GLenum get_gl_stencil_op(StencilOp);
+
+void operator>>(const LexicalConverter &, StencilOp &);
+void operator<<(LexicalConverter &, StencilOp);
+
+} // namespace GL
+} // namespace Msp
+
+#endif
index e1ad526115b5386a8c5007cf1e7a9563f52d8498..0bbec053c01ef3a5adee0ba0c31deba3a5af8b6b 100644 (file)
@@ -3,43 +3,6 @@
 namespace Msp {
 namespace GL {
 
-DepthTest::DepthTest():
-       write(true),
-       pred(LESS)
-{ }
-
-DepthTest::DepthTest(Predicate p, bool w):
-       write(w),
-       pred(p)
-{ }
-
-void DepthTest::bind() const
-{
-       if(set_current(this))
-       {
-               glEnable(GL_DEPTH_TEST);
-               glDepthFunc(get_gl_predicate(pred));
-               glDepthMask(write);
-       }
-}
-
-const DepthTest &DepthTest::lequal()
-{
-       static DepthTest test(LEQUAL);
-       return test;
-}
-
-void DepthTest::unbind()
-{
-       if(set_current(0))
-       {
-               glDisable(GL_DEPTH_TEST);
-               // Allow glClear(GL_DEPTH_BUFFER_BIT) to work
-               glDepthMask(true);
-       }
-}
-
-
 ScissorTest::ScissorTest():
        left(0),
        bottom(0),
index f7d729504a37f34b477a635675197f4166c29791..7e38e81e41a0c956f36da24578d998f94d215fd6 100644 (file)
@@ -8,27 +8,6 @@
 namespace Msp {
 namespace GL {
 
-/**
-Tests incoming fragment depth values against the depth buffer.  If the test
-fails, the fragment is discarded.
-*/
-class DepthTest: public Bindable<DepthTest>
-{
-private:
-       bool write;
-       Predicate pred;
-
-public:
-       DepthTest();
-       DepthTest(Predicate, bool = true);
-
-       void bind() const;
-
-       static const DepthTest &lequal();
-       static void unbind();
-};
-
-
 /**
 Tests fragment coordinates against a rectangle.  Any fragments outside the
 rectangle are discarded.
index a6d431bc200da86e025dcc2b640aa9d2a342d0e0..cf73e810070581d8c03c6e5f3c61391d127d1551 100644 (file)
@@ -6,7 +6,6 @@
 #include "resources.h"
 #include "scene.h"
 #include "shadowmap.h"
-#include "tests.h"
 
 using namespace std;
 
@@ -42,6 +41,9 @@ void ShadowMap::init(unsigned s)
        fbo.attach(DEPTH_ATTACHMENT, depth_buf, 0);
        fbo.require_complete();
 
+       depth_test.enabled = true;
+       depth_test.compare = LEQUAL;
+
        set_darkness(1.0f);
        shdata.uniform("shd_world_matrix", Matrix());
 }
@@ -92,11 +94,11 @@ void ShadowMap::setup_frame(Renderer &renderer)
        shdata.uniform("shd_world_matrix", shadow_matrix);
 
        BindRestore bind_fbo(fbo);
-       Bind bind_depth(DepthTest::lequal());
        fbo.clear(DEPTH_BUFFER_BIT);
 
        Renderer::Push push(renderer);
        renderer.set_camera(shadow_camera);
+       renderer.set_depth_test(&depth_test);
 
        renderer.render(shadow_caster);
 }
index dc1ce548cb325bd233f39a600afacbcd4e0ccddd..67f2cf6c30a0b1b264759b0090265b89cec7a5b6 100644 (file)
@@ -2,6 +2,7 @@
 #define MSP_GL_SHADOWMAP_H_
 
 #include "camera.h"
+#include "depthtest.h"
 #include "effect.h"
 #include "framebuffer.h"
 #include "programdata.h"
@@ -30,6 +31,7 @@ private:
        Camera shadow_camera;
        Matrix shadow_matrix;
        Texture2D depth_buf;
+       DepthTest depth_test;
        const Sampler &sampler;
        Vector3 target;
        float radius;
index 29db99232cd48a8a9e946b12f9326d32fb0e23a8..68b7927dcb7067c0e3331c33f3f09bab1bf6a04a 100644 (file)
@@ -161,6 +161,21 @@ void Renderer::set_face_cull(CullMode cull)
        state->face_cull = cull;
 }
 
+void Renderer::set_depth_test(const DepthTest *dt)
+{
+       state->depth_test = dt;
+}
+
+void Renderer::set_stencil_test(const StencilTest *st)
+{
+       state->stencil_test = st;
+}
+
+void Renderer::set_blend(const Blend *b)
+{
+       state->blend = b;
+}
+
 void Renderer::set_object_lod_bias(unsigned b)
 {
        state->object_lod_bias = b;
@@ -282,6 +297,10 @@ void Renderer::apply_state()
                changed &= ~SHADER_DATA;
        }
 
+       pipeline_state.set_depth_test(state->depth_test);
+       pipeline_state.set_stencil_test(state->stencil_test);
+       pipeline_state.set_blend(state->blend);
+
        pipeline_state.apply();
 }
 
@@ -310,6 +329,9 @@ Renderer::State::State():
        vertex_setup(0),
        front_face(NON_MANIFOLD),
        face_cull(NO_CULL),
+       depth_test(0),
+       stencil_test(0),
+       blend(0),
        object_lod_bias(0)
 { }
 
index ee48b9107cddab64af53442fccb00f10bb4df1ea..23ced9e4fc567bc124a80fefd70b330937f149cc 100644 (file)
@@ -95,6 +95,9 @@ private:
                const VertexSetup *vertex_setup;
                FaceWinding front_face;
                CullMode face_cull;
+               const DepthTest *depth_test;
+               const StencilTest *stencil_test;
+               const Blend *blend;
                unsigned object_lod_bias;
 
                State();
@@ -160,6 +163,10 @@ public:
        void set_front_face(FaceWinding);
        void set_face_cull(CullMode);
 
+       void set_depth_test(const DepthTest *);
+       void set_stencil_test(const StencilTest *);
+       void set_blend(const Blend *);
+
        void set_object_lod_bias(unsigned);
        unsigned get_object_lod_bias() const { return state->object_lod_bias; }
 
index 9161c75146cc7552ac5363e21d69700a7ff5b564..2c32db86518b14033c9452a64be2ed0fb0106397 100644 (file)
@@ -163,8 +163,6 @@ void Sequence::render(Renderer &renderer, Tag tag) const
        const Framebuffer *out_fbo = Framebuffer::current();
        // These are no-ops but will ensure the related state gets restored
        BindRestore restore_fbo(out_fbo);
-       BindRestore restore_depth_test(DepthTest::current());
-       BindRestore restore_blend(Blend::current());
 
        if(target[0])
        {
@@ -175,15 +173,11 @@ void Sequence::render(Renderer &renderer, Tag tag) const
 
        for(vector<Step>::const_iterator i=steps.begin(); i!=steps.end(); ++i)
        {
-               if(const DepthTest *dt = i->get_depth_test())
-                       dt->bind();
-               else
-                       DepthTest::unbind();
+               Renderer::Push push(renderer);
 
-               if(const Blend *b = i->get_blend())
-                       b->bind();
-               else
-                       Blend::unbind();
+               renderer.set_depth_test(&i->get_depth_test());
+               renderer.set_stencil_test(&i->get_stencil_test());
+               renderer.set_blend(&i->get_blend());
 
                if (const Lighting *lighting = i->get_lighting())
                        renderer.add_shader_data(lighting->get_shader_data());
@@ -195,8 +189,9 @@ void Sequence::render(Renderer &renderer, Tag tag) const
 
        if(target[0])
        {
-               DepthTest::unbind();
-               Blend::unbind();
+               renderer.set_depth_test(0);
+               renderer.set_stencil_test(0);
+               renderer.set_blend(0);
 
                if(samples)
                        target[0]->blit_from(*target_ms);
@@ -275,8 +270,6 @@ void Sequence::set_target_debug_names()
 Sequence::Step::Step(Tag t, Renderable *r):
        tag(t),
        lighting(0),
-       depth_test(0),
-       blend(0),
        clipping(0),
        renderable(r)
 { }
@@ -286,12 +279,17 @@ void Sequence::Step::set_lighting(const Lighting *l)
        lighting = l;
 }
 
-void Sequence::Step::set_depth_test(const DepthTest *d)
+void Sequence::Step::set_depth_test(const DepthTest &dt)
 {
-       depth_test = d;
+       depth_test = dt;
 }
 
-void Sequence::Step::set_blend(const Blend *b)
+void Sequence::Step::set_stencil_test(const StencilTest &st)
+{
+       stencil_test = st;
+}
+
+void Sequence::Step::set_blend(const Blend &b)
 {
        blend = b;
 }
index b1d2c7cabc54f81eea9d0a1ac2abcaf6bf4f2b69..be8ed30621a08403842616c11d09fbab877359d3 100644 (file)
@@ -3,10 +3,13 @@
 
 #include <map>
 #include <set>
+#include "blend.h"
+#include "depthtest.h"
 #include "framebuffer.h"
 #include "renderable.h"
 #include "renderbuffer.h"
 #include "rendertarget.h"
+#include "stenciltest.h"
 #include "texture2d.h"
 
 namespace Msp {
@@ -15,7 +18,6 @@ namespace GL {
 class Blend;
 class Camera;
 class Clipping;
-class DepthTest;
 class Lighting;
 class PostProcessor;
 class View;
@@ -42,8 +44,9 @@ public:
        private:
                Tag tag;
                const Lighting *lighting;
-               const DepthTest *depth_test;
-               const Blend *blend;
+               DepthTest depth_test;
+               StencilTest stencil_test;
+               Blend blend;
                const Clipping *clipping;
                Renderable *renderable;
 
@@ -53,12 +56,14 @@ public:
                Tag get_tag() const { return tag; }
 
                void set_lighting(const Lighting *);
-               void set_depth_test(const DepthTest *);
-               void set_blend(const Blend *);
+               void set_depth_test(const DepthTest &);
+               void set_stencil_test(const StencilTest &);
+               void set_blend(const Blend &);
                void set_clipping(const Clipping *);
                const Lighting *get_lighting() const { return lighting; }
-               const DepthTest *get_depth_test() const { return depth_test; }
-               const Blend *get_blend() const { return blend; }
+               const DepthTest &get_depth_test() const { return depth_test; }
+               const StencilTest &get_stencil_test() const { return stencil_test; }
+               const Blend &get_blend() const { return blend; }
                const Clipping *get_clipping() const { return clipping; }
                Renderable *get_renderable() const { return renderable; }
        };
index b05e6695c0a9d2438295ce2421d60e60bc75024d..2c950e18e2acc22714ee9d3030ed7467371a0fe0 100644 (file)
@@ -23,7 +23,6 @@
 #include <msp/gl/resources.h>
 #include <msp/gl/simplescene.h>
 #include <msp/gl/technique.h>
-#include <msp/gl/tests.h>
 #include <msp/gl/windowview.h>
 #include <msp/input/mouse.h>
 #include <msp/io/print.h>
@@ -238,8 +237,8 @@ Viewer::Viewer(int argc, char **argv):
                sequence = new GL::Sequence(view);
                GL::Sequence::Step &step = sequence->add_step(0, *renderable);
                step.set_lighting(&lighting);
-               step.set_depth_test(&GL::DepthTest::lequal());
-               step.set_blend(&GL::Blend::alpha());
+               step.set_depth_test(GL::LEQUAL);
+               step.set_blend(GL::Blend(GL::SRC_ALPHA, GL::ONE_MINUS_SRC_ALPHA));
        }
 
        view.set_content(sequence);