globject_rs/
glbuffer.rs

1
2use crate::prelude::*;
3use std::{
4	cmp::min,
5	ffi::c_void,
6	fmt::{self, Debug, Formatter},
7	mem::size_of,
8	rc::Rc,
9};
10
11/// The OpenGL buffer binding targets
12#[derive(Clone, Copy, PartialEq)]
13pub enum BufferTarget {
14	ArrayBuffer = GL_ARRAY_BUFFER as isize,
15	AtomicCounterBuffer = GL_ATOMIC_COUNTER_BUFFER as isize,
16	CopyReadBuffer = GL_COPY_READ_BUFFER as isize,
17	CopyWriteBuffer = GL_COPY_WRITE_BUFFER as isize,
18	DispatchIndirectBuffer = GL_DISPATCH_INDIRECT_BUFFER as isize,
19	DrawIndirectBuffer = GL_DRAW_INDIRECT_BUFFER as isize,
20	ElementArrayBuffer = GL_ELEMENT_ARRAY_BUFFER as isize,
21	PixelPackBuffer = GL_PIXEL_PACK_BUFFER as isize,
22	PixelUnpackBuffer = GL_PIXEL_UNPACK_BUFFER as isize,
23	QueryBuffer = GL_QUERY_BUFFER as isize,
24	ShaderStorageBuffer = GL_SHADER_STORAGE_BUFFER as isize,
25	TextureBuffer = GL_TEXTURE_BUFFER as isize,
26	TransformFeedbackBuffer = GL_TRANSFORM_FEEDBACK_BUFFER as isize,
27	UniformBuffer = GL_UNIFORM_BUFFER as isize,
28}
29
30/// The usage for the buffer
31#[derive(Clone, Copy, PartialEq)]
32pub enum BufferUsage {
33	StreamDraw = GL_STREAM_DRAW as isize,
34	StreamRead = GL_STREAM_READ as isize,
35	StreamCopy = GL_STREAM_COPY as isize,
36	StaticDraw = GL_STATIC_DRAW as isize,
37	StaticRead = GL_STATIC_READ as isize,
38	StaticCopy = GL_STATIC_COPY as isize,
39	DynamicDraw = GL_DYNAMIC_DRAW as isize,
40	DynamicRead = GL_DYNAMIC_READ as isize,
41	DynamicCopy = GL_DYNAMIC_COPY as isize,
42}
43
44/// The access flags for `glMapBuffers()`
45#[derive(Clone, Copy, PartialEq)]
46pub enum MapAccess {
47	ReadOnly = GL_READ_ONLY as isize,
48	WriteOnly = GL_WRITE_ONLY as isize,
49	ReadWrite = GL_READ_WRITE as isize,
50}
51
52/// The OpenGL buffer object
53pub struct Buffer {
54	pub glcore: Rc<GLCore>,
55	name: u32,
56	usage: BufferUsage,
57	target: BufferTarget,
58	size: usize,
59}
60
61/// When to use a buffer, must bind the buffer first. The RAII system could help automatically unbind the buffer.
62#[derive(Debug)]
63pub struct BufferBind<'a> {
64	pub buffer: &'a Buffer,
65	target: BufferTarget,
66}
67
68/// When to modify the buffer or retrieve the data from the buffer, use map to update the buffer.
69#[derive(Debug)]
70pub struct BufferMapping<'a> {
71	pub buffer: &'a Buffer,
72	target: BufferTarget,
73	access: MapAccess,
74	address: *mut c_void,
75}
76
77impl Buffer {
78	/// Get the internal name
79	pub fn get_name(&self) -> u32 {
80		self.name
81	}
82
83	/// Create a new OpenGL buffer with the specified size and data. The data could be `NULL`, indicating no initialization to the buffer.
84	pub fn new(glcore: Rc<GLCore>, target: BufferTarget, size: usize, usage: BufferUsage, data_ptr: *const c_void) -> Self {
85		let mut name: u32 = 0;
86		glcore.glGenBuffers(1, &mut name as *mut u32);
87		glcore.glBindBuffer(target as u32, name);
88		glcore.glBufferData(target as u32, size, data_ptr, usage as u32);
89		glcore.glBindBuffer(target as u32, 0);
90		Self {
91			glcore,
92			name,
93			usage,
94			target,
95			size,
96		}
97	}
98
99	/// Get the size of the buffer in bytes
100	pub fn size(&self) -> usize {
101		self.size
102	}
103
104	/// Get the default binding target
105	pub fn get_target(&self) -> BufferTarget {
106		self.target
107	}
108
109	/// Get the usage when initializing
110	pub fn get_usage(&self) -> BufferUsage {
111		self.usage
112	}
113
114	/// Resize the buffer. Actually, this operation will reallocate the buffer and copy the data.
115	pub fn resize<T: Copy + Sized>(&mut self, new_len: usize, value: T) {
116		let new_len = min(self.size, new_len);
117		let data = vec![value; new_len / size_of::<T>()];
118		let mut name: u32 = 0;
119		self.glcore.glGenBuffers(1, &mut name as *mut u32);
120		self.glcore.glBindBuffer(BufferTarget::CopyReadBuffer as u32, self.name);
121		self.glcore.glBindBuffer(BufferTarget::CopyWriteBuffer as u32, name);
122		self.glcore.glBufferData(BufferTarget::CopyWriteBuffer as u32, new_len,
123			if new_len > self.size {
124				data.as_ptr() as *const c_void
125			} else {
126				std::ptr::null()
127			},
128			self.usage as u32);
129		self.glcore.glCopyBufferSubData(BufferTarget::CopyReadBuffer as u32, BufferTarget::CopyWriteBuffer as u32, 0, 0, new_len);
130		self.glcore.glBindBuffer(BufferTarget::CopyReadBuffer as u32, 0);
131		self.glcore.glBindBuffer(BufferTarget::CopyWriteBuffer as u32, 0);
132		self.glcore.glDeleteBuffers(1, &self.name as *const u32);
133		self.name = name;
134	}
135
136	/// Set the default binding target
137	pub fn set_target(&mut self, target: BufferTarget) {
138		self.target = target;
139	}
140
141	/// Create a `BufferBind` to use the RAII system to manage the binding state.
142	pub fn bind<'a>(&'a self) -> BufferBind<'a> {
143		BufferBind::new(self, self.target)
144	}
145
146	/// Bind to a specific target. WILL NOT change the default target of the buffer. Create a `BufferBind` to use the RAII system to manage the binding state.
147	pub fn bind_to<'a>(&'a self, target: BufferTarget) -> BufferBind<'a> {
148		BufferBind::new(&*self, target)
149	}
150}
151
152impl Drop for Buffer {
153	/// Delete the OpenGL buffer on `drop()` called.
154	fn drop(&mut self) {
155		self.glcore.glDeleteBuffers(1, &self.name as *const u32);
156	}
157}
158
159impl Clone for Buffer {
160	fn clone(&self) -> Self {
161		let mut name: u32 = 0;
162		self.glcore.glGenBuffers(1, &mut name as *mut u32);
163		self.glcore.glBindBuffer(self.target as u32, name);
164		self.glcore.glBindBuffer(BufferTarget::CopyReadBuffer as u32, self.name);
165		self.glcore.glBufferData(BufferTarget::CopyWriteBuffer as u32, self.size, std::ptr::null(), self.usage as u32);
166		self.glcore.glCopyBufferSubData(BufferTarget::CopyReadBuffer as u32, self.target as u32, 0, 0, self.size);
167		self.glcore.glBindBuffer(self.target as u32, 0);
168		self.glcore.glBindBuffer(BufferTarget::CopyReadBuffer as u32, 0);
169		Self {
170			glcore: self.glcore.clone(),
171			name,
172			usage: self.usage,
173			target: self.target,
174			size: self.size,
175		}
176	}
177}
178
179impl Debug for Buffer {
180	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
181		f.debug_struct("Buffer")
182		.field("name", &self.name)
183		.field("usage", &self.usage)
184		.field("target", &self.target)
185		.field("size", &self.size)
186		.finish()
187	}
188}
189
190impl<'a> BufferBind<'a> {
191	/// Bind the buffer to the target
192	fn new(buffer: &'a Buffer, target: BufferTarget) -> Self {
193		buffer.glcore.glBindBuffer(target as u32, buffer.name);
194		Self {
195			buffer,
196			target,
197		}
198	}
199
200	/// Unbind the buffer
201	pub fn unbind(self) {} // Unbind by owning it in the function and `drop()`
202
203	/// Create a `BufferMapping` to use the RAII system to manage the mapping state.
204	pub fn map(&self, access: MapAccess) -> (BufferMapping<'a>, *mut c_void) {
205		BufferMapping::new(self.buffer, self.target, access)
206	}
207
208	/// Create a `BufferMapping` to use the RAII system to manage the mapping state, with partially mapped range.
209	pub fn map_ranged(&self, offset: usize, length: usize, access: MapAccess) -> (BufferMapping<'a>, *mut c_void) {
210		BufferMapping::new_ranged(self.buffer, self.target, offset, length, access)
211	}
212
213	/// Get the binding target
214	pub fn get_target(&self) -> BufferTarget {
215		self.target
216	}
217}
218
219impl<'a> Drop for BufferBind<'a> {
220	/// Unbind if dropped
221	fn drop(&mut self) {
222		self.buffer.glcore.glBindBuffer(self.target as u32, 0);
223	}
224}
225
226impl<'a> BufferMapping<'a> {
227	/// Map to the buffer to modify or retrieve the data of the buffer
228	fn new(buffer: &'a Buffer, target: BufferTarget, access: MapAccess) -> (Self, *mut c_void) {
229		let address = buffer.glcore.glMapBuffer(target as u32, access as u32);
230		(Self {
231			buffer,
232			target,
233			access,
234			address,
235		}, address)
236	}
237
238	/// Map to the buffer partially to modify or retrieve the data of the buffer
239	fn new_ranged(buffer: &'a Buffer, target: BufferTarget, offset: usize, length: usize, access: MapAccess) -> (Self, *mut c_void) {
240		let address = buffer.glcore.glMapBufferRange(target as u32, offset, length, access as u32);
241		(Self {
242			buffer,
243			target,
244			access,
245			address,
246		}, address)
247	}
248
249	/// Unmap the buffer
250	pub fn unmap(self) {} // Unmap by owning it in the function and `drop()`
251
252	/// Get the mapped target
253	pub fn get_target(&self) -> BufferTarget {
254		self.target
255	}
256
257	/// Get the mapped access
258	pub fn get_access(&self) -> MapAccess {
259		self.access
260	}
261
262	/// Get the mapping address
263	pub fn get_mapping_address(&self) -> *mut c_void {
264		self.address
265	}
266}
267
268impl<'a> Drop for BufferMapping<'a> {
269	/// Unmap the buffer when dropped
270	fn drop(&mut self) {
271		self.buffer.glcore.glUnmapBuffer(self.target as u32);
272	}
273}
274
275impl Debug for BufferTarget {
276	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
277		match self {
278			Self::ArrayBuffer => write!(f, "ArrayBuffer"),
279			Self::AtomicCounterBuffer => write!(f, "AtomicCounterBuffer"),
280			Self::CopyReadBuffer => write!(f, "CopyReadBuffer"),
281			Self::CopyWriteBuffer => write!(f, "CopyWriteBuffer"),
282			Self::DispatchIndirectBuffer => write!(f, "DispatchIndirectBuffer"),
283			Self::DrawIndirectBuffer => write!(f, "DrawIndirectBuffer"),
284			Self::ElementArrayBuffer => write!(f, "ElementArrayBuffer"),
285			Self::PixelPackBuffer => write!(f, "PixelPackBuffer"),
286			Self::PixelUnpackBuffer => write!(f, "PixelUnpackBuffer"),
287			Self::QueryBuffer => write!(f, "QueryBuffer"),
288			Self::ShaderStorageBuffer => write!(f, "ShaderStorageBuffer"),
289			Self::TextureBuffer => write!(f, "TextureBuffer"),
290			Self::TransformFeedbackBuffer => write!(f, "TransformFeedbackBuffer"),
291			Self::UniformBuffer => write!(f, "UniformBuffer"),
292		}
293	}
294}
295
296impl Debug for BufferUsage {
297	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
298		match self {
299			Self::StreamDraw => write!(f, "StreamDraw"),
300			Self::StreamRead => write!(f, "StreamRead"),
301			Self::StreamCopy => write!(f, "StreamCopy"),
302			Self::StaticDraw => write!(f, "StaticDraw"),
303			Self::StaticRead => write!(f, "StaticRead"),
304			Self::StaticCopy => write!(f, "StaticCopy"),
305			Self::DynamicDraw => write!(f, "DynamicDraw"),
306			Self::DynamicRead => write!(f, "DynamicRead"),
307			Self::DynamicCopy => write!(f, "DynamicCopy"),
308		}
309	}
310}
311
312impl Debug for MapAccess {
313	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
314		match self {
315			Self::ReadOnly => write!(f, "StreamDraw"),
316			Self::WriteOnly => write!(f, "StreamRead"),
317			Self::ReadWrite => write!(f, "StreamCopy"),
318		}
319	}
320}