From: Mikko Rasa Date: Wed, 14 Apr 2021 11:42:11 +0000 (+0300) Subject: Rename Pipeline to Sequence X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=commitdiff_plain;h=dff7004fa078d55911664c0f513b5dc6c9449420 Rename Pipeline to Sequence Pipeline::Pass is now Sequence::Step. These better match what the classes do. --- diff --git a/demos/desertpillars.cpp b/demos/desertpillars.cpp index 89a0fe51..d741beea 100644 --- a/demos/desertpillars.cpp +++ b/demos/desertpillars.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -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 index 12a5312f..00000000 --- a/source/builders/pipelinebuilder.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include -#include -#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 &passes = tmpl.get_passes(); - for(vector::const_iterator i=passes.begin(); i!=passes.end(); ++i) - renderables[i->renderable_name] = 0; - const vector &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(samplesrenderable_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 = new Pipeline(w, h); - build(*pipeline); - return pipeline.release(); -} - -Pipeline *PipelineBuilder::build(const View &view) const -{ - RefPtr pipeline = new Pipeline(view); - build(*pipeline); - return pipeline.release(); -} - -Pipeline *PipelineBuilder::build(const Framebuffer &fbo) const -{ - RefPtr 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 index ab0dc4b9..00000000 --- a/source/builders/pipelinebuilder.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef PIPELINEBUILDER_H_ -#define PIPELINEBUILDER_H_ - -#include -#include - -namespace Msp { -namespace GL { - -class Framebuffer; -class Pipeline; -class PipelineTemplate; -class PostProcessor; -class Renderable; -class View; - -class PipelineBuilder -{ -private: - const PipelineTemplate &tmpl; - std::map renderables; - std::map 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 index de91450e..00000000 --- a/source/builders/pipelinetemplate.cpp +++ /dev/null @@ -1,202 +0,0 @@ -#include -#include -#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("ambient_occlusion"); - registry.register_type("bloom"); - registry.register_type("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(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(p, 0) -{ - init(); -} - -PipelineTemplate::Pass::Loader::Loader(Pass &p, Collection &c): - DataFile::CollectionObjectLoader(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 lightn = new Lighting; - load_sub(*lightn); - obj.lighting = lightn; -} - -void PipelineTemplate::Pass::Loader::lighting(const string &name) -{ - obj.lighting = &get_collection().get(name); - obj.lighting.keep(); -} - -/*void PipelineTemplate::Pass::Loader::scene(const string &name) -{ - obj.default_renderable = get_collection().get(name); -}*/ - -} // namespace GL -} // namespace Msp diff --git a/source/builders/pipelinetemplate.h b/source/builders/pipelinetemplate.h deleted file mode 100644 index 515ebfaf..00000000 --- a/source/builders/pipelinetemplate.h +++ /dev/null @@ -1,152 +0,0 @@ -#ifndef PIPELINETEMPLATE_H_ -#define PIPELINETEMPLATE_H_ - -#include -#include -#include -#include -#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 - struct AddPostProc - { - void operator()(const std::string &kw, PostProcLoader &ldr) const { ldr.add(kw, &PostProcLoader::postprocessor); } - }; - - protected: - RefPtr postproc; - - public: - PostProcLoader(); - - PostProcessor::Template *get_postprocessor_template() { return postproc.release(); } - - protected: - virtual void postprocessor_loaded() { } - - private: - template - void postprocessor(); - - friend class PipelineTemplate; - }; - -public: - class Loader: public DataFile::CollectionObjectLoader, 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 - { - 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; - RefPtr depth_test; - RefPtr 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 PassArray; - typedef std::vector PostProcessorArray; - -private: - typedef TypeRegistry 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 - static void register_postprocessor(const std::string &); -private: - static PostProcessorRegistry &get_postprocessor_registry(); -}; - -template -void PipelineTemplate::register_postprocessor(const std::string &kw) -{ - get_postprocessor_registry().register_type(kw); -} - -template -void PipelineTemplate::PostProcLoader::postprocessor() -{ - if(postproc) - throw std::logic_error("Only one postprocessor allowed per slot"); - RefPtr 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 index 00000000..0f2a1b54 --- /dev/null +++ b/source/builders/sequencebuilder.cpp @@ -0,0 +1,98 @@ +#include +#include +#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 &steps = tmpl.get_steps(); + for(vector::const_iterator i=steps.begin(); i!=steps.end(); ++i) + renderables[i->renderable_name] = 0; + const vector &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 &steps = tmpl.get_steps(); + for(vector::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 = new Sequence(w, h); + build(*sequence); + return sequence.release(); +} + +Sequence *SequenceBuilder::build(const View &view) const +{ + RefPtr sequence = new Sequence(view); + build(*sequence); + return sequence.release(); +} + +Sequence *SequenceBuilder::build(const Framebuffer &fbo) const +{ + RefPtr 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 index 00000000..739cc5ed --- /dev/null +++ b/source/builders/sequencebuilder.h @@ -0,0 +1,39 @@ +#ifndef SEQUENCEBUILDER_H_ +#define SEQUENCEBUILDER_H_ + +#include +#include + +namespace Msp { +namespace GL { + +class Framebuffer; +class Sequence; +class SequenceTemplate; +class PostProcessor; +class Renderable; +class View; + +class SequenceBuilder +{ +private: + const SequenceTemplate &tmpl; + std::map renderables; + std::map 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 index 00000000..bfab2804 --- /dev/null +++ b/source/builders/sequencetemplate.cpp @@ -0,0 +1,205 @@ +#include +#include +#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("ambient_occlusion"); + registry.register_type("bloom"); + registry.register_type("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(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(p, 0) +{ + init(); +} + +SequenceTemplate::Step::Loader::Loader(Step &p, Collection &c): + DataFile::CollectionObjectLoader(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 lightn = new Lighting; + load_sub(*lightn); + obj.lighting = lightn; +} + +void SequenceTemplate::Step::Loader::lighting(const string &name) +{ + obj.lighting = &get_collection().get(name); + obj.lighting.keep(); +} + +/*void SequenceTemplate::Step::Loader::scene(const string &name) +{ + obj.default_renderable = get_collection().get(name); +}*/ + +} // namespace GL +} // namespace Msp diff --git a/source/builders/sequencetemplate.h b/source/builders/sequencetemplate.h new file mode 100644 index 00000000..5c5b04b5 --- /dev/null +++ b/source/builders/sequencetemplate.h @@ -0,0 +1,151 @@ +#ifndef SEQUENCETEMPLATE_H_ +#define SEQUENCETEMPLATE_H_ + +#include +#include +#include +#include +#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 + struct AddPostProc + { + void operator()(const std::string &kw, PostProcLoader &ldr) const { ldr.add(kw, &PostProcLoader::postprocessor); } + }; + + protected: + RefPtr postproc; + + public: + PostProcLoader(); + + PostProcessor::Template *get_postprocessor_template() { return postproc.release(); } + + protected: + virtual void postprocessor_loaded() { } + + private: + template + void postprocessor(); + + friend class SequenceTemplate; + }; + +public: + class Loader: public DataFile::CollectionObjectLoader, 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 + { + 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; + RefPtr depth_test; + RefPtr 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 PostProcessorArray; + +private: + typedef TypeRegistry PostProcessorRegistry; + + Resources *resources; + bool hdr; + bool alpha; + unsigned required_multisample; + unsigned max_multisample; + std::vector 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 &get_steps() const { return steps; } + const PostProcessorArray &get_postprocessors() const { return postprocessors; } + + template + static void register_postprocessor(const std::string &); +private: + static PostProcessorRegistry &get_postprocessor_registry(); +}; + +template +void SequenceTemplate::register_postprocessor(const std::string &kw) +{ + get_postprocessor_registry().register_type(kw); +} + +template +void SequenceTemplate::PostProcLoader::postprocessor() +{ + if(postproc) + throw std::logic_error("Only one postprocessor allowed per slot"); + RefPtr pp = new typename T::Template; + load_sub(*pp); + postproc = pp; + pp = 0; + postprocessor_loaded(); +} + +} // namespace GL +} // namespace Msp + +#endif diff --git a/source/effects/environmentmap.h b/source/effects/environmentmap.h index bd6800a6..a13bea3f 100644 --- a/source/effects/environmentmap.h +++ b/source/effects/environmentmap.h @@ -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 diff --git a/source/materials/light.h b/source/materials/light.h index e94f3c5a..c7e28188 100644 --- a/source/materials/light.h +++ b/source/materials/light.h @@ -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 index 21f9e85e..00000000 --- a/source/render/pipeline.cpp +++ /dev/null @@ -1,287 +0,0 @@ -#include -#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::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::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::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; iget_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 index 91996186..00000000 --- a/source/render/pipeline.h +++ /dev/null @@ -1,140 +0,0 @@ -#ifndef MSP_GL_PIPELINE_H_ -#define MSP_GL_PIPELINE_H_ - -#include -#include -#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 passes; - - Slot(Renderable *); - }; - - typedef std::list PassList; - - PassList passes; - const Camera *camera; - std::vector renderables; - std::vector > 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 index 00000000..6898e668 --- /dev/null +++ b/source/render/sequence.cpp @@ -0,0 +1,287 @@ +#include +#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::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::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::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; iget_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 index 00000000..97d376d1 --- /dev/null +++ b/source/render/sequence.h @@ -0,0 +1,145 @@ +#ifndef MSP_GL_SEQUENCE_H_ +#define MSP_GL_SEQUENCE_H_ + +#include +#include +#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 passes; + + Slot(Renderable *); + }; + + typedef std::list StepList; + + StepList steps; + const Camera *camera; + std::vector renderables; + std::vector > 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 diff --git a/source/resources/resources.cpp b/source/resources/resources.cpp index dca3e8d3..e83f33eb 100644 --- a/source/resources/resources.cpp +++ b/source/resources/resources.cpp @@ -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().keyword("mesh").creator(&Resources::create_mesh); add_type().suffix(".glsl").suffix(".spv").creator(&Resources::create_module); add_type().keyword("object"); - add_type().suffix(".pipe").keyword("pipeline"); + add_type().suffix(".seq").keyword("sequence"); add_type().keyword("pose"); add_type().keyword("shader").creator(&Resources::create_program); add_type().suffix(".samp").keyword("sampler"); diff --git a/tools/viewer.cpp b/tools/viewer.cpp index 4ae9c87b..ffdc4ec6 100644 --- a/tools/viewer.cpp +++ b/tools/viewer.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include @@ -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); }