summaryrefslogtreecommitdiff
path: root/src/gl/buffer.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/gl/buffer.h')
-rw-r--r--src/gl/buffer.h206
1 files changed, 206 insertions, 0 deletions
diff --git a/src/gl/buffer.h b/src/gl/buffer.h
new file mode 100644
index 0000000..439533b
--- /dev/null
+++ b/src/gl/buffer.h
@@ -0,0 +1,206 @@
+// Copyright 2021 Benjamin Barenblat
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+// Buffer objects.
+
+#ifndef GLPLANET_SRC_GL_BUFFER_H_
+#define GLPLANET_SRC_GL_BUFFER_H_
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <concepts>
+#include <type_traits>
+#include <utility>
+
+#include "src/gl/error.h"
+#include "third_party/abseil/absl/types/span.h"
+#include "third_party/glew/include/GL/glew.h"
+
+namespace gl {
+
+// A byte buffer in GPU memory.
+class Buffer final {
+ public:
+ // The frequency with which data in the buffer will be accessed.
+ enum class AccessFrequency : uint8_t { kStatic, kStream, kDynamic };
+
+ // The type of that access.
+ enum class AccessNature : uint8_t { kDraw, kRead, kCopy };
+
+ explicit Buffer() noexcept(!(gl_internal::kThreadSafetyChecks ||
+ gl_internal::kAggressiveErrorChecking))
+ : size_bytes_(0),
+ frequency_(AccessFrequency::kStatic),
+ nature_(AccessNature::kDraw) {
+ gl_internal::CheckThreadSafety();
+ glCreateBuffers(1, &buffer_);
+ gl_internal::UnnecessaryErrorCheck();
+ }
+
+ Buffer(const Buffer&);
+
+ Buffer& operator=(const Buffer& other) {
+ if (this != &other) {
+ Buffer other2(other);
+ swap(*this, other2);
+ }
+ return *this;
+ }
+
+ Buffer(Buffer&& other) noexcept
+ : buffer_(0),
+ size_bytes_(0),
+ frequency_(AccessFrequency::kStatic),
+ nature_(AccessNature::kDraw) {
+ *this = std::move(other);
+ }
+
+ Buffer& operator=(Buffer&& other) noexcept {
+ swap(*this, other);
+ return *this;
+ }
+
+ ~Buffer() noexcept(!(gl_internal::kThreadSafetyChecks ||
+ gl_internal::kAggressiveErrorChecking)) {
+ gl_internal::CheckThreadSafety();
+ glDeleteBuffers(1, &buffer_);
+ gl_internal::UnnecessaryErrorCheck();
+ }
+
+ friend void swap(Buffer& left, Buffer& right) noexcept {
+ using ::std::swap;
+ swap(left.buffer_, right.buffer_);
+ swap(left.size_bytes_, right.size_bytes_);
+ swap(left.frequency_, right.frequency_);
+ swap(left.nature_, right.nature_);
+ }
+
+ // Loads data into the buffer.
+ void SetData(const void*, int size_bytes, AccessFrequency, AccessNature);
+
+ int size() const noexcept { return size_bytes_; }
+
+ // The GL identifier for this buffer.
+ unsigned int id() const noexcept { return buffer_; }
+
+ private:
+ GLuint buffer_;
+ int size_bytes_;
+ AccessFrequency frequency_;
+ AccessNature nature_;
+};
+
+// A vertex buffer object.
+class VertexBuffer final {
+ public:
+ explicit VertexBuffer() noexcept(!(gl_internal::kThreadSafetyChecks ||
+ gl_internal::kAggressiveErrorChecking)) =
+ default;
+
+ // A shorthand to construct the buffer and load data into it in one step.
+ template <typename T>
+ explicit VertexBuffer(absl::Span<const T> data,
+ Buffer::AccessFrequency frequency,
+ Buffer::AccessNature nature) {
+ SetData(data, frequency, nature);
+ }
+
+ VertexBuffer(const VertexBuffer&) = default;
+ VertexBuffer& operator=(const VertexBuffer&) = default;
+ VertexBuffer(VertexBuffer&&) = default;
+ VertexBuffer& operator=(VertexBuffer&&) = default;
+
+ // Loads data into the buffer.
+ template <typename T>
+ void SetData(absl::Span<const T> data, Buffer::AccessFrequency frequency,
+ Buffer::AccessNature nature) {
+ buffer_.SetData(data.data(), data.size() * sizeof(T), frequency, nature);
+ element_size_ = sizeof(T);
+ }
+
+ // The number of vertices in this buffer.
+ int size() const noexcept {
+ assert(buffer_.size() % element_size() == 0);
+ return buffer_.size() / element_size();
+ }
+
+ // The size, in bytes, of an individual vertex.
+ int element_size() const noexcept { return element_size_; }
+
+ // The GL identifier for this buffer.
+ unsigned int id() const noexcept { return buffer_.id(); }
+
+ private:
+ Buffer buffer_;
+ int element_size_;
+};
+
+// The types that can go in an element buffer.
+template <typename T>
+concept IsElement = std::same_as<T, uint8_t> || std::same_as<T, uint16_t> ||
+ std::same_as<T, uint32_t>;
+
+// An element buffer.
+class ElementBuffer final {
+ public:
+ explicit ElementBuffer() noexcept(!(gl_internal::kThreadSafetyChecks ||
+ gl_internal::kAggressiveErrorChecking)) =
+ default;
+
+ // Constructs an element buffer containing the specified data.
+ template <IsElement T>
+ explicit ElementBuffer(absl::Span<const T> data,
+ Buffer::AccessFrequency frequency,
+ Buffer::AccessNature nature) {
+ SetData(data, frequency, nature);
+ }
+
+ ElementBuffer(const ElementBuffer&) = default;
+ ElementBuffer& operator=(const ElementBuffer&) = default;
+ ElementBuffer(ElementBuffer&&) noexcept = default;
+ ElementBuffer& operator=(ElementBuffer&&) noexcept = default;
+
+ // Loads data into the buffer.
+ template <IsElement T>
+ void SetData(absl::Span<const T> data, Buffer::AccessFrequency frequency,
+ Buffer::AccessNature nature) {
+ buffer_.SetData(data.data(), data.size() * sizeof(T), frequency, nature);
+ element_size_ = sizeof(T);
+ }
+
+ // The number of elements in this buffer.
+ int size() const noexcept {
+ assert(buffer_.size() % element_size() == 0);
+ return buffer_.size() / element_size();
+ }
+
+ // The size, in bytes, of an individual element. This will always be 1, 2,
+ // or 4.
+ int element_size() const noexcept {
+ assert(element_size_ == 1 || element_size_ == 2 || element_size_ == 4);
+ return element_size_;
+ }
+
+ // The GL identifier for this buffer.
+ unsigned int id() const noexcept { return buffer_.id(); }
+
+ private:
+ Buffer buffer_;
+ int element_size_;
+};
+
+} // namespace gl
+
+#endif // GLPLANET_SRC_GL_BUFFER_H_