#include <msp/core/maputils.h>
#include <msp/strings/format.h>
#include "error.h"
-#include "renderbuffer.h"
#include "rendertarget.h"
+#include "texture2d.h"
+#include "texture2dmultisample.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,");
-
- PixelComponents comp = get_components(f);
- DataType type = get_component_type(f);
- unsigned size = 0;
- unsigned char out = outputs[count-1];
- if(get_output_type(out)>=get_output_type(RENDER_DEPTH))
- {
- if(comp!=DEPTH_COMPONENT)
- throw invalid_argument("RenderTargetFormat::operator,");
- switch(type)
- {
- case UNSIGNED_SHORT: size = 0; break;
- case UNSIGNED_INT: size = 2; break;
- case FLOAT: size = 3; break;
- default: throw invalid_argument("RenderTargetFormat::operator,");
- }
- }
- else
- {
- if(comp!=RED && comp!=RG && comp!=RGB && comp!=RGBA)
- throw invalid_argument("RenderTargetformat::operator,");
- switch(type)
- {
- case UNSIGNED_BYTE: size = 0; break;
- case HALF_FLOAT: size = 2; break;
- case FLOAT: size = 3; break;
- default: throw invalid_argument("RenderTargetFormat::operator,");
- }
- }
-
- 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) const
-{
- 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)
-{
- PixelComponents comp;
- DataType type;
- if(get_output_type(o)>=get_output_type(RENDER_DEPTH))
- {
- static DataType types[4] = { UNSIGNED_SHORT, UNSIGNED_SHORT, UNSIGNED_INT, FLOAT };
- comp = DEPTH_COMPONENT;
- type = types[(o>>2)&3];
- }
- else
- {
- static PixelComponents components[4] = { RED, RG, RGB, RGBA };
- static DataType types[4] = { UNSIGNED_BYTE, UNSIGNED_SHORT, HALF_FLOAT, FLOAT };
- comp = components[o&3];
- type = types[(o>>2)&3];
- }
-
- return make_pixelformat(comp, type);
-}
-
-
-RenderTarget::RenderTarget(unsigned w, unsigned h, RenderOutput o)
-{
- init(w, h, 0, o);
-}
-
-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)
+RenderTarget::RenderTarget(unsigned w, unsigned h, const FrameFormat &f):
+ width(w),
+ height(h),
+ fbo(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)
+ textures.reserve(f.size());
+ unsigned samples = f.get_samples();
+ for(FrameAttachment a: f)
{
- 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);
+ PixelFormat pf = get_attachment_pixelformat(a);
- TargetBuffer tgt;
- if(samples)
+ if(samples>1)
{
- tgt.buffer = new Renderbuffer;
- tgt.buffer->storage_multisample(samples, pf, width, height);
- fbo.attach(att, *tgt.buffer);
+ Texture2DMultisample *tex2d_ms = new Texture2DMultisample;
+ tex2d_ms->storage(pf, width, height, samples);
+ fbo.attach(a, *tex2d_ms);
+ textures.push_back(tex2d_ms);
}
else
{
- tgt.texture = new Texture2D;
- tgt.texture->storage(pf, width, height, 1);
- Sampler &sampler = tgt.texture->get_default_sampler();
- sampler.set_filter(NEAREST);
- sampler.set_wrap(CLAMP_TO_EDGE);
- fbo.attach(att, *tgt.texture);
+ Texture2D *tex2d = new Texture2D;
+ tex2d->storage(pf, width, height, 1);
+ fbo.attach(a, *tex2d);
+ textures.push_back(tex2d);
}
- 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;
- }
-}
-
-void RenderTarget::set_texture_filter(TextureFilter filt)
-{
- if(!samples)
- {
- for(vector<TargetBuffer>::iterator i=buffers.begin(); i!=buffers.end(); ++i)
- i->texture->get_default_sampler().set_filter(filt);
- }
+ for(Texture *t: textures)
+ delete t;
}
const Texture2D &RenderTarget::get_target_texture(unsigned i) const
{
- if(i>=buffers.size())
+ if(i>=textures.size())
throw out_of_range("RenderTarget::get_target_texture");
- if(samples)
+ if(fbo.get_format().get_samples()>1)
throw invalid_operation("RenderTarget::get_target_texture");
- return *buffers[i].texture;
+ return *static_cast<const Texture2D *>(textures[i]);
}
-const Texture2D &RenderTarget::get_target_texture(RenderOutput o) const
+const Texture2D &RenderTarget::get_target_texture(FrameAttachment fa) const
{
- int index = format.index(o);
+ int index = fbo.get_format().index(fa);
if(index<0)
- throw key_error(o);
+ throw key_error(fa);
return get_target_texture(index);
}
-void RenderTarget::blit_from(const RenderTarget &other)
-{
- fbo.blit_from(other.fbo, COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT, false);
-}
-
void RenderTarget::set_debug_name(const string &name)
{
#ifdef DEBUG
fbo.set_debug_name(name+" [FBO]");
unsigned i = 0;
- for(const unsigned char *j=format.begin(); j!=format.end(); ++i, ++j)
+ for(FrameAttachment a: fbo.get_format())
{
- unsigned type = get_output_type(*j);
+ unsigned attach_pt = get_attach_point(a);
- string buf_name;
- if(type>=get_output_type(RENDER_DEPTH))
- buf_name = name+"/depth";
+ string tex_name;
+ if(attach_pt==get_attach_point(DEPTH_ATTACHMENT))
+ tex_name = name+"/depth";
+ else if(attach_pt==get_attach_point(STENCIL_ATTACHMENT))
+ tex_name = name+"/stencil";
else
- buf_name = Msp::format("%s/color%d", name, type);
+ tex_name = Msp::format("%s/color%d", name, attach_pt);
- if(samples)
- buffers[i].buffer->set_debug_name(buf_name+".tex2d");
- else
- buffers[i].texture->set_debug_name(buf_name+".rbuf");
+ textures[i++]->set_debug_name(tex_name+".tex");
}
#else
(void)name;