Antkeeper  0.0.1
vertex-buffer.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 Christopher J. Howard
3  *
4  * This file is part of Antkeeper source code.
5  *
6  * Antkeeper source code is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Antkeeper source code is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
21 #include <stdexcept>
22 #include <glad/gl.h>
23 #include <utility>
24 
25 namespace gl {
26 
27 namespace
28 {
29  static constexpr GLenum buffer_usage_lut[] =
30  {
31  GL_STREAM_DRAW,
32  GL_STREAM_READ,
33  GL_STREAM_COPY,
34  GL_STATIC_DRAW,
35  GL_STATIC_READ,
36  GL_STATIC_COPY,
37  GL_DYNAMIC_DRAW,
38  GL_DYNAMIC_READ,
39  GL_DYNAMIC_COPY
40  };
41 }
42 
43 vertex_buffer::vertex_buffer(buffer_usage usage, std::size_t size, std::span<const std::byte> data):
44  m_usage{usage},
45  m_size{size}
46 {
47  if (!data.empty())
48  {
49  // Bounds check
50  if (data.size() < size)
51  {
52  throw std::out_of_range("Vertex buffer construct operation exceeded data bounds.");
53  }
54  }
55 
56  const GLenum gl_usage = buffer_usage_lut[std::to_underlying(m_usage)];
57  glCreateBuffers(1, &m_gl_named_buffer);
58  glNamedBufferData(m_gl_named_buffer, static_cast<GLsizeiptr>(m_size), data.empty() ? nullptr : data.data(), gl_usage);
59 }
60 
62  vertex_buffer(buffer.m_usage, buffer.m_size)
63 {
64  copy(buffer, m_size);
65 }
66 
68  m_gl_named_buffer{std::exchange(buffer.m_gl_named_buffer, 0)},
69  m_usage{std::move(buffer.m_usage)},
70  m_size{std::exchange(buffer.m_size, 0)}
71 {}
72 
74 {
75  if (m_gl_named_buffer)
76  {
77  glDeleteBuffers(1, &m_gl_named_buffer);
78  }
79 }
80 
82 {
83  repurpose(buffer.m_usage, buffer.m_size);
84  copy(buffer, m_size);
85 
86  return *this;
87 }
88 
90 {
91  if (m_gl_named_buffer)
92  {
93  glDeleteBuffers(1, &m_gl_named_buffer);
94  }
95 
96  m_gl_named_buffer = std::exchange(buffer.m_gl_named_buffer, 0);
97  m_usage = std::move(buffer.m_usage);
98  m_size = std::exchange(buffer.m_size, 0);
99 
100  return *this;
101 }
102 
103 void vertex_buffer::repurpose(buffer_usage usage, std::size_t size, std::span<const std::byte> data)
104 {
105  if (!data.empty())
106  {
107  // Bounds check
108  if (data.size() < size)
109  {
110  throw std::out_of_range("Vertex buffer resize operation exceeded data bounds.");
111  }
112  }
113 
114  m_usage = usage;
115  m_size = size;
116 
117  const auto gl_usage = buffer_usage_lut[std::to_underlying(m_usage)];
118  glNamedBufferData(m_gl_named_buffer, static_cast<GLsizeiptr>(m_size), data.empty() ? nullptr : data.data(), gl_usage);
119 }
120 
121 void vertex_buffer::write(std::size_t offset, std::span<const std::byte> data)
122 {
123  // Ignore empty write operations
124  if (data.empty())
125  {
126  return;
127  }
128 
129  // Bounds check
130  if (offset + data.size() > m_size)
131  {
132  throw std::out_of_range("Vertex buffer write operation exceeded buffer bounds.");
133  }
134 
135  glNamedBufferSubData(m_gl_named_buffer, static_cast<GLintptr>(offset), static_cast<GLsizeiptr>(data.size()), data.data());
136 }
137 
138 void vertex_buffer::read(std::size_t offset, std::span<std::byte> data) const
139 {
140  // Ignore empty read operations
141  if (data.empty())
142  {
143  return;
144  }
145 
146  // Bounds check
147  if (offset + data.size() > m_size)
148  {
149  throw std::out_of_range("Vertex buffer read operation exceeded buffer bounds.");
150  }
151 
152  glGetNamedBufferSubData(m_gl_named_buffer, static_cast<GLintptr>(offset), static_cast<GLsizeiptr>(data.size()), data.data());
153 }
154 
155 void vertex_buffer::copy(const vertex_buffer& read_buffer, std::size_t copy_size, std::size_t read_offset, std::size_t write_offset)
156 {
157  // Bounds check
158  if (read_offset + copy_size > read_buffer.m_size)
159  {
160  throw std::out_of_range("Vertex buffer copy operation exceeded read buffer bounds.");
161  }
162  if (write_offset + copy_size > m_size)
163  {
164  throw std::out_of_range("Vertex buffer copy operation exceeded write buffer bounds.");
165  }
166 
167  glCopyNamedBufferSubData(read_buffer.m_gl_named_buffer, m_gl_named_buffer, static_cast<GLintptr>(read_offset), static_cast<GLintptr>(write_offset), static_cast<GLsizeiptr>(copy_size));
168 }
169 
170 } // namespace gl
Vertex buffer object (VBO).
void repurpose(buffer_usage usage, std::size_t size, std::span< const std::byte > data={})
Repurposes the vertex buffer, changing its usage hint, size, and updating its data.
vertex_buffer()
Constructs a vertex buffer.
void copy(const vertex_buffer &read_buffer, std::size_t copy_size, std::size_t read_offset=0, std::size_t write_offset=0)
Copies a subset of another vertex buffer's data into this vertex buffer.
vertex_buffer & operator=(const vertex_buffer &buffer)
Copies another vertex buffer.
void write(std::size_t offset, std::span< const std::byte > data)
Writes data into the vertex buffer.
constexpr std::size_t size() const noexcept
Returns the size of the buffer's data, in bytes.
void read(std::size_t offset, std::span< std::byte > data) const
Reads a subset of the buffer's data from the GL and returns it to the application.
~vertex_buffer()
Destroys a vertex buffer.
constexpr buffer_usage usage() const noexcept
Return's the buffer's usage hint.
Graphics library interface.
Definition: window.hpp:28
buffer_usage
Usage hints for vertex buffers.
T offset(T longitude)
Calculates the UTC offset at a given longitude.
Definition: utc.hpp:38