+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)
+{
+ BindRestore _bind(this);
+ glClear(bits);
+}
+
+void Framebuffer::blit_from(const Framebuffer &other, int sx0, int sy0, int sx1, int sy1, int dx0, int dy0, int dx1, int dy1, BufferBits bits, bool filter)
+{
+ static Require _req(EXT_framebuffer_blit);
+
+ const Framebuffer *old = current();
+ if(set_current(this))
+ {
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, id);
+ if(dirty)
+ {
+ update_attachment(dirty);
+ dirty = 0;
+ }
+ }
+ if(old!=&other)
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, other.id);
+
+ glBlitFramebuffer(sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1, bits, (filter ? GL_LINEAR : GL_NEAREST));
+
+ set_current(old);
+ glBindFramebuffer(GL_FRAMEBUFFER, (old ? old->id : 0));
+}
+
+void Framebuffer::blit_from(const Framebuffer &other, int sx, int sy, unsigned wd, unsigned ht, int dx, int dy, BufferBits bits)
+{
+ blit_from(other, sx, sy, sx+wd, sy+ht, dx, dy, dx+wd, dy+ht, bits, false);
+}
+
+void Framebuffer::blit_from(const Framebuffer &other, BufferBits bits, bool filter)
+{
+ blit_from(other, 0, 0, other.width, other.height, 0, 0, width, height, bits, filter);
+}
+
+void Framebuffer::bind() const