-#include <stdexcept>
-#include "arb_pixel_buffer_object.h"
-#include "arb_uniform_buffer_object.h"
-#include "arb_vertex_buffer_object.h"
-#include "buffer.h"
-#include "misc.h"
-
-using namespace std;
-
-namespace Msp {
-namespace GL {
-
-const Buffer *Buffer::bound[5] = { 0, 0, 0, 0, 0 };
-
-Buffer::Buffer(BufferType t):
- type(t),
- usage(STATIC_DRAW),
- size(0)
-{
- require_buffer_type(type);
-
- glGenBuffers(1, &id);
-}
-
-Buffer::~Buffer()
-{
- glDeleteBuffers(1, &id);
-}
-
-void Buffer::require_buffer_type(BufferType type)
-{
- static Require _req_vbo(ARB_vertex_buffer_object);
- if(type==PIXEL_PACK_BUFFER || type==PIXEL_UNPACK_BUFFER)
- static Require _req_pbo(ARB_pixel_buffer_object);
- else if(type==UNIFORM_BUFFER)
- static Require _req_ubo(ARB_uniform_buffer_object);
-}
-
-void Buffer::set_usage(BufferUsage u)
-{
- usage = u;
-}
-
-void Buffer::data(unsigned sz, const void *d)
-{
- const Buffer *old = current(type);
- bind();
- glBufferData(type, sz, d, usage);
- size = sz;
- restore(old, type);
-}
-
-void Buffer::sub_data(unsigned off, unsigned sz, const void *d)
-{
- const Buffer *old = current(type);
- bind();
- glBufferSubData(type, off, sz, d);
- restore(old, type);
-}
-
-BufferRange *Buffer::create_range(unsigned s, unsigned o)
-{
- return new BufferRange(*this, s, o);
-}
-
-void Buffer::bind_to(BufferType t) const
-{
- if(t!=type)
- require_buffer_type(t);
- if(set_current(t, this))
- glBindBuffer(t, id);
-}
-
-void Buffer::unbind_from(BufferType type)
-{
- if(set_current(type, 0))
- glBindBuffer(type, 0);
-}
-
-const Buffer *&Buffer::binding(BufferType type)
-{
- switch(type)
- {
- case ARRAY_BUFFER: return bound[0];
- case ELEMENT_ARRAY_BUFFER: return bound[1];
- case PIXEL_PACK_BUFFER: return bound[2];
- case PIXEL_UNPACK_BUFFER: return bound[3];
- case UNIFORM_BUFFER: return bound[4];
- default: throw invalid_argument("Buffer::binding");
- }
-}
-
-bool Buffer::set_current(BufferType type, const Buffer *buf)
-{
- const Buffer *&ptr = binding(type);
- if(ptr==buf)
- return false;
-
- ptr = buf;
- return true;
-}
-
-void Buffer::restore(const Buffer *buf, BufferType type)
-{
- if(buf!=current(type))
- {
- if(buf)
- buf->bind_to(type);
- else
- unbind_from(type);
- }
-}
-
-
-vector<const BufferRange *> BufferRange::bound_uniform;
-
-BufferRange::BufferRange(Buffer &b, unsigned o, unsigned s):
- buffer(b),
- offset(o),
- size(s)
-{
- if(o>buffer.get_size() || o+s>buffer.get_size())
- throw out_of_range("BufferRange::BufferRange");
-}
-
-void BufferRange::data(const void *d)
-{
- buffer.sub_data(offset, size, d);
-}
-
-void BufferRange::bind_to(BufferType t, unsigned i)
-{
- if(t!=buffer.type)
- Buffer::require_buffer_type(t);
- // Intentionally using bitwise | to avoid short-circuiting
- if(Buffer::set_current(t, &buffer) | set_current(t, i, this))
- glBindBufferRange(t, i, buffer.id, offset, size);
-}
-
-void BufferRange::unbind_from(BufferType t, unsigned i)
-{
- if(set_current(t, i, 0))
- {
- Buffer::set_current(t, 0);
- glBindBufferBase(t, i, 0);
- }
-}
-
-const BufferRange *&BufferRange::binding(BufferType type, unsigned index)
-{
- if(type==UNIFORM_BUFFER)
- {
- if(index>=get_n_uniform_buffer_bindings())
- throw out_of_range("BufferRange::binding");
- if(bound_uniform.size()<=index)
- bound_uniform.resize(index+1);
- return bound_uniform[index];
- }
- else
- throw invalid_argument("BufferRange::binding");
-}
-
-bool BufferRange::set_current(BufferType type, unsigned index, const BufferRange *buf)
-{
- const BufferRange *&ptr = binding(type, index);
- if(ptr==buf)
- return false;
-
- ptr = buf;
- return true;
-}
-
-unsigned BufferRange::get_n_uniform_buffer_bindings()
-{
- static unsigned count = get_i(GL_MAX_UNIFORM_BUFFER_BINDINGS);
- return count;
-}
-
-unsigned BufferRange::get_uniform_buffer_alignment()
-{
- static unsigned align = get_i(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT);
- return align;
-}
-
-} // namespace GL
-} // namespace Msp