-#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