]> git.tdb.fi Git - libs/gl.git/blobdiff - source/render/rendertarget.cpp
Rearrange soucre files into subdirectories
[libs/gl.git] / source / render / rendertarget.cpp
diff --git a/source/render/rendertarget.cpp b/source/render/rendertarget.cpp
new file mode 100644 (file)
index 0000000..1349944
--- /dev/null
@@ -0,0 +1,197 @@
+#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,");
+
+       PixelComponents comp = get_components(f);
+       unsigned size = get_component_size(f);
+       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,");
+               if(size>1)
+                       --size;
+               if(get_component_type(f)==UNSIGNED_INT)
+                       --size;
+       }
+       else
+       {
+               if(comp!=RED && comp!=RG && comp!=RGB && comp!=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) 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)
+{
+       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, 1);
+                       Sampler &sampler = tgt.texture->get_default_sampler();
+                       sampler.set_filter(NEAREST);
+                       sampler.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;
+       }
+}
+
+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);
+       }
+}
+
+const Texture2D &RenderTarget::get_target_texture(unsigned i) const
+{
+       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) const
+{
+       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