From 2b2676392aff2eb6b38c3e463cc67f4d67a4ef8b Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Wed, 18 Aug 2021 17:33:59 +0300 Subject: [PATCH] Redesign depth and stencil test and blend state management --- blender/io_mspgl/export_scene.py | 4 +- demos/desertpillars/data/exported/Desert.seq | 2 +- demos/desertpillars/source/desertpillars.cpp | 4 +- source/builders/sequencebuilder.cpp | 5 +- source/builders/sequencetemplate.cpp | 44 +++---- source/builders/sequencetemplate.h | 17 +-- source/core/blend.cpp | 119 ++++++++++++++----- source/core/blend.h | 73 +++++++----- source/core/depthtest.cpp | 35 ++++++ source/core/depthtest.h | 36 ++++++ source/core/pipelinestate.cpp | 64 ++++++++++ source/core/pipelinestate.h | 14 ++- source/core/stencil.cpp | 17 --- source/core/stencil.h | 33 ----- source/core/stenciltest.cpp | 98 +++++++++++++++ source/core/stenciltest.h | 58 +++++++++ source/core/tests.cpp | 37 ------ source/core/tests.h | 21 ---- source/effects/shadowmap.cpp | 6 +- source/effects/shadowmap.h | 2 + source/render/renderer.cpp | 22 ++++ source/render/renderer.h | 7 ++ source/render/sequence.cpp | 32 +++-- source/render/sequence.h | 19 +-- tools/viewer.cpp | 5 +- 25 files changed, 532 insertions(+), 242 deletions(-) create mode 100644 source/core/depthtest.cpp create mode 100644 source/core/depthtest.h delete mode 100644 source/core/stencil.cpp delete mode 100644 source/core/stencil.h create mode 100644 source/core/stenciltest.cpp create mode 100644 source/core/stenciltest.h diff --git a/blender/io_mspgl/export_scene.py b/blender/io_mspgl/export_scene.py index 3f0509ab..7bb32efe 100644 --- a/blender/io_mspgl/export_scene.py +++ b/blender/io_mspgl/export_scene.py @@ -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) diff --git a/demos/desertpillars/data/exported/Desert.seq b/demos/desertpillars/data/exported/Desert.seq index 347f662d..8000033c 100644 --- a/demos/desertpillars/data/exported/Desert.seq +++ b/demos/desertpillars/data/exported/Desert.seq @@ -1,7 +1,7 @@ hdr true; pass "" "content" { - depth_test "lequal"; + depth_test LEQUAL; lighting "Desert.lightn"; scene "Desert.wrapper.scene"; }; diff --git a/demos/desertpillars/source/desertpillars.cpp b/demos/desertpillars/source/desertpillars.cpp index 124df81c..dee2c490 100644 --- a/demos/desertpillars/source/desertpillars.cpp +++ b/demos/desertpillars/source/desertpillars.cpp @@ -42,7 +42,7 @@ DesertPillars::DesertPillars(int, char **): shadow_seq = make_unique(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(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("Desert.lightn")); - step->set_depth_test(&GL::DepthTest::lequal()); + step->set_depth_test(GL::LEQUAL); env_map = make_unique(256, GL::RGB16F, 7, sphere, *env_seq); env_map->set_debug_name("Environment map"); diff --git a/source/builders/sequencebuilder.cpp b/source/builders/sequencebuilder.cpp index 9bb8f1dc..12e7bdf3 100644 --- a/source/builders/sequencebuilder.cpp +++ b/source/builders/sequencebuilder.cpp @@ -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); } diff --git a/source/builders/sequencetemplate.cpp b/source/builders/sequencetemplate.cpp index 3ad97313..18a328e1 100644 --- a/source/builders/sequencetemplate.cpp +++ b/source/builders/sequencetemplate.cpp @@ -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(name); } +void SequenceTemplate::Step::Loader::stencil_test() +{ + load_sub(obj.stencil_test); +} + } // namespace GL } // namespace Msp diff --git a/source/builders/sequencetemplate.h b/source/builders/sequencetemplate.h index 32736d8e..061fdfc3 100644 --- a/source/builders/sequencetemplate.h +++ b/source/builders/sequencetemplate.h @@ -6,13 +6,14 @@ #include #include #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 depth_test; - RefPtr blend; + DepthTest depth_test; + StencilTest stencil_test; + Blend blend; std::string slot_name; Renderable *default_renderable; diff --git a/source/core/blend.cpp b/source/core/blend.cpp index 3327885c..a5e8f44d 100644 --- a/source/core/blend.cpp +++ b/source/core/blend.cpp @@ -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(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(eq))); + } } void operator>>(const LexicalConverter &conv, BlendFactor &factor) diff --git a/source/core/blend.h b/source/core/blend.h index e7b291e6..986844c0 100644 --- a/source/core/blend.h +++ b/source/core/blend.h @@ -1,64 +1,73 @@ #ifndef MSP_GL_BLEND_H_ #define MSP_GL_BLEND_H_ +#include #include -#include "bindable.h" +#include "color.h" #include "gl.h" -#include 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 +struct Blend { -private: - BlendEquation eq; + class Loader: public DataFile::ObjectLoader + { + 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 index 00000000..5ae4f728 --- /dev/null +++ b/source/core/depthtest.cpp @@ -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(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 index 00000000..d79f06e8 --- /dev/null +++ b/source/core/depthtest.h @@ -0,0 +1,36 @@ +#ifndef MSP_GL_DEPTHTEST_H_ +#define MSP_GL_DEPTHTEST_H_ + +#include +#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 + { + public: + Loader(DepthTest &); + + private: + void compare(Predicate); + }; + + bool enabled; + Predicate compare; + bool write; + + DepthTest(); + DepthTest(Predicate, bool = true); +}; + +} // namespace GL +} // namespace Msp + +#endif diff --git a/source/core/pipelinestate.cpp b/source/core/pipelinestate.cpp index 673fa701..7a38eab5 100644 --- a/source/core/pipelinestate.cpp +++ b/source/core/pipelinestate.cpp @@ -5,10 +5,13 @@ #include #include #include +#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; } } diff --git a/source/core/pipelinestate.h b/source/core/pipelinestate.h index 1d313c3b..a931e25c 100644 --- a/source/core/pipelinestate.h +++ b/source/core/pipelinestate.h @@ -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 textures; std::vector 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 index 28d59f19..00000000 --- a/source/core/stencil.cpp +++ /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 index 02f4ed3f..00000000 --- a/source/core/stencil.h +++ /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 index 00000000..7076f4d7 --- /dev/null +++ b/source/core/stenciltest.cpp @@ -0,0 +1,98 @@ +#include +#include +#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(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(op))); + } +} + +} // namespace GL +} // namespace Msp diff --git a/source/core/stenciltest.h b/source/core/stenciltest.h new file mode 100644 index 00000000..cdc61388 --- /dev/null +++ b/source/core/stenciltest.h @@ -0,0 +1,58 @@ +#ifndef MSP_GL_STENCILTEST_H_ +#define MSP_GL_STENCILTEST_H_ + +#include +#include +#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 + { + 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 diff --git a/source/core/tests.cpp b/source/core/tests.cpp index e1ad5261..0bbec053 100644 --- a/source/core/tests.cpp +++ b/source/core/tests.cpp @@ -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), diff --git a/source/core/tests.h b/source/core/tests.h index f7d72950..7e38e81e 100644 --- a/source/core/tests.h +++ b/source/core/tests.h @@ -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 -{ -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. diff --git a/source/effects/shadowmap.cpp b/source/effects/shadowmap.cpp index a6d431bc..cf73e810 100644 --- a/source/effects/shadowmap.cpp +++ b/source/effects/shadowmap.cpp @@ -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); } diff --git a/source/effects/shadowmap.h b/source/effects/shadowmap.h index dc1ce548..67f2cf6c 100644 --- a/source/effects/shadowmap.h +++ b/source/effects/shadowmap.h @@ -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; diff --git a/source/render/renderer.cpp b/source/render/renderer.cpp index 29db9923..68b7927d 100644 --- a/source/render/renderer.cpp +++ b/source/render/renderer.cpp @@ -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) { } diff --git a/source/render/renderer.h b/source/render/renderer.h index ee48b910..23ced9e4 100644 --- a/source/render/renderer.h +++ b/source/render/renderer.h @@ -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; } diff --git a/source/render/sequence.cpp b/source/render/sequence.cpp index 9161c751..2c32db86 100644 --- a/source/render/sequence.cpp +++ b/source/render/sequence.cpp @@ -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::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; } diff --git a/source/render/sequence.h b/source/render/sequence.h index b1d2c7ca..be8ed306 100644 --- a/source/render/sequence.h +++ b/source/render/sequence.h @@ -3,10 +3,13 @@ #include #include +#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; } }; diff --git a/tools/viewer.cpp b/tools/viewer.cpp index b05e6695..2c950e18 100644 --- a/tools/viewer.cpp +++ b/tools/viewer.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -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); -- 2.43.0