--- /dev/null
+#ifndef MSP_GL_BUFFERABLE_H_
+#define MSP_GL_BUFFERABLE_H_
+
+namespace Msp {
+namespace GL {
+
+class Buffer;
+
+/**
+Base class for things that can store data in buffers. Supports buffer sharing.
+A dirty flag is provided for derived classes. It should be set when the data
+in the buffer is considered out of date, and is cleared by Bufferable after
+uploading fresh data to the buffer.
+*/
+class Bufferable
+{
+public:
+ class AsyncUpdater
+ {
+ private:
+ const Bufferable &bufferable;
+ char *mapped_address;
+
+ public:
+ AsyncUpdater(const Bufferable &);
+ ~AsyncUpdater();
+
+ void upload_data();
+ };
+
+private:
+ Buffer *buffer;
+ unsigned offset;
+ Bufferable *next_in_buffer;
+ Bufferable *prev_in_buffer;
+ mutable bool location_dirty;
+protected:
+ mutable bool dirty;
+
+ Bufferable();
+public:
+ virtual ~Bufferable();
+
+ /** Sets the buffer to use. If prev is not null, it must use the same
+ buffer, and this object is inserted after it. */
+ void use_buffer(Buffer *buf, Bufferable *prev = 0);
+
+ /** Sets the buffer for the entire chain of objects. */
+ void change_buffer(Buffer *);
+
+ /** Returns the total amount of storage required by this object and others
+ in the same chain, including any alignment between objects. */
+ unsigned get_required_buffer_size() const;
+
+ /** Uploads new data into the buffer if necessary. */
+ void refresh() const { if(buffer && dirty) upload_data(0); }
+
+ /** Returns an object which can be used to upload data to the buffer using
+ mapped memory. */
+ AsyncUpdater *refresh_async() const;
+
+private:
+ void unlink_from_buffer();
+
+public:
+ /** Returns the buffer in which the data is stored. */
+ const Buffer *get_buffer() const { return buffer; }
+
+protected:
+ /** Returns the amount of data to be stored in the buffer, in bytes. */
+ virtual unsigned get_data_size() const = 0;
+
+ /** Returns a pointer to the start of data in client memory. */
+ virtual const void *get_data_pointer() const = 0;
+
+ /** Returns the alignment required for the data, in bytes. The offset is
+ guaranteed to be a multiple of this. */
+ virtual unsigned get_alignment() const { return 1; }
+
+ /** Updates the offsets for the chain so that data from different objects
+ does not overlap. Should be called if either data size or alignment
+ changes. */
+ void update_offset();
+
+ /** Returns the offset where the data should be uploaded. */
+ unsigned get_offset() const { return offset; }
+
+ /** Called when the target buffer or offset within it has changed. */
+ virtual void location_changed(Buffer *, unsigned, unsigned) const { }
+
+private:
+ /** Uploads data to the buffer. Receives pointer to mapped buffer memory as
+ parameter, or null to use the buffer upload interface. */
+ void upload_data(char *) const;
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif