-#include <msp/core/maputils.h>
-#include "blend.h"
-#include "camera.h"
-#include "framebuffer.h"
+#include <msp/strings/format.h>
+#include "error.h"
#include "lighting.h"
#include "postprocessor.h"
-#include "renderbuffer.h"
#include "renderer.h"
+#include "rendertarget.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;
-}
+Tag Sequence::noclear_tag = "noclear";
-Sequence::Sequence(const View &view)
+Sequence::Sequence(unsigned w, unsigned h, const FrameFormat &f):
+ width(w),
+ height(h),
+ target_format(f)
{
- init(view.get_width(), view.get_height());
-}
+ if(target_format.empty())
+ throw invalid_argument("Sequence::Sequence");
-Sequence::Sequence(const Framebuffer &fbo)
-{
- init(fbo.get_width(), fbo.get_height());
-}
+ FrameFormat postproc_fmt = target_format;
+ postproc_fmt.set_samples(1);
+ target[0] = new RenderTarget(width, height, postproc_fmt);
+ target[1] = new RenderTarget(width, height, postproc_fmt);
-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;
+ if(target_format.get_samples()>1)
+ target_ms = new RenderTarget(width, height, target_format);
}
Sequence::~Sequence()
{
- for(vector<PostProcStep>::iterator i=postproc.begin(); i!=postproc.end(); ++i)
- if(i->owned)
- delete i->postproc;
+ for(OwnedObject &o: owned_data)
+ o.delete_func(o.pointer);
delete target[0];
delete target[1];
delete target_ms;
}
-void Sequence::set_hdr(bool h)
+void Sequence::set_clear_enabled(bool c)
{
- if(h==hdr)
- return;
-
- bool old_hdr = hdr;
- hdr = h;
- try
- {
- create_targets(2);
- }
- catch(...)
- {
- hdr = old_hdr;
- throw;
- }
+ clear_enabled = c;
}
-void Sequence::set_alpha(bool a)
+void Sequence::set_clear_colors(const vector<Color> &c)
{
- if(a==alpha)
- return;
-
- bool old_alpha = alpha;
- alpha = a;
- try
- {
- create_targets(2);
- }
- catch(...)
- {
- alpha = old_alpha;
- throw;
- }
+ clear_enabled = true;
+ clear_colors = c;
}
-void Sequence::set_multisample(unsigned s)
+void Sequence::set_clear_depth(float d)
{
- if(s==samples)
- return;
+ clear_enabled = true;
+ clear_depth = d;
+}
- unsigned old_samples = samples;
- samples = s;
- try
- {
- create_targets(1);
- }
- catch(...)
- {
- samples = old_samples;
- throw;
- }
+void Sequence::set_clear_stencil(int s)
+{
+ clear_enabled = true;
+ clear_stencil = s;
}
Sequence::Step &Sequence::add_step(Tag tag, Renderable &r)
{
- steps.push_back(Step(tag, &r));
+ steps.emplace_back(tag, &r);
return steps.back();
}
void Sequence::add_postprocessor(PostProcessor &pp)
{
- add_postprocessor(&pp, false);
-}
-
-void Sequence::add_postprocessor_owned(PostProcessor *pp)
-{
- add_postprocessor(pp, true);
-}
-
-void Sequence::add_postprocessor(PostProcessor *pp, bool owned)
-{
- postproc.push_back(PostProcStep(pp, owned));
- try
- {
- create_targets(0);
- }
- catch(...)
- {
- if(!owned)
- delete pp;
- postproc.pop_back();
- throw;
- }
+ if(target_format.empty())
+ throw invalid_operation("Sequence::add_postprocessor");
+ postproc.push_back(&pp);
}
void Sequence::setup_frame(Renderer &renderer)
{
- for(vector<Step>::const_iterator i=steps.begin(); i!=steps.end(); ++i)
- if(Renderable *renderable = i->get_renderable())
+ for(const Step &s: steps)
+ if(Renderable *renderable = s.get_renderable())
renderable->setup_frame(renderer);
}
void Sequence::finish_frame()
{
- for(vector<Step>::const_iterator i=steps.begin(); i!=steps.end(); ++i)
- if(Renderable *renderable = i->get_renderable())
+ for(const Step &s: steps)
+ if(Renderable *renderable = s.get_renderable())
renderable->finish_frame();
}
void Sequence::render(Renderer &renderer, Tag tag) const
{
- if(tag.id)
+ if(tag.id && tag!=noclear_tag)
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());
+ Renderer::Push _push(renderer);
+
+ const Framebuffer *out_fbo = renderer.get_framebuffer();
if(target[0])
+ renderer.set_framebuffer(&(target_ms ? target_ms : target[0])->get_framebuffer());
+
+ if(clear_enabled && tag!=noclear_tag)
{
- Framebuffer &fbo = (samples ? target_ms : target[0])->get_framebuffer();
- fbo.bind();
- fbo.clear();
+ const Framebuffer *target_fbo = renderer.get_framebuffer();
+ if(!target_fbo)
+ throw invalid_operation("Sequence::render");
+
+ const FrameFormat &format = target_fbo->get_format();
+ ClearValue clear_values[FrameFormat::MAX_ATTACHMENTS];
+ unsigned i = 0;
+ Color default_color = (clear_colors.empty() ? Color(0.0f, 0.0f, 0.0f, 0.0f) : clear_colors.front());
+ ClearValue *cv = clear_values;
+ for(FrameAttachment a: format)
+ {
+ if(get_attach_point(a)==get_attach_point(DEPTH_ATTACHMENT))
+ cv->depth_stencil.depth = clear_depth;
+ else if(get_attach_point(a)==get_attach_point(STENCIL_ATTACHMENT))
+ cv->depth_stencil.stencil = clear_stencil;
+ else
+ cv->color = (i<clear_colors.size() ? clear_colors[i++] : default_color);
+ ++cv;
+ }
+
+ renderer.clear(clear_values);
}
- for(vector<Step>::const_iterator i=steps.begin(); i!=steps.end(); ++i)
+ for(const Step &s: steps)
{
- if(const DepthTest *dt = i->get_depth_test())
- dt->bind();
- else
- DepthTest::unbind();
+ Renderer::Push _push2(renderer);
- if(const Blend *b = i->get_blend())
- b->bind();
- else
- Blend::unbind();
+ renderer.set_depth_test(&s.get_depth_test());
+ renderer.set_stencil_test(&s.get_stencil_test());
- if (const Lighting *lighting = i->get_lighting())
+ if(const Lighting *lighting = s.get_lighting())
renderer.add_shader_data(lighting->get_shader_data());
- renderer.set_clipping(i->get_clipping());
- if(const Renderable *renderable = i->get_renderable())
- renderer.render(*renderable, i->get_tag());
+ if(const Renderable *renderable = s.get_renderable())
+ renderable->render(renderer, s.get_tag());
}
if(target[0])
{
- DepthTest::unbind();
- Blend::unbind();
+ if(target_ms)
+ renderer.resolve_multisample(target[0]->get_framebuffer());
- if(samples)
- target[0]->blit_from(*target_ms);
+ renderer.set_depth_test(0);
+ renderer.set_stencil_test(0);
+ renderer.set_blend(0);
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].postproc->render(renderer, color, depth);
+ renderer.set_framebuffer(i+1<postproc.size() ? &target[1-j]->get_framebuffer() : out_fbo);
+ renderer.clear(0);
+ const Texture2D &color = target[j]->get_target_texture(COLOR_ATTACHMENT);
+ const Texture2D &depth = target[j]->get_target_texture(DEPTH_ATTACHMENT);
+ 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);
-
-#ifdef DEBUG
- if(!debug_name.empty())
- set_target_debug_names();
-#endif
-}
-
void Sequence::set_debug_name(const string &name)
{
-#ifdef DEBUG
- debug_name = name;
- if(!name.empty())
- set_target_debug_names();
-#else
- (void)name;
-#endif
-}
-
-void Sequence::set_target_debug_names()
-{
#ifdef DEBUG
for(unsigned i=0; i<2; ++i)
if(target[i])
- target[i]->set_debug_name(format("%s [RT:%d]", debug_name, i));
+ target[i]->set_debug_name(format("%s [RT:%d]", name, i));
if(target_ms)
- target_ms->set_debug_name(debug_name+" [RT:ms]");
+ target_ms->set_debug_name(name+" [RT:ms]");
+#else
+ (void)name;
#endif
}
Sequence::Step::Step(Tag t, Renderable *r):
tag(t),
lighting(0),
- depth_test(0),
- blend(0),
- clipping(0),
renderable(r)
{ }
lighting = l;
}
-void Sequence::Step::set_depth_test(const DepthTest *d)
-{
- depth_test = d;
-}
-
-void Sequence::Step::set_blend(const Blend *b)
+void Sequence::Step::set_depth_test(const DepthTest &dt)
{
- blend = b;
+ depth_test = dt;
}
-void Sequence::Step::set_clipping(const Clipping *c)
+void Sequence::Step::set_stencil_test(const StencilTest &st)
{
- clipping =c;
+ stencil_test = st;
}
} // namespace GL