if(target[0])
{
- Framebuffer &fbo = (samples ? target_ms->fbo : target[0]->fbo);
+ Framebuffer &fbo = (samples ? target_ms : target[0])->get_framebuffer();
fbo.bind();
fbo.clear(COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT);
}
Blend::unbind();
if(samples)
- target[0]->fbo.blit_from(target_ms->fbo, COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT, false);
+ 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]->fbo.bind();
+ target[1-j]->get_framebuffer().bind();
else
out_fbo->bind();
- postproc[i]->render(renderer, target[j]->color, target[j]->depth);
+ 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);
}
}
target_ms = 0;
}
- PixelFormat fmt = (hdr ? RGB16F : RGB);
+ PixelFormat color_pf = (hdr ? RGB16F : RGB);
+ RenderTargetFormat fmt = (RENDER_COLOR,color_pf, RENDER_DEPTH);
if(!postproc.empty() || samples)
{
if(!target[0])
}
if(!target_ms && samples)
- target_ms = new MultisampleTarget(width, height, samples, fmt);
+ target_ms = new RenderTarget(width, height, samples, fmt);
}
renderable(r)
{ }
-
-Pipeline::RenderTarget::RenderTarget(unsigned w, unsigned h, PixelFormat f)
-{
- color.set_min_filter(NEAREST);
- color.set_mag_filter(NEAREST);
- color.set_wrap(CLAMP_TO_EDGE);
- color.storage(f, w, h);
- fbo.attach(COLOR_ATTACHMENT0, color, 0);
-
- depth.set_min_filter(NEAREST);
- depth.set_mag_filter(NEAREST);
- depth.set_wrap(CLAMP_TO_EDGE);
- depth.storage(DEPTH_COMPONENT, w, h);
- fbo.attach(DEPTH_ATTACHMENT, depth, 0);
-
- fbo.require_complete();
-}
-
-
-Pipeline::MultisampleTarget::MultisampleTarget(unsigned w, unsigned h, unsigned s, PixelFormat f)
-{
- color.storage_multisample(s, f, w, h);
- fbo.attach(COLOR_ATTACHMENT0, color);
-
- depth.storage_multisample(s, DEPTH_COMPONENT, w, h);
- fbo.attach(DEPTH_ATTACHMENT, depth);
-
- fbo.require_complete();
-}
-
} // namespace GL
} // namespace Msp
#include "framebuffer.h"
#include "renderable.h"
#include "renderbuffer.h"
+#include "rendertarget.h"
#include "texture2d.h"
namespace Msp {
Slot(const Renderable *);
};
- struct RenderTarget
- {
- Framebuffer fbo;
- Texture2D color;
- Texture2D depth;
-
- RenderTarget(unsigned, unsigned, PixelFormat);
- };
-
- struct MultisampleTarget
- {
- Framebuffer fbo;
- Renderbuffer color;
- Renderbuffer depth;
-
- MultisampleTarget(unsigned, unsigned, unsigned, PixelFormat);
- };
-
typedef std::list<Pass> PassList;
PassList passes;
bool hdr;
unsigned samples;
RenderTarget *target[2];
- MultisampleTarget *target_ms;
+ RenderTarget *target_ms;
mutable bool in_frame;
public:
--- /dev/null
+#include <msp/core/maputils.h>
+#include "error.h"
+#include "renderbuffer.h"
+#include "rendertarget.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+RenderTargetFormat::RenderTargetFormat():
+ count(0)
+{ }
+
+RenderTargetFormat::RenderTargetFormat(RenderOutput o):
+ count(1)
+{
+ outputs[0] = o;
+}
+
+RenderTargetFormat RenderTargetFormat::operator,(RenderOutput o) const
+{
+ if(count>=MAX_OUTPUTS)
+ throw invalid_operation("RenderTargetFormat::operator,");
+
+ RenderTargetFormat result = *this;
+ result.outputs[result.count++] = o;
+
+ return result;
+}
+
+RenderTargetFormat RenderTargetFormat::operator,(PixelFormat f) const
+{
+ if(!count)
+ throw invalid_operation("RenderTargetFormat::operator,");
+
+ PixelFormat unsized = get_unsized_pixelformat(f);
+ unsigned size = get_component_size(f);
+ unsigned char out = outputs[count-1];
+ if(get_output_type(out)>=get_output_type(RENDER_DEPTH))
+ {
+ if(unsized!=DEPTH_COMPONENT)
+ throw invalid_argument("RenderTargetformat::operator,");
+ if(size>1)
+ --size;
+ }
+ else
+ {
+ if(unsized!=RGB && unsized!=RGBA)
+ throw invalid_argument("RenderTargetformat::operator,");
+ if(size>3)
+ --size;
+ }
+
+ out = (out&~15) | (size<<2) | (get_component_count(f)-1);
+ RenderTargetFormat result = *this;
+ result.outputs[result.count-1] = out;
+
+ return result;
+}
+
+int RenderTargetFormat::index(RenderOutput o)
+{
+ unsigned type = get_output_type(o);
+ unsigned i = 0;
+ for(const unsigned char *j=begin(); j!=end(); ++j, ++i)
+ if(get_output_type(*j)==type)
+ return i;
+ return -1;
+}
+
+
+PixelFormat get_output_pixelformat(unsigned char o)
+{
+ unsigned ncomp = (o&3)+1;
+ unsigned size = ((o>>2)&3);
+ PixelFormat base;
+ if(get_output_type(o)>=get_output_type(RENDER_DEPTH))
+ {
+ base = DEPTH_COMPONENT;
+ if(size)
+ ++size;
+ }
+ else
+ {
+ base = (ncomp==4 ? RGBA : RGB);
+ if(size==3)
+ ++size;
+ }
+
+ if(size)
+ return get_sized_pixelformat(base, size);
+ else
+ return base;
+}
+
+
+RenderTarget::RenderTarget(unsigned w, unsigned h, const RenderTargetFormat &f)
+{
+ init(w, h, 0, f);
+}
+
+RenderTarget::RenderTarget(unsigned w, unsigned h, unsigned s, const RenderTargetFormat &f)
+{
+ init(w, h, s, f);
+}
+
+void RenderTarget::init(unsigned w, unsigned h, unsigned s, const RenderTargetFormat &f)
+{
+ width = w;
+ height = h;
+ samples = s;
+ format = f;
+
+ for(const unsigned char *i=format.begin(); i!=format.end(); ++i)
+ {
+ unsigned type = get_output_type(*i);
+ FramebufferAttachment att;
+ if(type>=get_output_type(RENDER_DEPTH))
+ att = DEPTH_ATTACHMENT;
+ else
+ att = static_cast<FramebufferAttachment>(COLOR_ATTACHMENT0+type);
+
+ PixelFormat pf = get_output_pixelformat(*i);
+
+ TargetBuffer tgt;
+ if(samples)
+ {
+ tgt.buffer = new Renderbuffer;
+ tgt.buffer->storage_multisample(samples, pf, width, height);
+ fbo.attach(att, *tgt.buffer);
+ }
+ else
+ {
+ tgt.texture = new Texture2D;
+ tgt.texture->storage(pf, width, height);
+ tgt.texture->set_filter(NEAREST);
+ tgt.texture->set_wrap(CLAMP_TO_EDGE);
+ fbo.attach(att, *tgt.texture);
+ }
+ buffers.push_back(tgt);
+ }
+
+ fbo.require_complete();
+}
+
+RenderTarget::~RenderTarget()
+{
+ for(vector<TargetBuffer>::iterator i=buffers.begin(); i!=buffers.end(); ++i)
+ {
+ if(samples)
+ delete i->buffer;
+ else
+ delete i->texture;
+ }
+}
+
+const Texture2D &RenderTarget::get_target_texture(unsigned i)
+{
+ if(i>=buffers.size())
+ throw out_of_range("RenderTarget::get_target_texture");
+ if(samples)
+ throw invalid_operation("RenderTarget::get_target_texture");
+
+ return *buffers[i].texture;
+}
+
+const Texture2D &RenderTarget::get_target_texture(RenderOutput o)
+{
+ int index = format.index(o);
+ if(index<0)
+ throw key_error(o);
+
+ return get_target_texture(index);
+}
+
+void RenderTarget::blit_from(const RenderTarget &other)
+{
+ fbo.blit_from(other.fbo, COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT, false);
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef RENDERTARGET_H_
+#define RENDERTARGET_H_
+
+#include "framebuffer.h"
+#include "texture2d.h"
+
+namespace Msp {
+namespace GL {
+
+enum RenderOutput
+{
+ RENDER_COLOR = 0|3,
+ RENDER_DEPTH = 192|12
+};
+
+class RenderTargetFormat
+{
+private:
+ enum { MAX_OUTPUTS = 7 };
+
+ unsigned char count;
+ unsigned char outputs[MAX_OUTPUTS];
+
+public:
+ RenderTargetFormat();
+ RenderTargetFormat(RenderOutput);
+
+ RenderTargetFormat operator,(RenderOutput) const;
+ RenderTargetFormat operator,(PixelFormat) const;
+
+ bool empty() const { return !count; }
+ const unsigned char *begin() const { return outputs; }
+ const unsigned char *end() const { return outputs+count; }
+ int index(RenderOutput);
+};
+
+inline RenderTargetFormat operator,(RenderOutput o1, RenderOutput o2)
+{ return (RenderTargetFormat(o1), o2); }
+
+inline RenderTargetFormat operator,(RenderOutput o, PixelFormat f)
+{ return (RenderTargetFormat(o), f); }
+
+inline unsigned get_output_type(unsigned char o)
+{ return o>>4; }
+
+PixelFormat get_output_pixelformat(unsigned char);
+
+
+class RenderTarget
+{
+private:
+ union TargetBuffer
+ {
+ Texture2D *texture;
+ Renderbuffer *buffer;
+ };
+
+ unsigned width;
+ unsigned height;
+ unsigned samples;
+ RenderTargetFormat format;
+ std::vector<TargetBuffer> buffers;
+ Framebuffer fbo;
+
+public:
+ RenderTarget(unsigned, unsigned, const RenderTargetFormat & = (RENDER_COLOR, RENDER_DEPTH));
+ RenderTarget(unsigned, unsigned, unsigned, const RenderTargetFormat & = (RENDER_COLOR, RENDER_DEPTH));
+private:
+ RenderTarget(const RenderTarget &);
+ RenderTarget &operator=(const RenderTarget &);
+ void init(unsigned, unsigned, unsigned, const RenderTargetFormat &);
+public:
+ ~RenderTarget();
+
+ const RenderTargetFormat &get_format() const { return format; }
+ Framebuffer &get_framebuffer() { return fbo; }
+ const Texture2D &get_target_texture(unsigned);
+ const Texture2D &get_target_texture(RenderOutput);
+ void blit_from(const RenderTarget &);
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif