From 76e338af116120d93d082ad247591ec9adad9233 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sun, 24 May 2009 10:56:35 +0000 Subject: [PATCH] Generalize VertexBuffer into Buffer with support for other types as well Support using index buffer for Mesh Don't autoreset Immediate on end() to make it compatible with MeshBuilder Add a RAII class for bindings Make Program::bind const --- source/batch.cpp | 5 +++ source/batch.h | 13 ++++-- source/buffer.cpp | 85 +++++++++++++++++++++++++++++++++++++++ source/buffer.h | 88 +++++++++++++++++++++++++++++++++++++++++ source/immediate.cpp | 10 ++++- source/immediate.h | 1 + source/mesh.cpp | 59 +++++++++++++++++++++++++-- source/mesh.h | 8 +++- source/misc.h | 25 ++++++++++++ source/program.cpp | 4 +- source/program.h | 4 +- source/vertexarray.cpp | 8 ++-- source/vertexarray.h | 6 +-- source/vertexbuffer.cpp | 52 ------------------------ source/vertexbuffer.h | 19 ++++----- 15 files changed, 303 insertions(+), 84 deletions(-) create mode 100644 source/buffer.cpp create mode 100644 source/buffer.h delete mode 100644 source/vertexbuffer.cpp diff --git a/source/batch.cpp b/source/batch.cpp index f2a57bcf..e5224911 100644 --- a/source/batch.cpp +++ b/source/batch.cpp @@ -46,6 +46,11 @@ void Batch::draw() const draw_range_elements(type, min_index, max_index, indices.size(), &indices[0]); } +void Batch::draw_with_buffer(unsigned offset) const +{ + draw_range_elements(type, min_index, max_index, indices.size(), (unsigned *)0+offset); +} + Batch::Loader::Loader(Batch &b): batch(b) diff --git a/source/batch.h b/source/batch.h index 4a2e4b34..9b2072de 100644 --- a/source/batch.h +++ b/source/batch.h @@ -29,15 +29,20 @@ public: void indices(const std::vector &); }; - Batch(PrimitiveType t); - Batch &append(uint); - void append(const std::vector &); - void draw() const; private: PrimitiveType type; std::vector indices; uint min_index; uint max_index; + +public: + Batch(PrimitiveType t); + Batch &append(uint); + void append(const std::vector &); + unsigned size() const { return indices.size(); } + const std::vector &get_indices() const { return indices; } + void draw() const; + void draw_with_buffer(unsigned) const; }; } // namespace GL diff --git a/source/buffer.cpp b/source/buffer.cpp new file mode 100644 index 00000000..b4b71c3a --- /dev/null +++ b/source/buffer.cpp @@ -0,0 +1,85 @@ +/* $Id$ + +This file is part of libmspgl +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#include "arb_vertex_buffer_object.h" +#include "extension.h" +#include "buffer.h" + +namespace Msp { +namespace GL { + +Buffer::Buffer(BufferType t): + type(t), + usage(STATIC_DRAW) +{ + static RequireExtension _req_vbo("GL_ARB_vertex_buffer_object"); + if(type==PIXEL_PACK_BUFFER || type==PIXEL_UNPACK_BUFFER) + static RequireExtension _req_pbo("GL_ARB_pixel_buffer_object"); + + glGenBuffersARB(1, &id); +} + +Buffer::~Buffer() +{ + glDeleteBuffersARB(1, &id); +} + +void Buffer::bind(BufferType t) const +{ + glBindBufferARB(t, id); + binding(t)=this; +} + +void Buffer::maybe_bind() const +{ + if(binding(type)!=this) + bind(); +} + +void Buffer::set_usage(BufferUsage u) +{ + usage=u; +} + +void Buffer::data(unsigned size, const void *d) +{ + maybe_bind(); + glBufferDataARB(type, size, d, usage); +} + +void Buffer::sub_data(unsigned offset, unsigned size, const void *d) +{ + maybe_bind(); + glBufferSubDataARB(type, offset, size, d); +} + +void Buffer::unbind(BufferType type) +{ + const Buffer *&ptr=binding(type); + if(ptr) + { + glBindBufferARB(type, 0); + ptr=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]; + default: throw InvalidParameterValue("Invalid buffer type"); + } +} + +const Buffer *Buffer::bound[4]={ 0, 0, 0, 0 }; + +} // namespace GL +} // namespace Msp diff --git a/source/buffer.h b/source/buffer.h new file mode 100644 index 00000000..e9152486 --- /dev/null +++ b/source/buffer.h @@ -0,0 +1,88 @@ +/* $Id$ + +This file is part of libmspgl +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_GL_BUFFER_H_ +#define MSP_GL_BUFFER_H_ + +#include "types.h" + +namespace Msp { +namespace GL { + +enum BufferType +{ + ARRAY_BUFFER = GL_ARRAY_BUFFER_ARB, + ELEMENT_ARRAY_BUFFER = GL_ELEMENT_ARRAY_BUFFER_ARB, + PIXEL_PACK_BUFFER = GL_PIXEL_PACK_BUFFER_ARB, + PIXEL_UNPACK_BUFFER = GL_PIXEL_UNPACK_BUFFER_ARB +}; + +enum BufferUsage +{ + STREAM_DRAW = GL_STREAM_DRAW_ARB, + STREAM_READ = GL_STREAM_READ_ARB, + STREAM_COPY = GL_STREAM_COPY_ARB, + STATIC_DRAW = GL_STATIC_DRAW_ARB, + STATIC_READ = GL_STATIC_READ_ARB, + STATIC_COPY = GL_STATIC_COPY_ARB, + DYNAMIC_DRAW = GL_DYNAMIC_DRAW_ARB, + DYNAMIC_READ = GL_DYNAMIC_READ_ARB, + DYNAMIC_COPY = GL_DYNAMIC_COPY_ARB +}; + +/** +A buffer for storing data in GL memory. Putting vertex and index data in +buffers can improve rendering performance. The VertexArray and Mesh classes +contain built-in support for buffers. +*/ +class Buffer +{ +private: + BufferType type; + BufferUsage usage; + unsigned id; + + static const Buffer *bound[4]; + +public: + Buffer(BufferType); + ~Buffer(); + + /** Binds the buffer in its default slot. */ + void bind() const { bind(type); } + + /** Binds the buffer in an alternate slot. */ + void bind(BufferType) const; + +private: + void maybe_bind() const; + +public: + /** Unbinds the buffer from its default slot. */ + void unbind() const { unbind(type); } + + /** Sets the usage hint of the buffer. It will take effect the next time + the buffer's contents are defined. */ + void set_usage(BufferUsage); + + /** Uploads data into the buffer, completely replacing any previous + contents. */ + void data(unsigned, const void *); + + /** Overwrites part of the buffer data with new data. The buffer size can + not be changed with this call. */ + void sub_data(unsigned, unsigned, const void *); + + static void unbind(BufferType); +private: + static const Buffer *&binding(BufferType); +}; + +} // namespace GL +} // namespace Msp + +#endif diff --git a/source/immediate.cpp b/source/immediate.cpp index e12ac9b5..a387d71b 100644 --- a/source/immediate.cpp +++ b/source/immediate.cpp @@ -15,12 +15,20 @@ Immediate::Immediate(VertexFormat f): array(f) { } +void Immediate::reset() +{ + if(in_batch) + throw InvalidState("Can't reset Immediate between begin() and end()"); + + array.clear(); + indices.clear(); +} + void Immediate::end_() { array.apply(); draw_elements(type, indices.size(), &indices[0]); - array.clear(); indices.clear(); } diff --git a/source/immediate.h b/source/immediate.h index c4d8aca5..89380c41 100644 --- a/source/immediate.h +++ b/source/immediate.h @@ -28,6 +28,7 @@ private: public: Immediate(VertexFormat); + void reset(); private: virtual void begin_() { } virtual void end_(); diff --git a/source/mesh.cpp b/source/mesh.cpp index 7f50beb7..d43e0d0e 100644 --- a/source/mesh.cpp +++ b/source/mesh.cpp @@ -5,6 +5,7 @@ Copyright © 2007 Mikko Rasa, Mikkosoft Productions Distributed under the LGPL */ +#include "buffer.h" #include "mesh.h" using namespace std; @@ -13,24 +14,41 @@ namespace Msp { namespace GL { Mesh::Mesh(): - vertices(VERTEX3) + vertices(VERTEX3), + ibuf(0) { } -Mesh::Mesh(VertexFormat f): - vertices(f) +Mesh::Mesh(const VertexFormat &f): + vertices(f), + ibuf(0) { } void Mesh::use_vertex_buffer(bool b) { if(b) + { vertices.use_vertex_buffer(); + if(!ibuf) + ibuf=new Buffer(ELEMENT_ARRAY_BUFFER); + update_index_buffer(); + } else + { vertices.use_vertex_buffer(0); + delete ibuf; + ibuf=0; + } +} + +float *Mesh::get_vertex(unsigned i) +{ + return vertices[i]; } void Mesh::add_batch(const Batch &b) { batches.push_back(b); + update_index_buffer(); } void Mesh::clear() @@ -42,8 +60,41 @@ void Mesh::clear() void Mesh::draw() const { vertices.apply(); + if(ibuf) + { + ibuf->bind(); + unsigned offset=0; + for(list::const_iterator i=batches.begin(); i!=batches.end(); ++i) + { + i->draw_with_buffer(offset); + offset+=i->size(); + } + ibuf->unbind(); + } + else + { + for(list::const_iterator i=batches.begin(); i!=batches.end(); ++i) + i->draw(); + } +} + +void Mesh::update_index_buffer() +{ + if(!ibuf) + return; + + unsigned total=0; + for(list::const_iterator i=batches.begin(); i!=batches.end(); ++i) + total+=i->size(); + + ibuf->data(total*sizeof(unsigned), 0); + unsigned offset=0; for(list::const_iterator i=batches.begin(); i!=batches.end(); ++i) - i->draw(); + { + ibuf->sub_data(offset*sizeof(unsigned), i->size()*sizeof(unsigned), &i->get_indices()[0]); + offset+=i->size(); + } + ibuf->unbind(); } diff --git a/source/mesh.h b/source/mesh.h index 633cf3ab..0a4142fe 100644 --- a/source/mesh.h +++ b/source/mesh.h @@ -15,6 +15,8 @@ Distributed under the LGPL namespace Msp { namespace GL { +class Buffer; + class Mesh { friend class MeshBuilder; @@ -34,17 +36,21 @@ public: private: VertexArray vertices; std::list batches; + Buffer *ibuf; public: Mesh(); - Mesh(VertexFormat f); + Mesh(const VertexFormat &f); void use_vertex_buffer(bool); const VertexArray &get_vertices() const { return vertices; } + float *get_vertex(unsigned); void add_batch(const Batch &b); const std::list &get_batches() { return batches; } void clear(); void draw() const; +private: + void update_index_buffer(); }; } // namespace GL diff --git a/source/misc.h b/source/misc.h index e9ed91bf..7aa8aaf9 100644 --- a/source/misc.h +++ b/source/misc.h @@ -20,6 +20,31 @@ void set(GLenum, bool); void get(GLenum, int &); int get_i(GLenum); +class Bind +{ +private: + struct Base + { + virtual ~Base() { } + }; + + template + struct Binder: Base + { + const T &obj; + + Binder(const T &o): obj(o) { obj.bind(); } + ~Binder() { obj.unbind(); } + }; + + Base *binder; + +public: + template + Bind(const T &o): binder(new Binder(o)) { } + ~Bind() { delete binder; } +}; + } // namespace GL } // namespace Msp diff --git a/source/program.cpp b/source/program.cpp index 1b8ffe4d..75f982d7 100644 --- a/source/program.cpp +++ b/source/program.cpp @@ -108,7 +108,7 @@ string Program::get_info_log() const return string(log, len); } -void Program::bind() +void Program::bind() const { if(!linked) throw InvalidState("Program is not linked"); @@ -137,7 +137,7 @@ void Program::maybe_bind() bind(); } -Program *Program::cur_prog=0; +const Program *Program::cur_prog=0; Program::Loader::Loader(Program &p): diff --git a/source/program.h b/source/program.h index fde4d854..ad37fb65 100644 --- a/source/program.h +++ b/source/program.h @@ -27,7 +27,7 @@ private: bool del_shaders; bool linked; - static Program *cur_prog; + static const Program *cur_prog; public: class Loader: public DataFile::Loader @@ -61,7 +61,7 @@ public: int get_param(GLenum param) const; bool get_linked() const { return linked; } std::string get_info_log() const; - void bind(); + void bind() const; int get_uniform_location(const std::string &) const; static void unbind(); diff --git a/source/vertexarray.cpp b/source/vertexarray.cpp index 6740818e..a2b65daa 100644 --- a/source/vertexarray.cpp +++ b/source/vertexarray.cpp @@ -35,13 +35,13 @@ void VertexArray::use_vertex_buffer() if(vbuf && own_vbuf) return; - vbuf=new VertexBuffer(); + vbuf=new Buffer(ARRAY_BUFFER); own_vbuf=true; update_data(); } -void VertexArray::use_vertex_buffer(VertexBuffer *b) +void VertexArray::use_vertex_buffer(Buffer *b) { if(own_vbuf) delete vbuf; @@ -123,7 +123,7 @@ void VertexArray::apply() const set_array(i-4, (found>>i)&1, 1<unbind(); } /** @@ -134,7 +134,7 @@ void VertexArray::update_data() if(vbuf) { vbuf->data(data.size()*sizeof(float), &data[0]); - VertexBuffer::unbind(); + vbuf->unbind(); } } diff --git a/source/vertexarray.h b/source/vertexarray.h index ef7f6a24..281996d4 100644 --- a/source/vertexarray.h +++ b/source/vertexarray.h @@ -19,7 +19,7 @@ Distributed under the LGPL namespace Msp { namespace GL { -class VertexBuffer; +class Buffer; class VertexArray { @@ -34,7 +34,7 @@ private: VertexFormat format; std::vector data; uint stride; - VertexBuffer *vbuf; + Buffer *vbuf; bool own_vbuf; VertexArray(const VertexArray &); @@ -46,7 +46,7 @@ public: const VertexFormat &get_format() const { return format; } const std::vector &get_data() const { return data; } void use_vertex_buffer(); - void use_vertex_buffer(VertexBuffer *); + void use_vertex_buffer(Buffer *); void reserve(unsigned); unsigned size() const { return data.size()/stride; } void clear(); diff --git a/source/vertexbuffer.cpp b/source/vertexbuffer.cpp deleted file mode 100644 index 395334b3..00000000 --- a/source/vertexbuffer.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* $Id$ - -This file is part of libmspgl -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#include "arb_vertex_buffer_object.h" -#include "extension.h" -#include "vertexbuffer.h" - -namespace Msp { -namespace GL { - -VertexBuffer::VertexBuffer() -{ - static RequireExtension _ext("GL_ARB_vertex_buffer_object"); - - glGenBuffersARB(1, &id); -} - -void VertexBuffer::bind() const -{ - glBindBufferARB(GL_ARRAY_BUFFER, id); - bound=this; -} - -void VertexBuffer::data(sizei size, void *d) -{ - if(bound!=this) bind(); - - glBufferDataARB(GL_ARRAY_BUFFER, size, d, GL_STATIC_DRAW); -} - -VertexBuffer::~VertexBuffer() -{ - glDeleteBuffersARB(1, &id); -} - -void VertexBuffer::unbind() -{ - if(bound) - { - glBindBufferARB(GL_ARRAY_BUFFER, 0); - bound=0; - } -} - -const VertexBuffer *VertexBuffer::bound=0; - -} // namespace GL -} // namespace Msp diff --git a/source/vertexbuffer.h b/source/vertexbuffer.h index 815e2682..b0963fb3 100644 --- a/source/vertexbuffer.h +++ b/source/vertexbuffer.h @@ -8,24 +8,21 @@ Distributed under the LGPL #ifndef MSP_GL_VERTEXBUFFER_H_ #define MSP_GL_VERTEXBUFFER_H_ -#include "types.h" +#include "buffer.h" namespace Msp { namespace GL { -class VertexBuffer +/** +Deprecated. Equivalent to Buffer of type ARRAY_BUFFER. Retained for backwards +compatibility only. +*/ +class VertexBuffer: public Buffer { public: - VertexBuffer(); - void bind() const; - void data(sizei, void *); - ~VertexBuffer(); - - static void unbind(); -private: - uint id; + VertexBuffer(): Buffer(ARRAY_BUFFER) { } - static const VertexBuffer *bound; + static void unbind() { Buffer::unbind(ARRAY_BUFFER); } }; } // namespace GL -- 2.43.0