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:
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)
hdr true;
pass "" "content"
{
- depth_test "lequal";
+ depth_test LEQUAL;
lighting "Desert.lightn";
scene "Desert.wrapper.scene";
};
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");
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");
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);
}
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)
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()
obj.default_renderable = &get_collection().get<Scene>(name);
}
+void SequenceTemplate::Step::Loader::stencil_test()
+{
+ load_sub(obj.stencil_test);
+}
+
} // namespace GL
} // namespace Msp
#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;
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;
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)
#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);
--- /dev/null
+#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
--- /dev/null
+#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
#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"
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())
}
}
+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);
}
}
+ 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;
}
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;
}
}
namespace Msp {
namespace GL {
+class Blend;
class BufferBackedUniformBlock;
class DefaultUniformBlock;
+class DepthTest;
class Program;
class Sampler;
+class StencilTest;
class Texture;
class UniformBlock;
class VertexSetup;
FACE_CULL = 4,
CLIP_PLANES = 8,
TEXTURES = 16,
- UNIFORMS = 32
+ UNIFORMS = 32,
+ DEPTH_TEST = 64,
+ STENCIL_TEST = 128,
+ BLEND = 256
};
const Program *shprog;
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;
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; }
+++ /dev/null
-#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
+++ /dev/null
-#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
--- /dev/null
+#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
--- /dev/null
+#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
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),
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.
#include "resources.h"
#include "scene.h"
#include "shadowmap.h"
-#include "tests.h"
using namespace std;
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());
}
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);
}
#define MSP_GL_SHADOWMAP_H_
#include "camera.h"
+#include "depthtest.h"
#include "effect.h"
#include "framebuffer.h"
#include "programdata.h"
Camera shadow_camera;
Matrix shadow_matrix;
Texture2D depth_buf;
+ DepthTest depth_test;
const Sampler &sampler;
Vector3 target;
float radius;
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;
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();
}
vertex_setup(0),
front_face(NON_MANIFOLD),
face_cull(NO_CULL),
+ depth_test(0),
+ stencil_test(0),
+ blend(0),
object_lod_bias(0)
{ }
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();
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; }
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])
{
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());
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);
Sequence::Step::Step(Tag t, Renderable *r):
tag(t),
lighting(0),
- depth_test(0),
- blend(0),
clipping(0),
renderable(r)
{ }
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;
}
#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 {
class Blend;
class Camera;
class Clipping;
-class DepthTest;
class Lighting;
class PostProcessor;
class View;
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;
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; }
};
#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>
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);