]> git.tdb.fi Git - libs/gl.git/commitdiff
Rename Pipeline to Sequence
authorMikko Rasa <tdb@tdb.fi>
Wed, 14 Apr 2021 11:42:11 +0000 (14:42 +0300)
committerMikko Rasa <tdb@tdb.fi>
Wed, 14 Apr 2021 12:24:27 +0000 (15:24 +0300)
Pipeline::Pass is now Sequence::Step.  These better match what the
classes do.

17 files changed:
demos/desertpillars.cpp
source/builders/pipelinebuilder.cpp [deleted file]
source/builders/pipelinebuilder.h [deleted file]
source/builders/pipelinetemplate.cpp [deleted file]
source/builders/pipelinetemplate.h [deleted file]
source/builders/sequencebuilder.cpp [new file with mode: 0644]
source/builders/sequencebuilder.h [new file with mode: 0644]
source/builders/sequencetemplate.cpp [new file with mode: 0644]
source/builders/sequencetemplate.h [new file with mode: 0644]
source/effects/environmentmap.h
source/materials/light.h
source/render/pipeline.cpp [deleted file]
source/render/pipeline.h [deleted file]
source/render/sequence.cpp [new file with mode: 0644]
source/render/sequence.h [new file with mode: 0644]
source/resources/resources.cpp
tools/viewer.cpp

index 89a0fe51333c9d97cd31d22b54dd6a57bbc9c9a7..d741beea5390b0eb8307fdb78d401fb47c62b314 100644 (file)
@@ -17,7 +17,7 @@
 #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>
@@ -46,7 +46,7 @@ including:
 - 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
@@ -132,7 +132,7 @@ private:
        GL::EnvironmentMap *env_cube;
 
        GL::WindowView view;
-       GL::Pipeline pipeline;
+       GL::Sequence sequence;
        GL::Camera camera;
        GL::SimpleScene sky_scene;
        GL::InstanceScene scene;
@@ -142,7 +142,7 @@ private:
        GL::Bloom bloom;
        GL::ColorCurve colorcurve;
 
-       GL::Pipeline env_pipeline;
+       GL::Sequence env_sequence;
 
        Time::TimeStamp last_tick;
        float camera_angle;
@@ -166,7 +166,7 @@ public:
 
 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();
@@ -299,11 +299,11 @@ DesertPillars::DesertPillars(int argc, char **argv):
        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),
@@ -319,7 +319,7 @@ DesertPillars::DesertPillars(int argc, char **argv):
        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();
@@ -340,13 +340,13 @@ void DesertPillars::setup_view()
        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
@@ -362,26 +362,26 @@ void DesertPillars::create_pipeline()
        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());
 }
@@ -778,7 +778,7 @@ void DesertPillars::create_cube()
        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);
 }
 
diff --git a/source/builders/pipelinebuilder.cpp b/source/builders/pipelinebuilder.cpp
deleted file mode 100644 (file)
index 12a5312..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-#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
diff --git a/source/builders/pipelinebuilder.h b/source/builders/pipelinebuilder.h
deleted file mode 100644 (file)
index ab0dc4b..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#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
diff --git a/source/builders/pipelinetemplate.cpp b/source/builders/pipelinetemplate.cpp
deleted file mode 100644 (file)
index de91450..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-#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
diff --git a/source/builders/pipelinetemplate.h b/source/builders/pipelinetemplate.h
deleted file mode 100644 (file)
index 515ebfa..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-#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
diff --git a/source/builders/sequencebuilder.cpp b/source/builders/sequencebuilder.cpp
new file mode 100644 (file)
index 0000000..0f2a1b5
--- /dev/null
@@ -0,0 +1,98 @@
+#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
diff --git a/source/builders/sequencebuilder.h b/source/builders/sequencebuilder.h
new file mode 100644 (file)
index 0000000..739cc5e
--- /dev/null
@@ -0,0 +1,39 @@
+#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
diff --git a/source/builders/sequencetemplate.cpp b/source/builders/sequencetemplate.cpp
new file mode 100644 (file)
index 0000000..bfab280
--- /dev/null
@@ -0,0 +1,205 @@
+#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
diff --git a/source/builders/sequencetemplate.h b/source/builders/sequencetemplate.h
new file mode 100644 (file)
index 0000000..5c5b04b
--- /dev/null
@@ -0,0 +1,151 @@
+#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
index bd6800a6f16da78b299b1cec3af3435fd678b97b..a13bea3faeeea6eaea41e1d594700c48437a16b1 100644 (file)
@@ -19,9 +19,9 @@ class Resources;
 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
index e94f3c5aca8b333c5a73f6c31082cd2d0afa34a3..c7e281887651c7f3d5495f86c34960055d9429e9 100644 (file)
@@ -21,7 +21,7 @@ is not 180 degrees, it's a spotlight.  Otherwise it's an omnidirectional point
 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.
 */
diff --git a/source/render/pipeline.cpp b/source/render/pipeline.cpp
deleted file mode 100644 (file)
index 21f9e85..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-#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
diff --git a/source/render/pipeline.h b/source/render/pipeline.h
deleted file mode 100644 (file)
index 9199618..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-#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
diff --git a/source/render/sequence.cpp b/source/render/sequence.cpp
new file mode 100644 (file)
index 0000000..6898e66
--- /dev/null
@@ -0,0 +1,287 @@
+#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
diff --git a/source/render/sequence.h b/source/render/sequence.h
new file mode 100644 (file)
index 0000000..97d376d
--- /dev/null
@@ -0,0 +1,145 @@
+#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
index dca3e8d3d82158947b33ae743a3deb0cf6ecf0ee..e83f33eb529078f80c1bd08d426c40dc49a9a08e 100644 (file)
@@ -10,7 +10,7 @@
 #include "mesh.h"
 #include "module.h"
 #include "object.h"
-#include "pipelinetemplate.h"
+#include "sequencetemplate.h"
 #include "pose.h"
 #include "program.h"
 #include "resourcemanager.h"
@@ -48,7 +48,7 @@ Resources::Resources():
        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");
index 4ae9c87b26c7483bdb1ad7c4fd2b1637d5d80aa0..ffdc4ec6eb513e4ad2955ddfedc8004f53032692 100644 (file)
@@ -16,7 +16,7 @@
 #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>
@@ -65,7 +65,7 @@ private:
        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;
@@ -121,7 +121,7 @@ Viewer::Viewer(int argc, char **argv):
        gl_ctx(window, opts.gl_opts),
        mouse(window),
        view(window, gl_ctx),
-       pipeline(view),
+       sequence(view),
        renderable(0),
        anim_object(0),
        anim_player(0),
@@ -212,12 +212,12 @@ Viewer::Viewer(int argc, char **argv):
        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);
 }