-#include "arb_draw_buffers.h"
+#include <msp/gl/extensions/arb_draw_buffers.h>
+#include <msp/gl/extensions/ext_framebuffer_blit.h>
+#include <msp/gl/extensions/ext_framebuffer_object.h>
+#include <msp/gl/extensions/msp_draw_buffer.h>
#include "error.h"
-#include "ext_framebuffer_blit.h"
-#include "ext_framebuffer_object.h"
#include "framebuffer.h"
#include "misc.h"
#include "renderbuffer.h"
namespace Msp {
namespace GL {
+void operator<<(LexicalConverter &conv, FramebufferStatus status)
+{
+ switch(status)
+ {
+ case FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
+ conv.result("incomplete attachment");
+ break;
+ case FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
+ conv.result("missing attachment");
+ break;
+ case FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
+ conv.result("mismatched attachment dimensions");
+ break;
+ case FRAMEBUFFER_INCOMPLETE_FORMATS:
+ conv.result("mismatched attachment formats");
+ break;
+ case FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
+ conv.result("missing draw buffer attachment");
+ break;
+ case FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
+ conv.result("missing read buffer attachment");
+ break;
+ case FRAMEBUFFER_UNSUPPORTED:
+ conv.result("unsupported");
+ break;
+ default:
+ conv.result(lexical_cast<string, unsigned>(status, "%#x"));
+ break;
+ }
+}
+
+framebuffer_incomplete::framebuffer_incomplete(FramebufferStatus status):
+ runtime_error(lexical_cast<string>(status))
+{ }
+
+
Framebuffer::Framebuffer(unsigned i):
id(i),
dirty(0)
if(id)
throw invalid_argument("System framebuffer must have id 0");
- int viewport[4];
- glGetIntegerv(GL_VIEWPORT, viewport);
- width = viewport[2];
- height = viewport[3];
+ glGetIntegerv(GL_VIEWPORT, &view.left);
+ width = view.width;
+ height = view.height;
}
Framebuffer::Framebuffer():
color_bufs.push_back(attch.attachment);
}
- if(color_bufs.empty())
- glDrawBuffer(GL_NONE);
- else if(color_bufs.size()==1)
- glDrawBuffer(color_bufs.front());
- else
- {
+ if(color_bufs.size()>1)
static Require _req(ARB_draw_buffers);
+
+ GLenum first_buffer = (color_bufs.empty() ? GL_NONE : color_bufs.front());
+ if(ARB_draw_buffers)
glDrawBuffers(color_bufs.size(), &color_bufs[0]);
- }
+ else if(MSP_draw_buffer)
+ glDrawBuffer(first_buffer);
+
+ if(MSP_draw_buffer)
+ glReadBuffer(first_buffer);
}
else
dirty |= mask;
void Framebuffer::check_size()
{
+ bool full_viewport = (view.left==0 && view.bottom==0 && view.width==width && view.height==height);
for(vector<Attachment>::iterator i=attachments.begin(); i!=attachments.end(); ++i)
if(i->type)
{
width = static_cast<TextureCube *>(i->tex)->get_size();
height = width;
}
- if(current()==this)
- glViewport(0, 0, width, height);
+ if(full_viewport)
+ reset_viewport();
break;
}
}
FramebufferStatus Framebuffer::check_status() const
{
- Bind _bind(this, true);
+ BindRestore _bind(this);
return static_cast<FramebufferStatus>(glCheckFramebufferStatus(GL_FRAMEBUFFER));
}
+void Framebuffer::require_complete() const
+{
+ FramebufferStatus status = check_status();
+ if(status!=FRAMEBUFFER_COMPLETE)
+ throw framebuffer_incomplete(status);
+}
+
+void Framebuffer::viewport(int l, int b, unsigned w, unsigned h)
+{
+ view.left = l;
+ view.bottom = b;
+ view.width = w;
+ view.height = h;
+
+ if(current()==this)
+ glViewport(view.left, view.bottom, view.width, view.height);
+}
+
+void Framebuffer::reset_viewport()
+{
+ viewport(0, 0, width, height);
+}
+
void Framebuffer::clear(BufferBits bits)
{
- Bind _bind(this, true);
+ BindRestore _bind(this);
glClear(bits);
}
update_attachment(dirty);
dirty = 0;
}
+
if(width && height)
- glViewport(0, 0, width, height);
+ glViewport(view.left, view.bottom, view.width, view.height);
}
}
const Framebuffer *Framebuffer::current()
-{
+{
if(!cur_obj)
cur_obj = &system();
return cur_obj;
type = 0;
}
+
+Framebuffer::Viewport::Viewport():
+ left(0),
+ bottom(0),
+ width(0),
+ height(0)
+{ }
+
} // namespace GL
} // namespace Msp