]> git.tdb.fi Git - libs/gl.git/commitdiff
Add a system for creating Pipelines from loadable templates
authorMikko Rasa <tdb@tdb.fi>
Tue, 19 Dec 2017 16:24:48 +0000 (18:24 +0200)
committerMikko Rasa <tdb@tdb.fi>
Tue, 19 Dec 2017 16:24:48 +0000 (18:24 +0200)
13 files changed:
source/bloom.cpp
source/bloom.h
source/colorcurve.cpp
source/colorcurve.h
source/pipeline.cpp
source/pipeline.h
source/pipelinebuilder.cpp [new file with mode: 0644]
source/pipelinebuilder.h [new file with mode: 0644]
source/pipelinetemplate.cpp [new file with mode: 0644]
source/pipelinetemplate.h [new file with mode: 0644]
source/postprocessor.cpp
source/postprocessor.h
source/resources.cpp

index 7537b0a6a80711fdcb1ff6cfc9b005b60d27fecc..e00fd0e149bc0c8bc5ad9c74d0a13522c2124d76 100644 (file)
@@ -84,5 +84,27 @@ void Bloom::render(Renderer &renderer, const Texture2D &src, const Texture2D &)
        quad.draw(renderer);
 }
 
+
+Bloom::Template::Template():
+       radius(2.0f),
+       strength(0.2f)
+{ }
+
+Bloom *Bloom::Template::create(unsigned width, unsigned height) const
+{
+       RefPtr<Bloom> bloom = new Bloom(width/size_divisor, height/size_divisor);
+       bloom->set_radius(radius);
+       bloom->set_strength(strength);
+       return bloom.release();
+}
+
+
+Bloom::Template::Loader::Loader(Template &t):
+       DataFile::DerivedObjectLoader<Template, PostProcessor::Template::Loader>(t)
+{
+       add("strength", &Template::strength);
+       add("radius", &Template::radius);
+}
+
 } // namespace GL
 } // namespace Msp
index b3841c73318b65b698cb5ec437372a5feaae1d86..d8bb61acd24ed8f9d1d643683754ab314b57b74e 100644 (file)
@@ -23,6 +23,23 @@ a blur filter.
 */
 class Bloom: public PostProcessor
 {
+public:
+       struct Template: public PostProcessor::Template
+       {
+               class Loader: public DataFile::DerivedObjectLoader<Template, PostProcessor::Template::Loader>
+               {
+               public:
+                       Loader(Template &);
+               };
+
+               float radius;
+               float strength;
+
+               Template();
+
+               virtual Bloom *create(unsigned, unsigned) const;
+       };
+
 private:
        RenderTarget *target[2];
        ProgramData common_shdata;
index f1c090308458b4edbf9360d5018a80d817389471..40f61b813dd088171beeea361b92dc91dac11a6e 100644 (file)
@@ -88,5 +88,46 @@ void ColorCurve::render(Renderer &renderer, const Texture2D &color_buf, const Te
        quad.draw(renderer);
 }
 
+
+ColorCurve::Template::Template():
+       exposure_adjust(0.0f),
+       brightness_response(0.4f),
+       gamma(1.0f),
+       srgb(false)
+{ }
+
+ColorCurve *ColorCurve::Template::create(unsigned, unsigned) const
+{
+       RefPtr<ColorCurve> colorcurve = new ColorCurve;
+       colorcurve->set_exposure_adjust(exposure_adjust);
+       colorcurve->set_brightness_response(brightness_response);
+       if(srgb)
+               colorcurve->set_srgb();
+       else
+               colorcurve->set_gamma(gamma);
+       return colorcurve.release();
+}
+
+
+ColorCurve::Template::Loader::Loader(Template &t):
+       DataFile::DerivedObjectLoader<Template, PostProcessor::Template::Loader>(t)
+{
+       add("brightness_response", &Template::brightness_response);
+       add("exposure_adjust", &Template::exposure_adjust);
+       add("gamma", &Loader::gamma);
+       add("srgb", &Loader::srgb);
+}
+
+void ColorCurve::Template::Loader::gamma(float g)
+{
+       obj.gamma = g;
+       obj.srgb = false;
+}
+
+void ColorCurve::Template::Loader::srgb()
+{
+       obj.srgb = true;
+}
+
 } // namespace GL
 } // namespace Msp
index 608af44888ce9edcc3030d135cac98abb3728772..dac0ac08ab689382ace03041070d4db77ec873e2 100644 (file)
@@ -21,6 +21,29 @@ space and converting to sRGB for display.
 */
 class ColorCurve: public PostProcessor
 {
+public:
+       struct Template: public PostProcessor::Template
+       {
+               class Loader: public DataFile::DerivedObjectLoader<Template, PostProcessor::Template::Loader>
+               {
+               public:
+                       Loader(Template &);
+
+               private:
+                       void gamma(float);
+                       void srgb();
+               };
+
+               float exposure_adjust;
+               float brightness_response;
+               float gamma;
+               bool srgb;
+
+               Template();
+
+               virtual ColorCurve *create(unsigned, unsigned) const;
+       };
+
 private:
        Program shprog;
        ProgramData shdata;
index 9e2976ab69e5dc4e383c413be18c9239ac786a94..037741d24e4e1bfa0372c09943c1509cfad5b115 100644 (file)
@@ -136,7 +136,19 @@ Pipeline::Pass &Pipeline::add_pass(const Tag &tag, Renderable &r)
 
 void Pipeline::add_postprocessor(PostProcessor &pp)
 {
-       postproc.push_back(&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);
@@ -192,7 +204,6 @@ void Pipeline::render(Renderer &renderer, const Tag &tag) const
                fbo.clear(COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT);
        }
 
-
        for(PassList::const_iterator i=passes.begin(); i!=passes.end(); ++i)
        {
                if(const DepthTest *dt = i->get_depth_test())
index 35d10a41c6f5a6f3521ade05f0066a4218bebbb3..9ac03efbb9989d4b2d462d689346f348ab299615 100644 (file)
@@ -76,7 +76,7 @@ private:
        PassList passes;
        const Camera *camera;
        std::vector<Slot> renderables;
-       std::vector<PostProcessor *> postproc;
+       std::vector<RefPtr<PostProcessor> > postproc;
        unsigned width;
        unsigned height;
        bool hdr;
@@ -98,6 +98,11 @@ public:
 
        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; }
+
        // Deprecated
        void set_camera(const Camera *);
        Pass &add_pass(const Tag &tag);
@@ -112,6 +117,15 @@ public:
        /** 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();
 
diff --git a/source/pipelinebuilder.cpp b/source/pipelinebuilder.cpp
new file mode 100644 (file)
index 0000000..cbf181f
--- /dev/null
@@ -0,0 +1,65 @@
+#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;
+}
+
+void PipelineBuilder::set_renderable(const string &name, Renderable &rend)
+{
+       get_item(renderables, name) = &rend;
+}
+
+void PipelineBuilder::build(Pipeline &pipeline) const
+{
+       pipeline.set_hdr(tmpl.get_hdr());
+       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 = (*i)->create(pipeline.get_width(), pipeline.get_height());
+               pipeline.add_postprocessor_owned(proc);
+       }
+}
+
+Pipeline *PipelineBuilder::build(const View &view) const
+{
+       RefPtr<Pipeline> pipeline = new Pipeline(view);
+       build(*pipeline);
+       return pipeline.release();
+}
+
+} // namespace GL
+} // namespace Msp
diff --git a/source/pipelinebuilder.h b/source/pipelinebuilder.h
new file mode 100644 (file)
index 0000000..5ad420e
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef PIPELINEBUILDER_H_
+#define PIPELINEBUILDER_H_
+
+#include <map>
+#include <string>
+
+namespace Msp {
+namespace GL {
+
+class Pipeline;
+class PipelineTemplate;
+class Renderable;
+class View;
+
+class PipelineBuilder
+{
+private:
+       const PipelineTemplate &tmpl;
+       std::map<std::string, Renderable *> renderables;
+
+public:
+       PipelineBuilder(const PipelineTemplate &);
+
+       void set_renderable(const std::string &, Renderable &);
+
+       void build(Pipeline &) const;
+       Pipeline *build(const View &) const;
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
diff --git a/source/pipelinetemplate.cpp b/source/pipelinetemplate.cpp
new file mode 100644 (file)
index 0000000..6dbfd0a
--- /dev/null
@@ -0,0 +1,161 @@
+#include <msp/core/maputils.h>
+#include <msp/datafile/collection.h>
+#include "blend.h"
+#include "bloom.h"
+#include "colorcurve.h"
+#include "lighting.h"
+#include "pipelinetemplate.h"
+#include "tests.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+PipelineTemplate::PipelineTemplate():
+       hdr(false),
+       required_multisample(0),
+       max_multisample(0)
+{ }
+
+
+PipelineTemplate::Pass::~Pass()
+{ }
+
+
+PipelineTemplate::Loader::Loader(PipelineTemplate &t):
+       DataFile::CollectionObjectLoader<PipelineTemplate>(t, 0)
+{
+       init();
+}
+
+PipelineTemplate::Loader::Loader(PipelineTemplate &t, Collection &c):
+       DataFile::CollectionObjectLoader<PipelineTemplate>(t, &c)
+{
+       init();
+}
+
+void PipelineTemplate::Loader::init()
+{
+       add("bloom", &Loader::postprocessor<Bloom>);
+       add("colorcurve", &Loader::postprocessor<ColorCurve>);
+       add("hdr", &PipelineTemplate::hdr);
+       add("multisample", &Loader::multisample);
+       add("multisample", &Loader::multisample_range);
+       add("pass", &Loader::pass);
+}
+
+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);
+}
+
+template<typename T>
+void PipelineTemplate::Loader::postprocessor()
+{
+       RefPtr<typename T::Template> postproc = new typename T::Template;
+       load_sub(*postproc);
+       obj.postprocessors.push_back(postproc.release());
+}
+
+
+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 *blend = 0;
+       if(name=="alpha")
+               blend = &Blend::alpha();
+       else if(name=="additive")
+               blend = &Blend::additive();
+       else if(name=="additive_alpha")
+               blend = &Blend::additive_alpha();
+       else
+               throw key_error(name);
+
+       obj.blend = blend;
+       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/pipelinetemplate.h b/source/pipelinetemplate.h
new file mode 100644 (file)
index 0000000..56c4da1
--- /dev/null
@@ -0,0 +1,89 @@
+#ifndef PIPELINETEMPLATE_H_
+#define PIPELINETEMPLATE_H_
+
+#include <string>
+#include <vector>
+#include <msp/datafile/objectloader.h>
+#include "blend.h"
+#include "postprocessor.h"
+#include "predicate.h"
+
+namespace Msp {
+namespace GL {
+
+class DepthTest;
+class Lighting;
+
+class PipelineTemplate
+{
+public:
+       class Loader: public DataFile::CollectionObjectLoader<PipelineTemplate>
+       {
+       public:
+               Loader(PipelineTemplate &);
+               Loader(PipelineTemplate &, Collection &);
+       private:
+               void init();
+
+               void multisample(unsigned);
+               void multisample_range(unsigned, unsigned);
+               void pass(const std::string &, const std::string &);
+
+               template<typename T>
+               void postprocessor();
+       };
+
+       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();
+       };
+
+       typedef std::vector<Pass> PassArray;
+       typedef std::vector<PostProcessor::Template *> PostProcessorArray;
+
+private:
+       bool hdr;
+       unsigned required_multisample;
+       unsigned max_multisample;
+       PassArray passes;
+       PostProcessorArray postprocessors;
+
+public:
+       PipelineTemplate();
+
+       bool get_hdr() const { return hdr; }
+       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; }
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
index 26330a4d08b3d03a1f5df88711e681f519482327..28ae71b0945b2ca28e04cf3de34d60e222a36646 100644 (file)
@@ -50,5 +50,17 @@ const Mesh &PostProcessor::create_fullscreen_quad()
        return mesh;
 }
 
+
+PostProcessor::Template::Template():
+       size_divisor(1)
+{ }
+
+
+PostProcessor::Template::Loader::Loader(Template &t):
+       DataFile::ObjectLoader<Template>(t)
+{
+       add("size_divisor", &Template::size_divisor);
+}
+
 } // namespace GL
 } // namespace Msp
index 15cdc271149265e171da1b2cdf4ef6ce6a3b842d..6e3153dab69f9dea7639ffc675ad4386c8d45725 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef MSP_GL_POSTPROCESSOR_H_
 #define MSP_GL_POSTPROCESSOR_H_
 
+#include <msp/datafile/objectloader.h>
+
 namespace Msp {
 namespace GL {
 
@@ -16,6 +18,23 @@ process.
 */
 class PostProcessor
 {
+public:
+       struct Template
+       {
+               class Loader: public Msp::DataFile::ObjectLoader<Template>
+               {
+               public:
+                       Loader(Template &);
+               };
+
+               unsigned size_divisor;
+
+               Template();
+               virtual ~Template() { }
+
+               virtual PostProcessor *create(unsigned, unsigned) const = 0;
+       };
+
 protected:
        PostProcessor() { }
 public:
index b25c346a11ec7882511ee4cee68c0286c28be0ca..c34139b25e139e1b53e588c732715afc30a7ce62 100644 (file)
@@ -8,6 +8,7 @@
 #include "material.h"
 #include "mesh.h"
 #include "object.h"
+#include "pipelinetemplate.h"
 #include "pose.h"
 #include "program.h"
 #include "programcompiler.h"
@@ -39,6 +40,7 @@ Resources::Resources():
        add_type<Material>().suffix(".mat").keyword("material");
        add_type<Mesh>().keyword("mesh").creator(&Resources::create_mesh);
        add_type<Object>().keyword("object");
+       add_type<PipelineTemplate>().suffix(".pipe").keyword("pipeline");
        add_type<Pose>().keyword("pose");
        add_type<Program>().keyword("shader").suffix(".glsl").creator(&Resources::create_program);
        add_type<Technique>().suffix(".tech").keyword("technique");