#include <msp/gl/mesh.h>
#include <msp/gl/meshbuilder.h>
#include <msp/gl/object.h>
-#include <msp/gl/pipeline.h>
+#include <msp/gl/sequence.h>
#include <msp/gl/program.h>
#include <msp/gl/renderer.h>
#include <msp/gl/resources.h>
- Shadow mapping
- Environment mapped reflections
- Skybox using a cube map texture
-- Effects with nested pipelines
+- Effects with nested sequences
- Complex multitexturing
- Shader-based deformations
- Creating a normalmapped texture through rendering
GL::EnvironmentMap *env_cube;
GL::WindowView view;
- GL::Pipeline pipeline;
+ GL::Sequence sequence;
GL::Camera camera;
GL::SimpleScene sky_scene;
GL::InstanceScene scene;
GL::Bloom bloom;
GL::ColorCurve colorcurve;
- GL::Pipeline env_pipeline;
+ GL::Sequence env_sequence;
Time::TimeStamp last_tick;
float camera_angle;
private:
void setup_view();
- void create_pipeline();
+ void create_sequence();
void create_skybox();
static void create_skybox_face(GL::TextureCube &, GL::TextureCubeFace);
void create_tiles_texture();
cube_shprog(cube_src),
cube_shadow_shprog(string(cube_src)+cube_shadow_src_tail),
view(window, gl_context),
- pipeline(view),
+ sequence(view),
shadow_scene(resources, 2048, scene, light),
bloom(resources, window.get_width(), window.get_height()),
colorcurve(resources),
- env_pipeline(512, 512),
+ env_sequence(512, 512),
camera_angle(0),
camera_stopped(false),
cube_angle(0),
keyboard.signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &DesertPillars::key_press), false));
setup_view();
- create_pipeline();
+ create_sequence();
create_skybox();
create_ground();
create_pillars();
camera.set_up_direction(GL::Vector3(0, 0, 1));
camera.set_depth_clip(1, 50);
view.set_camera(&camera);
- view.set_content(&pipeline);
+ view.set_content(&sequence);
}
-void DesertPillars::create_pipeline()
+void DesertPillars::create_sequence()
{
- pipeline.set_multisample(8);
- pipeline.set_hdr(true);
+ sequence.set_multisample(8);
+ sequence.set_hdr(true);
/* The shadow map is focused on the part of the scene that contains the
pillars and the cube. Making the ground cast shadows as well would result
lighting.set_ambient(GL::Color(0.2));
// The skybox is rendered first
- pipeline.add_pass(0, sky_scene);
+ sequence.add_pass(0, sky_scene);
- GL::Pipeline::Pass *pass = &pipeline.add_pass(0, shadow_scene);
+ GL::Sequence::Pass *pass = &sequence.add_pass(0, shadow_scene);
pass->set_lighting(&lighting);
pass->set_depth_test(&GL::DepthTest::lequal());
/* A bloom filter enhances the realism of bright surfaces, even if there
isn't anything really glowy in the scene. */
bloom.set_strength(0.3);
- pipeline.add_postprocessor(bloom);
+ sequence.add_postprocessor(bloom);
/* Lighting calculations are best done in linear color space, so the final
image must be converted to srgb for display. */
colorcurve.set_srgb();
- pipeline.add_postprocessor(colorcurve);
+ sequence.add_postprocessor(colorcurve);
- /* Initialize a second pipeline to render the environment map. It has the
+ /* Initialize a second sequence to render the environment map. It has the
same renderables and passes, but no postprocessors or camera. */
- env_pipeline.add_pass(0, sky_scene);
- pass = &env_pipeline.add_pass(0, shadow_scene);
+ env_sequence.add_pass(0, sky_scene);
+ pass = &env_sequence.add_pass(0, shadow_scene);
pass->set_lighting(&lighting);
pass->set_depth_test(&GL::DepthTest::lequal());
}
cube_data.object = new GL::Object(cube_data.mesh, &cube_tech);
cube = new Cube(*cube_data.object);
- env_cube = new GL::EnvironmentMap(resources, 512, *cube, env_pipeline);
+ env_cube = new GL::EnvironmentMap(resources, 512, *cube, env_sequence);
scene.add(*env_cube);
}
+++ /dev/null
-#include <msp/core/algorithm.h>
-#include <msp/core/maputils.h>
-#include "error.h"
-#include "pipeline.h"
-#include "pipelinebuilder.h"
-#include "pipelinetemplate.h"
-#include "renderbuffer.h"
-
-using namespace std;
-
-namespace Msp {
-namespace GL {
-
-PipelineBuilder::PipelineBuilder(const PipelineTemplate &t):
- tmpl(t)
-{
- const vector<PipelineTemplate::Pass> &passes = tmpl.get_passes();
- for(vector<PipelineTemplate::Pass>::const_iterator i=passes.begin(); i!=passes.end(); ++i)
- renderables[i->renderable_name] = 0;
- const vector<PipelineTemplate::PostProcessor> &postprocs = tmpl.get_postprocessors();
- for(PipelineTemplate::PostProcessorArray::const_iterator i=postprocs.begin(); i!=postprocs.end(); ++i)
- if(!i->slot_name.empty())
- postprocessors[i->slot_name] = 0;
-}
-
-void PipelineBuilder::set_renderable(const string &name, Renderable &rend)
-{
- get_item(renderables, name) = &rend;
-}
-
-void PipelineBuilder::set_postprocessor(const string &name, PostProcessor &pproc)
-{
- get_item(postprocessors, name) = &pproc;
-}
-
-void PipelineBuilder::build(Pipeline &pipeline) const
-{
- pipeline.set_hdr(tmpl.get_hdr());
- pipeline.set_alpha(tmpl.get_alpha());
- unsigned samples = min(tmpl.get_maximum_multisample(), Renderbuffer::get_max_samples());
- if(samples<tmpl.get_required_multisample())
- throw invalid_operation("PipelineBuilder::build");
-
- pipeline.set_multisample(samples);
-
- const PipelineTemplate::PassArray &passes = tmpl.get_passes();
- for(PipelineTemplate::PassArray::const_iterator i=passes.begin(); i!=passes.end(); ++i)
- {
- Renderable *renderable = get_item(renderables, i->renderable_name);
- if(!renderable)
- continue;
-
- Pipeline::Pass &pass = pipeline.add_pass(i->tag, *renderable);
- pass.set_blend(i->blend.get());
- pass.set_depth_test(i->depth_test.get());
- pass.set_lighting(i->lighting.get());
- }
-
- const PipelineTemplate::PostProcessorArray &postprocs = tmpl.get_postprocessors();
- for(PipelineTemplate::PostProcessorArray::const_iterator i=postprocs.begin(); i!=postprocs.end(); ++i)
- {
- PostProcessor *proc = 0;
- if(!i->slot_name.empty())
- proc = get_item(postprocessors, i->slot_name);
- if(proc)
- pipeline.add_postprocessor(*proc);
- else if(i->postprocessor_template)
- {
- proc = i->postprocessor_template->create(tmpl.get_resources(), pipeline.get_width(), pipeline.get_height());
- if(proc)
- pipeline.add_postprocessor_owned(proc);
- }
- }
-}
-
-Pipeline *PipelineBuilder::build(unsigned w, unsigned h) const
-{
- RefPtr<Pipeline> pipeline = new Pipeline(w, h);
- build(*pipeline);
- return pipeline.release();
-}
-
-Pipeline *PipelineBuilder::build(const View &view) const
-{
- RefPtr<Pipeline> pipeline = new Pipeline(view);
- build(*pipeline);
- return pipeline.release();
-}
-
-Pipeline *PipelineBuilder::build(const Framebuffer &fbo) const
-{
- RefPtr<Pipeline> pipeline = new Pipeline(fbo);
- build(*pipeline);
- return pipeline.release();
-}
-
-} // namespace GL
-} // namespace Msp
+++ /dev/null
-#ifndef PIPELINEBUILDER_H_
-#define PIPELINEBUILDER_H_
-
-#include <map>
-#include <string>
-
-namespace Msp {
-namespace GL {
-
-class Framebuffer;
-class Pipeline;
-class PipelineTemplate;
-class PostProcessor;
-class Renderable;
-class View;
-
-class PipelineBuilder
-{
-private:
- const PipelineTemplate &tmpl;
- std::map<std::string, Renderable *> renderables;
- std::map<std::string, PostProcessor *> postprocessors;
-
-public:
- PipelineBuilder(const PipelineTemplate &);
-
- void set_renderable(const std::string &, Renderable &);
- void set_postprocessor(const std::string &, PostProcessor &);
-
- void build(Pipeline &) const;
- Pipeline *build(unsigned, unsigned) const;
- Pipeline *build(const View &) const;
- Pipeline *build(const Framebuffer &) const;
-};
-
-} // namespace GL
-} // namespace Msp
-
-#endif
+++ /dev/null
-#include <msp/core/maputils.h>
-#include <msp/datafile/collection.h>
-#include "ambientocclusion.h"
-#include "blend.h"
-#include "bloom.h"
-#include "colorcurve.h"
-#include "lighting.h"
-#include "pipelinetemplate.h"
-#include "resources.h"
-#include "tests.h"
-
-using namespace std;
-
-namespace Msp {
-namespace GL {
-
-PipelineTemplate::PipelineTemplate():
- resources(0),
- hdr(false),
- alpha(false),
- required_multisample(0),
- max_multisample(0)
-{ }
-
-PipelineTemplate::~PipelineTemplate()
-{
- for(PostProcessorArray::iterator i=postprocessors.begin(); i!=postprocessors.end(); ++i)
- delete i->postprocessor_template;
-}
-
-Resources &PipelineTemplate::get_resources() const
-{
- if(!resources)
- throw logic_error("no resources");
- return *resources;
-}
-
-
-PipelineTemplate::PostProcessorRegistry &PipelineTemplate::get_postprocessor_registry()
-{
- static PostProcessorRegistry registry;
- static bool initialized = false;
- if(!initialized)
- {
- registry.register_type<AmbientOcclusion>("ambient_occlusion");
- registry.register_type<Bloom>("bloom");
- registry.register_type<ColorCurve>("colorcurve");
- initialized = true;
- }
- return registry;
-}
-
-
-PipelineTemplate::Pass::~Pass()
-{ }
-
-
-PipelineTemplate::PostProcessor::PostProcessor(GL::PostProcessor::Template *ppt):
- postprocessor_template(ppt)
-{ }
-
-
-PipelineTemplate::PostProcLoader::PostProcLoader()
-{
- get_postprocessor_registry().invoke_all(*this);
-}
-
-
-PipelineTemplate::Loader::Loader(PipelineTemplate &t, Collection &c):
- DataFile::CollectionObjectLoader<PipelineTemplate, Resources>(t, &c)
-{
- add("hdr", &PipelineTemplate::hdr);
- add("alpha", &PipelineTemplate::alpha);
- add("multisample", &Loader::multisample);
- add("multisample", &Loader::multisample_range);
- add("pass", &Loader::pass);
- add("postprocessor", &Loader::postprocessor);
-
- obj.resources = &c;
-}
-
-void PipelineTemplate::Loader::postprocessor_loaded()
-{
- obj.postprocessors.push_back(get_postprocessor_template());
-}
-
-void PipelineTemplate::Loader::multisample(unsigned samples)
-{
- obj.required_multisample = samples;
- obj.max_multisample = samples;
-}
-
-void PipelineTemplate::Loader::multisample_range(unsigned req, unsigned max)
-{
- obj.required_multisample = req;
- obj.max_multisample = max;
-}
-
-void PipelineTemplate::Loader::pass(const string &tag, const string &rend)
-{
- Pass pss;;
- pss.tag = tag;
- pss.renderable_name = rend;
- if(coll)
- load_sub(pss, *coll);
- else
- load_sub(pss);
-
- obj.passes.push_back(pss);
-}
-
-void PipelineTemplate::Loader::postprocessor(const string &slot)
-{
- PostProcLoader ldr;
- load_sub_with(ldr);
- PostProcessor pp;
- pp.postprocessor_template = ldr.get_postprocessor_template();
- pp.slot_name = slot;
- obj.postprocessors.push_back(pp);
-}
-
-
-PipelineTemplate::Pass::Loader::Loader(Pass &p):
- DataFile::CollectionObjectLoader<Pass>(p, 0)
-{
- init();
-}
-
-PipelineTemplate::Pass::Loader::Loader(Pass &p, Collection &c):
- DataFile::CollectionObjectLoader<Pass>(p, &c)
-{
- init();
-}
-
-void PipelineTemplate::Pass::Loader::init()
-{
- add("blend", &Loader::blend);
- add("blend", &Loader::blend_predefined);
- add("depth_test", &Loader::depth_test);
- add("depth_test", &Loader::depth_test_predefined);
- add("lighting", &Loader::lighting);
- add("lighting", &Loader::lighting_inline);
-}
-
-void PipelineTemplate::Pass::Loader::blend_predefined(const string &name)
-{
- 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();
-}
-
-void PipelineTemplate::Pass::Loader::blend(BlendFactor src, BlendFactor dest)
-{
- obj.blend = new Blend(src, dest);
-}
-
-void PipelineTemplate::Pass::Loader::depth_test_predefined(const string &name)
-{
- const DepthTest *dtest = 0;
- if(name=="lequal")
- dtest = &DepthTest::lequal();
- else
- throw key_error(name);
-
- obj.depth_test = dtest;
- obj.depth_test.keep();
-}
-
-void PipelineTemplate::Pass::Loader::depth_test(Predicate pred)
-{
- obj.depth_test = new DepthTest(pred);
-}
-
-void PipelineTemplate::Pass::Loader::lighting_inline()
-{
- RefPtr<Lighting> lightn = new Lighting;
- load_sub(*lightn);
- obj.lighting = lightn;
-}
-
-void PipelineTemplate::Pass::Loader::lighting(const string &name)
-{
- obj.lighting = &get_collection().get<Lighting>(name);
- obj.lighting.keep();
-}
-
-/*void PipelineTemplate::Pass::Loader::scene(const string &name)
-{
- obj.default_renderable = get_collection().get<Scene>(name);
-}*/
-
-} // namespace GL
-} // namespace Msp
+++ /dev/null
-#ifndef PIPELINETEMPLATE_H_
-#define PIPELINETEMPLATE_H_
-
-#include <string>
-#include <vector>
-#include <msp/core/typeregistry.h>
-#include <msp/datafile/objectloader.h>
-#include "blend.h"
-#include "postprocessor.h"
-#include "predicate.h"
-
-namespace Msp {
-namespace GL {
-
-class DepthTest;
-class Lighting;
-
-class PipelineTemplate
-{
-private:
- class PostProcLoader: virtual public DataFile::Loader
- {
- private:
- template<typename T>
- struct AddPostProc
- {
- void operator()(const std::string &kw, PostProcLoader &ldr) const { ldr.add(kw, &PostProcLoader::postprocessor<T>); }
- };
-
- protected:
- RefPtr<PostProcessor::Template> postproc;
-
- public:
- PostProcLoader();
-
- PostProcessor::Template *get_postprocessor_template() { return postproc.release(); }
-
- protected:
- virtual void postprocessor_loaded() { }
-
- private:
- template<typename T>
- void postprocessor();
-
- friend class PipelineTemplate;
- };
-
-public:
- class Loader: public DataFile::CollectionObjectLoader<PipelineTemplate, Resources>, public PostProcLoader
- {
- public:
- Loader(PipelineTemplate &, Collection &);
-
- virtual void postprocessor_loaded();
- void multisample(unsigned);
- void multisample_range(unsigned, unsigned);
- void pass(const std::string &, const std::string &);
- void postprocessor(const std::string &);
- };
-
- struct Pass
- {
- class Loader: public DataFile::CollectionObjectLoader<Pass>
- {
- public:
- Loader(Pass &);
- Loader(Pass &, Collection &);
- private:
- void init();
-
- void blend(BlendFactor, BlendFactor);
- void blend_predefined(const std::string &);
- void depth_test(Predicate);
- void depth_test_predefined(const std::string &);
- void lighting(const std::string &);
- void lighting_inline();
- // TODO requires support for scenes in Resources
- //void scene(const std::string &);
- };
-
- std::string tag;
- RefPtr<Lighting> lighting;
- RefPtr<const DepthTest> depth_test;
- RefPtr<const Blend> blend;
- std::string renderable_name;
- //Renderable *default_renderable;
-
- ~Pass();
- };
-
- struct PostProcessor
- {
- GL::PostProcessor::Template *postprocessor_template;
- std::string slot_name;
-
- PostProcessor(GL::PostProcessor::Template * = 0);
- };
-
- typedef std::vector<Pass> PassArray;
- typedef std::vector<PostProcessor> PostProcessorArray;
-
-private:
- typedef TypeRegistry<PostProcLoader::AddPostProc, PostProcLoader &> PostProcessorRegistry;
-
- Resources *resources;
- bool hdr;
- bool alpha;
- unsigned required_multisample;
- unsigned max_multisample;
- PassArray passes;
- PostProcessorArray postprocessors;
-
-public:
- PipelineTemplate();
- ~PipelineTemplate();
-
- Resources &get_resources() const;
- bool get_hdr() const { return hdr; }
- bool get_alpha() const { return alpha; }
- unsigned get_required_multisample() const { return required_multisample; }
- unsigned get_maximum_multisample() const { return max_multisample; }
- const PassArray &get_passes() const { return passes; }
- const PostProcessorArray &get_postprocessors() const { return postprocessors; }
-
- template<typename T>
- static void register_postprocessor(const std::string &);
-private:
- static PostProcessorRegistry &get_postprocessor_registry();
-};
-
-template<typename T>
-void PipelineTemplate::register_postprocessor(const std::string &kw)
-{
- get_postprocessor_registry().register_type<T>(kw);
-}
-
-template<typename T>
-void PipelineTemplate::PostProcLoader::postprocessor()
-{
- if(postproc)
- throw std::logic_error("Only one postprocessor allowed per slot");
- RefPtr<typename T::Template> pp = new typename T::Template;
- load_sub(*pp);
- postproc = pp;
- pp = 0;
- postprocessor_loaded();
-}
-
-} // namespace GL
-} // namespace Msp
-
-#endif
--- /dev/null
+#include <msp/core/algorithm.h>
+#include <msp/core/maputils.h>
+#include "error.h"
+#include "renderbuffer.h"
+#include "sequence.h"
+#include "sequencebuilder.h"
+#include "sequencetemplate.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+SequenceBuilder::SequenceBuilder(const SequenceTemplate &t):
+ tmpl(t)
+{
+ const vector<SequenceTemplate::Step> &steps = tmpl.get_steps();
+ for(vector<SequenceTemplate::Step>::const_iterator i=steps.begin(); i!=steps.end(); ++i)
+ renderables[i->renderable_name] = 0;
+ const vector<SequenceTemplate::PostProcessor> &postprocs = tmpl.get_postprocessors();
+ for(SequenceTemplate::PostProcessorArray::const_iterator i=postprocs.begin(); i!=postprocs.end(); ++i)
+ if(!i->slot_name.empty())
+ postprocessors[i->slot_name] = 0;
+}
+
+void SequenceBuilder::set_renderable(const string &name, Renderable &rend)
+{
+ get_item(renderables, name) = &rend;
+}
+
+void SequenceBuilder::set_postprocessor(const string &name, PostProcessor &pproc)
+{
+ get_item(postprocessors, name) = &pproc;
+}
+
+void SequenceBuilder::build(Sequence &sequence) const
+{
+ sequence.set_hdr(tmpl.get_hdr());
+ sequence.set_alpha(tmpl.get_alpha());
+ unsigned samples = min(tmpl.get_maximum_multisample(), Renderbuffer::get_max_samples());
+ if(samples<tmpl.get_required_multisample())
+ throw invalid_operation("SequenceBuilder::build");
+
+ sequence.set_multisample(samples);
+
+ const vector<SequenceTemplate::Step> &steps = tmpl.get_steps();
+ for(vector<SequenceTemplate::Step>::const_iterator i=steps.begin(); i!=steps.end(); ++i)
+ {
+ Renderable *renderable = get_item(renderables, i->renderable_name);
+ if(!renderable)
+ 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_lighting(i->lighting.get());
+ }
+
+ const SequenceTemplate::PostProcessorArray &postprocs = tmpl.get_postprocessors();
+ for(SequenceTemplate::PostProcessorArray::const_iterator i=postprocs.begin(); i!=postprocs.end(); ++i)
+ {
+ PostProcessor *proc = 0;
+ if(!i->slot_name.empty())
+ proc = get_item(postprocessors, i->slot_name);
+ if(proc)
+ sequence.add_postprocessor(*proc);
+ else if(i->postprocessor_template)
+ {
+ proc = i->postprocessor_template->create(tmpl.get_resources(), sequence.get_width(), sequence.get_height());
+ if(proc)
+ sequence.add_postprocessor_owned(proc);
+ }
+ }
+}
+
+Sequence *SequenceBuilder::build(unsigned w, unsigned h) const
+{
+ RefPtr<Sequence> sequence = new Sequence(w, h);
+ build(*sequence);
+ return sequence.release();
+}
+
+Sequence *SequenceBuilder::build(const View &view) const
+{
+ RefPtr<Sequence> sequence = new Sequence(view);
+ build(*sequence);
+ return sequence.release();
+}
+
+Sequence *SequenceBuilder::build(const Framebuffer &fbo) const
+{
+ RefPtr<Sequence> sequence = new Sequence(fbo);
+ build(*sequence);
+ return sequence.release();
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef SEQUENCEBUILDER_H_
+#define SEQUENCEBUILDER_H_
+
+#include <map>
+#include <string>
+
+namespace Msp {
+namespace GL {
+
+class Framebuffer;
+class Sequence;
+class SequenceTemplate;
+class PostProcessor;
+class Renderable;
+class View;
+
+class SequenceBuilder
+{
+private:
+ const SequenceTemplate &tmpl;
+ std::map<std::string, Renderable *> renderables;
+ std::map<std::string, PostProcessor *> postprocessors;
+
+public:
+ SequenceBuilder(const SequenceTemplate &);
+
+ void set_renderable(const std::string &, Renderable &);
+ void set_postprocessor(const std::string &, PostProcessor &);
+
+ void build(Sequence &) const;
+ Sequence *build(unsigned, unsigned) const;
+ Sequence *build(const View &) const;
+ Sequence *build(const Framebuffer &) const;
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <msp/core/maputils.h>
+#include <msp/datafile/collection.h>
+#include "ambientocclusion.h"
+#include "blend.h"
+#include "bloom.h"
+#include "colorcurve.h"
+#include "lighting.h"
+#include "resources.h"
+#include "sequencetemplate.h"
+#include "tests.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+SequenceTemplate::SequenceTemplate():
+ resources(0),
+ hdr(false),
+ alpha(false),
+ required_multisample(0),
+ max_multisample(0)
+{ }
+
+SequenceTemplate::~SequenceTemplate()
+{
+ for(PostProcessorArray::iterator i=postprocessors.begin(); i!=postprocessors.end(); ++i)
+ delete i->postprocessor_template;
+}
+
+Resources &SequenceTemplate::get_resources() const
+{
+ if(!resources)
+ throw logic_error("no resources");
+ return *resources;
+}
+
+
+SequenceTemplate::PostProcessorRegistry &SequenceTemplate::get_postprocessor_registry()
+{
+ static PostProcessorRegistry registry;
+ static bool initialized = false;
+ if(!initialized)
+ {
+ registry.register_type<AmbientOcclusion>("ambient_occlusion");
+ registry.register_type<Bloom>("bloom");
+ registry.register_type<ColorCurve>("colorcurve");
+ initialized = true;
+ }
+ return registry;
+}
+
+
+SequenceTemplate::Step::~Step()
+{ }
+
+
+SequenceTemplate::PostProcessor::PostProcessor(GL::PostProcessor::Template *ppt):
+ postprocessor_template(ppt)
+{ }
+
+
+SequenceTemplate::PostProcLoader::PostProcLoader()
+{
+ get_postprocessor_registry().invoke_all(*this);
+}
+
+
+SequenceTemplate::Loader::Loader(SequenceTemplate &t, Collection &c):
+ DataFile::CollectionObjectLoader<SequenceTemplate, Resources>(t, &c)
+{
+ add("hdr", &SequenceTemplate::hdr);
+ add("alpha", &SequenceTemplate::alpha);
+ add("multisample", &Loader::multisample);
+ add("multisample", &Loader::multisample_range);
+ add("postprocessor", &Loader::postprocessor);
+ add("step", &Loader::step);
+
+ // Deprecated
+ add("pass", &Loader::step);
+
+ obj.resources = &c;
+}
+
+void SequenceTemplate::Loader::postprocessor_loaded()
+{
+ obj.postprocessors.push_back(get_postprocessor_template());
+}
+
+void SequenceTemplate::Loader::multisample(unsigned samples)
+{
+ obj.required_multisample = samples;
+ obj.max_multisample = samples;
+}
+
+void SequenceTemplate::Loader::multisample_range(unsigned req, unsigned max)
+{
+ obj.required_multisample = req;
+ obj.max_multisample = max;
+}
+
+void SequenceTemplate::Loader::postprocessor(const string &slot)
+{
+ PostProcLoader ldr;
+ load_sub_with(ldr);
+ PostProcessor pp;
+ pp.postprocessor_template = ldr.get_postprocessor_template();
+ pp.slot_name = slot;
+ obj.postprocessors.push_back(pp);
+}
+
+void SequenceTemplate::Loader::step(const string &tag, const string &rend)
+{
+ Step stp;
+ stp.tag = tag;
+ stp.renderable_name = rend;
+ if(coll)
+ load_sub(stp, *coll);
+ else
+ load_sub(stp);
+
+ obj.steps.push_back(stp);
+}
+
+
+SequenceTemplate::Step::Loader::Loader(Step &p):
+ DataFile::CollectionObjectLoader<Step>(p, 0)
+{
+ init();
+}
+
+SequenceTemplate::Step::Loader::Loader(Step &p, Collection &c):
+ DataFile::CollectionObjectLoader<Step>(p, &c)
+{
+ init();
+}
+
+void SequenceTemplate::Step::Loader::init()
+{
+ add("blend", &Loader::blend);
+ add("blend", &Loader::blend_predefined);
+ add("depth_test", &Loader::depth_test);
+ add("depth_test", &Loader::depth_test_predefined);
+ add("lighting", &Loader::lighting);
+ add("lighting", &Loader::lighting_inline);
+}
+
+void SequenceTemplate::Step::Loader::blend_predefined(const string &name)
+{
+ 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();
+}
+
+void SequenceTemplate::Step::Loader::blend(BlendFactor src, BlendFactor dest)
+{
+ obj.blend = new Blend(src, dest);
+}
+
+void SequenceTemplate::Step::Loader::depth_test_predefined(const string &name)
+{
+ const DepthTest *dtest = 0;
+ if(name=="lequal")
+ dtest = &DepthTest::lequal();
+ else
+ throw key_error(name);
+
+ obj.depth_test = dtest;
+ obj.depth_test.keep();
+}
+
+void SequenceTemplate::Step::Loader::depth_test(Predicate pred)
+{
+ obj.depth_test = new DepthTest(pred);
+}
+
+void SequenceTemplate::Step::Loader::lighting_inline()
+{
+ RefPtr<Lighting> lightn = new Lighting;
+ load_sub(*lightn);
+ obj.lighting = lightn;
+}
+
+void SequenceTemplate::Step::Loader::lighting(const string &name)
+{
+ obj.lighting = &get_collection().get<Lighting>(name);
+ obj.lighting.keep();
+}
+
+/*void SequenceTemplate::Step::Loader::scene(const string &name)
+{
+ obj.default_renderable = get_collection().get<Scene>(name);
+}*/
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef SEQUENCETEMPLATE_H_
+#define SEQUENCETEMPLATE_H_
+
+#include <string>
+#include <vector>
+#include <msp/core/typeregistry.h>
+#include <msp/datafile/objectloader.h>
+#include "blend.h"
+#include "postprocessor.h"
+#include "predicate.h"
+
+namespace Msp {
+namespace GL {
+
+class DepthTest;
+class Lighting;
+
+class SequenceTemplate
+{
+private:
+ class PostProcLoader: virtual public DataFile::Loader
+ {
+ private:
+ template<typename T>
+ struct AddPostProc
+ {
+ void operator()(const std::string &kw, PostProcLoader &ldr) const { ldr.add(kw, &PostProcLoader::postprocessor<T>); }
+ };
+
+ protected:
+ RefPtr<PostProcessor::Template> postproc;
+
+ public:
+ PostProcLoader();
+
+ PostProcessor::Template *get_postprocessor_template() { return postproc.release(); }
+
+ protected:
+ virtual void postprocessor_loaded() { }
+
+ private:
+ template<typename T>
+ void postprocessor();
+
+ friend class SequenceTemplate;
+ };
+
+public:
+ class Loader: public DataFile::CollectionObjectLoader<SequenceTemplate, Resources>, public PostProcLoader
+ {
+ public:
+ Loader(SequenceTemplate &, Collection &);
+
+ virtual void postprocessor_loaded();
+ void multisample(unsigned);
+ void multisample_range(unsigned, unsigned);
+ void postprocessor(const std::string &);
+ void step(const std::string &, const std::string &);
+ };
+
+ struct Step
+ {
+ class Loader: public DataFile::CollectionObjectLoader<Step>
+ {
+ public:
+ Loader(Step &);
+ Loader(Step &, Collection &);
+ private:
+ void init();
+
+ void blend(BlendFactor, BlendFactor);
+ void blend_predefined(const std::string &);
+ void depth_test(Predicate);
+ void depth_test_predefined(const std::string &);
+ void lighting(const std::string &);
+ void lighting_inline();
+ // TODO requires support for scenes in Resources
+ //void scene(const std::string &);
+ };
+
+ std::string tag;
+ RefPtr<Lighting> lighting;
+ RefPtr<const DepthTest> depth_test;
+ RefPtr<const Blend> blend;
+ std::string renderable_name;
+ //Renderable *default_renderable;
+
+ ~Step();
+ };
+
+ struct PostProcessor
+ {
+ GL::PostProcessor::Template *postprocessor_template;
+ std::string slot_name;
+
+ PostProcessor(GL::PostProcessor::Template * = 0);
+ };
+
+ typedef std::vector<PostProcessor> PostProcessorArray;
+
+private:
+ typedef TypeRegistry<PostProcLoader::AddPostProc, PostProcLoader &> PostProcessorRegistry;
+
+ Resources *resources;
+ bool hdr;
+ bool alpha;
+ unsigned required_multisample;
+ unsigned max_multisample;
+ std::vector<Step> steps;
+ PostProcessorArray postprocessors;
+
+public:
+ SequenceTemplate();
+ ~SequenceTemplate();
+
+ Resources &get_resources() const;
+ bool get_hdr() const { return hdr; }
+ bool get_alpha() const { return alpha; }
+ unsigned get_required_multisample() const { return required_multisample; }
+ unsigned get_maximum_multisample() const { return max_multisample; }
+ const std::vector<Step> &get_steps() const { return steps; }
+ const PostProcessorArray &get_postprocessors() const { return postprocessors; }
+
+ template<typename T>
+ static void register_postprocessor(const std::string &);
+private:
+ static PostProcessorRegistry &get_postprocessor_registry();
+};
+
+template<typename T>
+void SequenceTemplate::register_postprocessor(const std::string &kw)
+{
+ get_postprocessor_registry().register_type<T>(kw);
+}
+
+template<typename T>
+void SequenceTemplate::PostProcLoader::postprocessor()
+{
+ if(postproc)
+ throw std::logic_error("Only one postprocessor allowed per slot");
+ RefPtr<typename T::Template> pp = new typename T::Template;
+ load_sub(*pp);
+ postproc = pp;
+ pp = 0;
+ postprocessor_loaded();
+}
+
+} // namespace GL
+} // namespace Msp
+
+#endif
Creates a cube map texture of the surroundings of the renderable. This texture
can then be used to implement effects such as reflections or refractions.
-If the EnvironmentMap is used in a Pipeline, it's worth noting that the cube
+If the EnvironmentMap is used in a Sequence, it's worth noting that the cube
map will be prepared outside of any rendering pass. It's recommended to use
-another Pipeline to define which passes should be used to render the
+another Sequence to define which passes should be used to render the
environment.
*/
class EnvironmentMap: public Effect
light.
Lights are usually grouped with a Lighting object, which can be used in a
-Pipeline::Pass.
+Sequence::Step.
Lights do not cast shadows by themselves. See ShadowMap for that.
*/
+++ /dev/null
-#include <msp/core/maputils.h>
-#include "blend.h"
-#include "camera.h"
-#include "framebuffer.h"
-#include "lighting.h"
-#include "pipeline.h"
-#include "postprocessor.h"
-#include "renderbuffer.h"
-#include "renderer.h"
-#include "tests.h"
-#include "texture2d.h"
-#include "view.h"
-
-using namespace std;
-
-namespace Msp {
-namespace GL {
-
-Pipeline::Pipeline(unsigned w, unsigned h, bool d)
-{
- init(w, h);
- hdr = d;
-}
-
-Pipeline::Pipeline(const View &view)
-{
- init(view.get_width(), view.get_height());
-}
-
-Pipeline::Pipeline(const Framebuffer &fbo)
-{
- init(fbo.get_width(), fbo.get_height());
-}
-
-void Pipeline::init(unsigned w, unsigned h)
-{
- camera = 0;
- width = w;
- height = h;
- hdr = false;
- alpha = false;
- samples = 0;
- target_ms = 0;
- target[0] = 0;
- target[1] = 0;
-}
-
-Pipeline::~Pipeline()
-{
- delete target[0];
- delete target[1];
- delete target_ms;
-}
-
-void Pipeline::set_hdr(bool h)
-{
- if(h==hdr)
- return;
-
- bool old_hdr = hdr;
- hdr = h;
- try
- {
- create_targets(2);
- }
- catch(...)
- {
- hdr = old_hdr;
- throw;
- }
-}
-
-void Pipeline::set_alpha(bool a)
-{
- if(a==alpha)
- return;
-
- bool old_alpha = alpha;
- alpha = a;
- try
- {
- create_targets(2);
- }
- catch(...)
- {
- alpha = old_alpha;
- throw;
- }
-}
-
-void Pipeline::set_multisample(unsigned s)
-{
- if(s==samples)
- return;
-
- unsigned old_samples = samples;
- samples = s;
- try
- {
- create_targets(1);
- }
- catch(...)
- {
- samples = old_samples;
- throw;
- }
-}
-
-Pipeline::Pass &Pipeline::add_pass(Tag tag, Renderable &r)
-{
- passes.push_back(Pass(tag, &r));
- return passes.back();
-}
-
-void Pipeline::add_postprocessor(PostProcessor &pp)
-{
- add_postprocessor(&pp, true);
-}
-
-void Pipeline::add_postprocessor_owned(PostProcessor *pp)
-{
- add_postprocessor(pp, false);
-}
-
-void Pipeline::add_postprocessor(PostProcessor *pp, bool keep)
-{
- postproc.push_back(pp);
- if(keep)
- postproc.back().keep();
- try
- {
- create_targets(0);
- }
- catch(...)
- {
- postproc.pop_back();
- throw;
- }
-}
-
-void Pipeline::setup_frame(Renderer &renderer)
-{
- for(PassList::const_iterator i=passes.begin(); i!=passes.end(); ++i)
- if(Renderable *renderable = i->get_renderable())
- renderable->setup_frame(renderer);
- for(vector<Slot>::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
- i->renderable->setup_frame(renderer);
-}
-
-void Pipeline::finish_frame()
-{
- for(PassList::const_iterator i=passes.begin(); i!=passes.end(); ++i)
- if(Renderable *renderable = i->get_renderable())
- renderable->finish_frame();
- for(vector<Slot>::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
- i->renderable->finish_frame();
-}
-
-void Pipeline::render(Renderer &renderer, Tag tag) const
-{
- if(tag.id)
- return;
-
- 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])
- {
- Framebuffer &fbo = (samples ? target_ms : target[0])->get_framebuffer();
- fbo.bind();
- fbo.clear();
- }
-
- for(PassList::const_iterator i=passes.begin(); i!=passes.end(); ++i)
- {
- if(const DepthTest *dt = i->get_depth_test())
- dt->bind();
- else
- DepthTest::unbind();
-
- if(const Blend *b = i->get_blend())
- b->bind();
- else
- Blend::unbind();
-
- renderer.set_lighting(i->get_lighting());
- renderer.set_clipping(i->get_clipping());
-
- if(const Renderable *renderable = i->get_renderable())
- renderer.render(*renderable, i->get_tag());
-
- for(vector<Slot>::const_iterator j=renderables.begin(); j!=renderables.end(); ++j)
- if(j->passes.empty() || j->passes.count(i->get_tag()))
- renderer.render(*j->renderable, i->get_tag());
- }
-
- if(target[0])
- {
- DepthTest::unbind();
- Blend::unbind();
-
- if(samples)
- target[0]->blit_from(*target_ms);
-
- for(unsigned i=0; i<postproc.size(); ++i)
- {
- unsigned j = i%2;
- if(i+1<postproc.size())
- target[1-j]->get_framebuffer().bind();
- else
- out_fbo->bind();
- const Texture2D &color = target[j]->get_target_texture(RENDER_COLOR);
- const Texture2D &depth = target[j]->get_target_texture(RENDER_DEPTH);
- postproc[i]->render(renderer, color, depth);
- }
- }
-}
-
-void Pipeline::create_targets(unsigned recreate)
-{
- if(recreate>=2)
- {
- delete target[0];
- delete target[1];
- target[0] = 0;
- target[1] = 0;
- }
- if(recreate>=1)
- {
- delete target_ms;
- target_ms = 0;
- }
-
- PixelFormat color_pf = (hdr ? (alpha ? RGBA16F : RGB16F) : (alpha ? RGBA8 : RGB8));
- RenderTargetFormat fmt = (RENDER_COLOR,color_pf, RENDER_DEPTH);
- if(!postproc.empty() || samples)
- {
- if(!target[0])
- target[0] = new RenderTarget(width, height, fmt);
- if(!target[1] && postproc.size()>1)
- target[1] = new RenderTarget(width, height, fmt);
- }
-
- if(!target_ms && samples)
- target_ms = new RenderTarget(width, height, samples, fmt);
-}
-
-
-Pipeline::Pass::Pass(Tag t, Renderable *r):
- tag(t),
- lighting(0),
- depth_test(0),
- blend(0),
- clipping(0),
- renderable(r)
-{ }
-
-void Pipeline::Pass::set_lighting(const Lighting *l)
-{
- lighting = l;
-}
-
-void Pipeline::Pass::set_depth_test(const DepthTest *d)
-{
- depth_test = d;
-}
-
-void Pipeline::Pass::set_blend(const Blend *b)
-{
- blend = b;
-}
-
-void Pipeline::Pass::set_clipping(const Clipping *c)
-{
- clipping =c;
-}
-
-
-Pipeline::Slot::Slot(Renderable *r):
- renderable(r)
-{ }
-
-} // namespace GL
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_GL_PIPELINE_H_
-#define MSP_GL_PIPELINE_H_
-
-#include <map>
-#include <set>
-#include "framebuffer.h"
-#include "renderable.h"
-#include "renderbuffer.h"
-#include "rendertarget.h"
-#include "texture2d.h"
-
-namespace Msp {
-namespace GL {
-
-class Blend;
-class Camera;
-class Clipping;
-class DepthTest;
-class Lighting;
-class PostProcessor;
-class View;
-
-/**
-Top-level content class. Typically a Pipeline is used as the content
-Renderable for a View or effects such as ShadowMap or EnvironmentMap.
-
-A Pipeline contains a sequence of passes. Each pass has a Renderable along
-with Lighting, Clipping, DepthTest and Blend states. Scenes can be used to
-organize Renderables within a pass.
-
-PostProcessors can be applied after all of the passes in the Pipeline have been
-rendered. Framebuffer objects are automatically used to pass render results to
-the PostProcessors. High dynamic range and multisample rendering can be
-requested for increased quality.
-*/
-class Pipeline: public Renderable
-{
-public:
- class Pass
- {
- private:
- Tag tag;
- const Lighting *lighting;
- const DepthTest *depth_test;
- const Blend *blend;
- const Clipping *clipping;
- Renderable *renderable;
-
- public:
- Pass(Tag, 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_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 Clipping *get_clipping() const { return clipping; }
- Renderable *get_renderable() const { return renderable; }
- };
-
-private:
- struct Slot
- {
- Renderable *renderable;
- std::set<Tag> passes;
-
- Slot(Renderable *);
- };
-
- typedef std::list<Pass> PassList;
-
- PassList passes;
- const Camera *camera;
- std::vector<Slot> renderables;
- std::vector<RefPtr<PostProcessor> > postproc;
- unsigned width;
- unsigned height;
- bool hdr;
- bool alpha;
- unsigned samples;
- RenderTarget *target[2];
- RenderTarget *target_ms;
-
-public:
- Pipeline(unsigned, unsigned, bool = false);
- Pipeline(const View &);
- Pipeline(const Framebuffer &);
-private:
- void init(unsigned, unsigned);
-public:
- ~Pipeline();
-
- /* Sets high dynamic range mode. Requires floating-point texture support.
- A ColorCurve postprocessor is recommended for full benefit. */
- void set_hdr(bool);
-
- /* Enable or disable alpha channel. When enabled, all render targets are
- created with an RGBA pixel format instead of RGB. */
- void set_alpha(bool);
-
- void set_multisample(unsigned);
-
- unsigned get_width() const { return width; }
- unsigned get_height() const { return height; }
- bool get_hdr() const { return hdr; }
- unsigned get_multisample() const { return samples; }
-
- /** Adds a pass to the pipeline. It's permissible to add the same
- Renderable multiple times. */
- Pass &add_pass(Tag, Renderable &);
-
- /** Adds a postprocessor to the pipeline. */
- void add_postprocessor(PostProcessor &);
-
- /** Adds a postprocessor to the pipeline, transferring ownership. The
- postprocessor will be deleted together with with pipeline. It is also
- deleted if this call throws an exception. */
- void add_postprocessor_owned(PostProcessor *);
-
-private:
- void add_postprocessor(PostProcessor *, bool);
-
-public:
- virtual void setup_frame(Renderer &);
- virtual void finish_frame();
-
- virtual void render(Renderer &, Tag tag = Tag()) const;
-
-private:
- void create_targets(unsigned);
-};
-
-} // namespace GL
-} // namespace Msp
-
-#endif
--- /dev/null
+#include <msp/core/maputils.h>
+#include "blend.h"
+#include "camera.h"
+#include "framebuffer.h"
+#include "lighting.h"
+#include "postprocessor.h"
+#include "renderbuffer.h"
+#include "renderer.h"
+#include "sequence.h"
+#include "tests.h"
+#include "texture2d.h"
+#include "view.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+Sequence::Sequence(unsigned w, unsigned h, bool d)
+{
+ init(w, h);
+ hdr = d;
+}
+
+Sequence::Sequence(const View &view)
+{
+ init(view.get_width(), view.get_height());
+}
+
+Sequence::Sequence(const Framebuffer &fbo)
+{
+ init(fbo.get_width(), fbo.get_height());
+}
+
+void Sequence::init(unsigned w, unsigned h)
+{
+ camera = 0;
+ width = w;
+ height = h;
+ hdr = false;
+ alpha = false;
+ samples = 0;
+ target_ms = 0;
+ target[0] = 0;
+ target[1] = 0;
+}
+
+Sequence::~Sequence()
+{
+ delete target[0];
+ delete target[1];
+ delete target_ms;
+}
+
+void Sequence::set_hdr(bool h)
+{
+ if(h==hdr)
+ return;
+
+ bool old_hdr = hdr;
+ hdr = h;
+ try
+ {
+ create_targets(2);
+ }
+ catch(...)
+ {
+ hdr = old_hdr;
+ throw;
+ }
+}
+
+void Sequence::set_alpha(bool a)
+{
+ if(a==alpha)
+ return;
+
+ bool old_alpha = alpha;
+ alpha = a;
+ try
+ {
+ create_targets(2);
+ }
+ catch(...)
+ {
+ alpha = old_alpha;
+ throw;
+ }
+}
+
+void Sequence::set_multisample(unsigned s)
+{
+ if(s==samples)
+ return;
+
+ unsigned old_samples = samples;
+ samples = s;
+ try
+ {
+ create_targets(1);
+ }
+ catch(...)
+ {
+ samples = old_samples;
+ throw;
+ }
+}
+
+Sequence::Step &Sequence::add_step(Tag tag, Renderable &r)
+{
+ steps.push_back(Step(tag, &r));
+ return steps.back();
+}
+
+void Sequence::add_postprocessor(PostProcessor &pp)
+{
+ add_postprocessor(&pp, true);
+}
+
+void Sequence::add_postprocessor_owned(PostProcessor *pp)
+{
+ add_postprocessor(pp, false);
+}
+
+void Sequence::add_postprocessor(PostProcessor *pp, bool keep)
+{
+ postproc.push_back(pp);
+ if(keep)
+ postproc.back().keep();
+ try
+ {
+ create_targets(0);
+ }
+ catch(...)
+ {
+ postproc.pop_back();
+ throw;
+ }
+}
+
+void Sequence::setup_frame(Renderer &renderer)
+{
+ for(StepList::const_iterator i=steps.begin(); i!=steps.end(); ++i)
+ if(Renderable *renderable = i->get_renderable())
+ renderable->setup_frame(renderer);
+ for(vector<Slot>::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
+ i->renderable->setup_frame(renderer);
+}
+
+void Sequence::finish_frame()
+{
+ for(StepList::const_iterator i=steps.begin(); i!=steps.end(); ++i)
+ if(Renderable *renderable = i->get_renderable())
+ renderable->finish_frame();
+ for(vector<Slot>::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
+ i->renderable->finish_frame();
+}
+
+void Sequence::render(Renderer &renderer, Tag tag) const
+{
+ if(tag.id)
+ return;
+
+ 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])
+ {
+ Framebuffer &fbo = (samples ? target_ms : target[0])->get_framebuffer();
+ fbo.bind();
+ fbo.clear();
+ }
+
+ for(StepList::const_iterator i=steps.begin(); i!=steps.end(); ++i)
+ {
+ if(const DepthTest *dt = i->get_depth_test())
+ dt->bind();
+ else
+ DepthTest::unbind();
+
+ if(const Blend *b = i->get_blend())
+ b->bind();
+ else
+ Blend::unbind();
+
+ renderer.set_lighting(i->get_lighting());
+ renderer.set_clipping(i->get_clipping());
+
+ if(const Renderable *renderable = i->get_renderable())
+ renderer.render(*renderable, i->get_tag());
+
+ for(vector<Slot>::const_iterator j=renderables.begin(); j!=renderables.end(); ++j)
+ if(j->passes.empty() || j->passes.count(i->get_tag()))
+ renderer.render(*j->renderable, i->get_tag());
+ }
+
+ if(target[0])
+ {
+ DepthTest::unbind();
+ Blend::unbind();
+
+ if(samples)
+ target[0]->blit_from(*target_ms);
+
+ for(unsigned i=0; i<postproc.size(); ++i)
+ {
+ unsigned j = i%2;
+ if(i+1<postproc.size())
+ target[1-j]->get_framebuffer().bind();
+ else
+ out_fbo->bind();
+ const Texture2D &color = target[j]->get_target_texture(RENDER_COLOR);
+ const Texture2D &depth = target[j]->get_target_texture(RENDER_DEPTH);
+ postproc[i]->render(renderer, color, depth);
+ }
+ }
+}
+
+void Sequence::create_targets(unsigned recreate)
+{
+ if(recreate>=2)
+ {
+ delete target[0];
+ delete target[1];
+ target[0] = 0;
+ target[1] = 0;
+ }
+ if(recreate>=1)
+ {
+ delete target_ms;
+ target_ms = 0;
+ }
+
+ PixelFormat color_pf = (hdr ? (alpha ? RGBA16F : RGB16F) : (alpha ? RGBA8 : RGB8));
+ RenderTargetFormat fmt = (RENDER_COLOR,color_pf, RENDER_DEPTH);
+ if(!postproc.empty() || samples)
+ {
+ if(!target[0])
+ target[0] = new RenderTarget(width, height, fmt);
+ if(!target[1] && postproc.size()>1)
+ target[1] = new RenderTarget(width, height, fmt);
+ }
+
+ if(!target_ms && samples)
+ target_ms = new RenderTarget(width, height, samples, fmt);
+}
+
+
+Sequence::Step::Step(Tag t, Renderable *r):
+ tag(t),
+ lighting(0),
+ depth_test(0),
+ blend(0),
+ clipping(0),
+ renderable(r)
+{ }
+
+void Sequence::Step::set_lighting(const Lighting *l)
+{
+ lighting = l;
+}
+
+void Sequence::Step::set_depth_test(const DepthTest *d)
+{
+ depth_test = d;
+}
+
+void Sequence::Step::set_blend(const Blend *b)
+{
+ blend = b;
+}
+
+void Sequence::Step::set_clipping(const Clipping *c)
+{
+ clipping =c;
+}
+
+
+Sequence::Slot::Slot(Renderable *r):
+ renderable(r)
+{ }
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GL_SEQUENCE_H_
+#define MSP_GL_SEQUENCE_H_
+
+#include <map>
+#include <set>
+#include "framebuffer.h"
+#include "renderable.h"
+#include "renderbuffer.h"
+#include "rendertarget.h"
+#include "texture2d.h"
+
+namespace Msp {
+namespace GL {
+
+class Blend;
+class Camera;
+class Clipping;
+class DepthTest;
+class Lighting;
+class PostProcessor;
+class View;
+
+/**
+Top-level content class. Typically a Sequence is used as the content
+Renderable for a View or effects such as ShadowMap or EnvironmentMap.
+
+A Sequence consists of a number of steps. Each step is defined with a
+Renderable and a tag to render it with and may also have Lighting, Clipping,
+DepthTest and Blend states. Scenes can be used to further organize Renderables
+within a step.
+
+PostProcessors can be applied after all of the steps in the Sequence have been
+processed. Framebuffer objects are automatically used to pass render results
+to the PostProcessors. High dynamic range and multisample rendering can be
+requested for increased quality.
+*/
+class Sequence: public Renderable
+{
+public:
+ class Step
+ {
+ private:
+ Tag tag;
+ const Lighting *lighting;
+ const DepthTest *depth_test;
+ const Blend *blend;
+ const Clipping *clipping;
+ Renderable *renderable;
+
+ public:
+ Step(Tag, 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_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 Clipping *get_clipping() const { return clipping; }
+ Renderable *get_renderable() const { return renderable; }
+ };
+
+ DEPRECATED typedef Step Pass;
+
+private:
+ struct Slot
+ {
+ Renderable *renderable;
+ std::set<Tag> passes;
+
+ Slot(Renderable *);
+ };
+
+ typedef std::list<Step> StepList;
+
+ StepList steps;
+ const Camera *camera;
+ std::vector<Slot> renderables;
+ std::vector<RefPtr<PostProcessor> > postproc;
+ unsigned width;
+ unsigned height;
+ bool hdr;
+ bool alpha;
+ unsigned samples;
+ RenderTarget *target[2];
+ RenderTarget *target_ms;
+
+public:
+ Sequence(unsigned, unsigned, bool = false);
+ Sequence(const View &);
+ Sequence(const Framebuffer &);
+private:
+ void init(unsigned, unsigned);
+public:
+ ~Sequence();
+
+ /* Sets high dynamic range mode. Requires floating-point texture support.
+ A ColorCurve postprocessor is recommended for full benefit. */
+ void set_hdr(bool);
+
+ /* Enable or disable alpha channel. When enabled, all render targets are
+ created with an RGBA pixel format instead of RGB. */
+ void set_alpha(bool);
+
+ void set_multisample(unsigned);
+
+ unsigned get_width() const { return width; }
+ unsigned get_height() const { return height; }
+ bool get_hdr() const { return hdr; }
+ unsigned get_multisample() const { return samples; }
+
+ /** Adds a step to the sequence. It's permissible to add the same
+ Renderable multiple times. */
+ Step &add_step(Tag, Renderable &);
+
+ DEPRECATED Step &add_pass(Tag t, Renderable &r) { return add_step(t, r); }
+
+ /** Adds a postprocessor to the sequence. */
+ void add_postprocessor(PostProcessor &);
+
+ /** Adds a postprocessor to the sequence, transferring ownership. The
+ postprocessor will be deleted together with with sequence. It is also
+ deleted if this call throws an exception. */
+ void add_postprocessor_owned(PostProcessor *);
+
+private:
+ void add_postprocessor(PostProcessor *, bool);
+
+public:
+ virtual void setup_frame(Renderer &);
+ virtual void finish_frame();
+
+ virtual void render(Renderer &, Tag tag = Tag()) const;
+
+private:
+ void create_targets(unsigned);
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
#include "mesh.h"
#include "module.h"
#include "object.h"
-#include "pipelinetemplate.h"
+#include "sequencetemplate.h"
#include "pose.h"
#include "program.h"
#include "resourcemanager.h"
add_type<Mesh>().keyword("mesh").creator(&Resources::create_mesh);
add_type<Module>().suffix(".glsl").suffix(".spv").creator(&Resources::create_module);
add_type<Object>().keyword("object");
- add_type<PipelineTemplate>().suffix(".pipe").keyword("pipeline");
+ add_type<SequenceTemplate>().suffix(".seq").keyword("sequence");
add_type<Pose>().keyword("pose");
add_type<Program>().keyword("shader").creator(&Resources::create_program);
add_type<Sampler>().suffix(".samp").keyword("sampler");
#include <msp/gl/lighting.h>
#include <msp/gl/mesh.h>
#include <msp/gl/object.h>
-#include <msp/gl/pipeline.h>
+#include <msp/gl/sequence.h>
#include <msp/gl/renderer.h>
#include <msp/gl/resources.h>
#include <msp/gl/simplescene.h>
Input::Mouse mouse;
Resources resources;
GL::WindowView view;
- GL::Pipeline pipeline;
+ GL::Sequence sequence;
GL::Renderable *renderable;
GL::AnimatedObject *anim_object;
GL::AnimationPlayer *anim_player;
gl_ctx(window, opts.gl_opts),
mouse(window),
view(window, gl_ctx),
- pipeline(view),
+ sequence(view),
renderable(0),
anim_object(0),
anim_player(0),
camera.set_up_direction(GL::Vector3(0, 0, 1));
update_camera();
- GL::Pipeline::Pass &pass = pipeline.add_pass(0, *renderable);
- pass.set_lighting(&lighting);
- pass.set_depth_test(&GL::DepthTest::lequal());
- pass.set_blend(&GL::Blend::alpha());
+ 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());
- view.set_content(&pipeline);
+ view.set_content(&sequence);
view.set_camera(&camera);
}