diff options
Diffstat (limited to 'include/mbgl/geometry/buffer.hpp')
-rw-r--r-- | include/mbgl/geometry/buffer.hpp | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/include/mbgl/geometry/buffer.hpp b/include/mbgl/geometry/buffer.hpp new file mode 100644 index 0000000000..20489cb33c --- /dev/null +++ b/include/mbgl/geometry/buffer.hpp @@ -0,0 +1,114 @@ +#ifndef MBGL_GEOMETRY_BUFFER +#define MBGL_GEOMETRY_BUFFER + +#include <mbgl/platform/gl.hpp> +#include <mbgl/util/noncopyable.hpp> + +#include <cstdlib> +#include <cassert> +#include <stdexcept> + +namespace mbgl { + +template < + size_t item_size, + int bufferType = GL_ARRAY_BUFFER, + size_t defaultLength = 8192, + bool retainAfterUpload = false +> +class Buffer : private util::noncopyable { +public: + ~Buffer() { + cleanup(); + if (buffer != 0) { + glDeleteBuffers(1, &buffer); + buffer = 0; + } + } + + // Returns the number of elements in this buffer. This is not the number of + // bytes, but rather the number of coordinates with associated information. + inline size_t index() const { + return pos / itemSize; + } + + inline bool empty() const { + return pos == 0; + } + + // Transfers this buffer to the GPU and binds the buffer to the GL context. + void bind(bool force = false) { + if (buffer == 0) { + glGenBuffers(1, &buffer); + force = true; + } + glBindBuffer(bufferType, buffer); + if (force) { + if (array == nullptr) { + throw std::runtime_error("Buffer was already deleted or doesn't contain elements"); + } + + glBufferData(bufferType, pos, array, GL_STATIC_DRAW); + if (!retainAfterUpload) { + cleanup(); + } + } + } + + void cleanup() { + if (array) { + free(array); + array = nullptr; + } + } + +protected: + // increase the buffer size by at least /required/ bytes. + inline void *addElement() { + if (buffer != 0) { + throw std::runtime_error("Can't add elements after buffer was bound to GPU"); + } + if (length < pos + itemSize) { + while (length < pos + itemSize) length += defaultLength; + array = realloc(array, length); + if (array == nullptr) { + throw std::runtime_error("Buffer reallocation failed¯"); + } + } + pos += itemSize; + return static_cast<char *>(array) + (pos - itemSize); + } + + // Get a pointer to the item at a given index. + inline void *getElement(size_t index) { + if (array == nullptr) { + throw std::runtime_error("Buffer was already deleted or doesn't contain elements"); + } + + if (index * itemSize >= pos) { + throw new std::runtime_error("Can't get element after array bounds"); + } else { + return static_cast<char *>(array) + (index * itemSize); + } + } + +public: + static const size_t itemSize = item_size; + +private: + // CPU buffer + void *array = nullptr; + + // Byte position where we are writing. + size_t pos = 0; + + // Number of bytes that are valid in this buffer. + size_t length = 0; + + // GL buffer ID + uint32_t buffer = 0; +}; + +} + +#endif |