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
*/
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;
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
*/
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;
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);
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())
PassList passes;
const Camera *camera;
std::vector<Slot> renderables;
- std::vector<PostProcessor *> postproc;
+ std::vector<RefPtr<PostProcessor> > postproc;
unsigned width;
unsigned height;
bool hdr;
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);
/** 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();
--- /dev/null
+#include <msp/core/algorithm.h>
+#include <msp/core/maputils.h>
+#include "error.h"
+#include "pipeline.h"
+#include "pipelinebuilder.h"
+#include "pipelinetemplate.h"
+#include "renderbuffer.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+PipelineBuilder::PipelineBuilder(const PipelineTemplate &t):
+ tmpl(t)
+{
+ const vector<PipelineTemplate::Pass> &passes = tmpl.get_passes();
+ for(vector<PipelineTemplate::Pass>::const_iterator i=passes.begin(); i!=passes.end(); ++i)
+ renderables[i->renderable_name] = 0;
+}
+
+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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
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
#ifndef MSP_GL_POSTPROCESSOR_H_
#define MSP_GL_POSTPROCESSOR_H_
+#include <msp/datafile/objectloader.h>
+
namespace Msp {
namespace GL {
*/
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:
#include "material.h"
#include "mesh.h"
#include "object.h"
+#include "pipelinetemplate.h"
#include "pose.h"
#include "program.h"
#include "programcompiler.h"
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");