--- /dev/null
+#include <stdexcept>
+#include "buffer.h"
+#include "bufferable.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+Bufferable::Bufferable():
+ buffer(0),
+ buffer_offset(0),
+ next_in_buffer(0),
+ prev_in_buffer(0),
+ dirty(false)
+{ }
+
+Bufferable::~Bufferable()
+{
+ unlink_from_buffer();
+}
+
+void Bufferable::use_buffer(Buffer *buf, Bufferable *prev)
+{
+ if(prev && buf!=prev->buffer)
+ throw invalid_argument("Bufferable::use_buffer");
+
+ if(buffer)
+ unlink_from_buffer();
+
+ buffer = buf;
+ if(buffer)
+ {
+ prev_in_buffer = prev;
+ if(prev_in_buffer)
+ prev_in_buffer->next_in_buffer = this;
+ }
+
+ update_buffer_offsets();
+}
+
+void Bufferable::unlink_from_buffer()
+{
+ if(prev_in_buffer)
+ prev_in_buffer->next_in_buffer = next_in_buffer;
+ if(next_in_buffer)
+ {
+ next_in_buffer->prev_in_buffer = prev_in_buffer;
+ next_in_buffer->update_buffer_offsets();
+ }
+ prev_in_buffer = 0;
+ next_in_buffer = 0;
+}
+
+void Bufferable::update_buffer_offsets()
+{
+ unsigned offset = 0;
+ if(prev_in_buffer)
+ offset = prev_in_buffer->buffer_offset+prev_in_buffer->get_data_size();
+
+ if(offset!=buffer_offset)
+ {
+ buffer_offset = offset;
+ dirty = true;
+ }
+
+ if(next_in_buffer)
+ next_in_buffer->update_buffer_offsets();
+}
+
+void Bufferable::update_buffer_data() const
+{
+ const Bufferable *first = this;
+ for(; first->prev_in_buffer; first=first->prev_in_buffer) ;
+
+ unsigned total_size = 0;
+ for(const Bufferable *b=first; b; b=b->next_in_buffer)
+ total_size += b->get_data_size();
+
+ buffer->data(total_size, 0);
+ for(const Bufferable *b=first; b; b=b->next_in_buffer)
+ {
+ buffer->sub_data(b->buffer_offset, b->get_data_size(), b->get_data());
+ b->dirty = false;
+ }
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GL_BUFFERABLE_H_
+#define MSP_GL_BUFFERABLE_H_
+
+namespace Msp {
+namespace GL {
+
+class Buffer;
+
+class Bufferable
+{
+protected:
+ Buffer *buffer;
+ unsigned buffer_offset;
+ Bufferable *next_in_buffer;
+ Bufferable *prev_in_buffer;
+ mutable bool dirty;
+
+ Bufferable();
+public:
+ virtual ~Bufferable();
+
+ void use_buffer(Buffer *, Bufferable * = 0);
+private:
+ void unlink_from_buffer();
+
+protected:
+ virtual unsigned get_data_size() const = 0;
+ virtual const void *get_data() const = 0;
+
+ void update_buffer_offsets();
+ void update_buffer_data() const;
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif