1extern crate gl;
2
3use std::ffi::c_void;
4
5use gl::types::GLenum;
6use crate::*;
7
8#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Clone, Copy)]
9pub enum BufferUsage {
10 StaticRead,
11 StaticCopy,
12 StaticDraw,
13 StreamRead,
14 StreamCopy,
15 StreamDraw,
16 DynamicRead,
17 DynamicCopy,
18 #[default]
19 DynamicDraw
20}
21
22impl GlEnum for BufferUsage {
23 fn to_enum(&self) -> GLenum {
24 match self {
25 BufferUsage::StaticRead => { gl::STATIC_READ },
26 BufferUsage::StaticCopy => { gl::STATIC_COPY },
27 BufferUsage::StaticDraw => { gl::STATIC_DRAW },
28 BufferUsage::StreamRead => { gl::STREAM_READ },
29 BufferUsage::StreamCopy => { gl::STREAM_COPY },
30 BufferUsage::StreamDraw => { gl::STREAM_DRAW },
31 BufferUsage::DynamicRead => { gl::DYNAMIC_READ },
32 BufferUsage::DynamicCopy => { gl::DYNAMIC_COPY },
33 BufferUsage::DynamicDraw => { gl::DYNAMIC_DRAW }
34 }
35 }
36}
37
38pub trait GlBuffer: GlObject + GlBind + GlTarget {
39 fn data<T: Sized>(&self, data: &Vec<T>, usage: BufferUsage) {
40 let size = std::mem::size_of::<T>() * data.capacity();
41 let ptr: *const c_void;
42 if data.is_empty() { ptr = std::ptr::null(); }
43 else { ptr = data.as_ptr() as *const c_void; }
44 unsafe {
45 gl::BufferData(Self::target(), size as isize, ptr, usage.to_enum());
46 }
47 }
48
49 fn subdata<T: Sized>(&self, offset: isize, count: usize, data: &Vec<T>) {
50 let size = std::mem::size_of::<T>() * count;
51 let ptr: *const c_void;
52 if data.is_empty() { ptr = std::ptr::null(); }
53 else { ptr = data.as_ptr() as *const c_void; }
54 unsafe {
55 gl::BufferSubData(Self::target(), offset, size as isize, ptr);
56 }
57 }
58
59 fn bind_read(&self) {
60 unsafe { gl::BindBuffer(gl::COPY_READ_BUFFER, self.get_id()) };
61 }
62
63 fn bind_write(&self) {
64 unsafe { gl::BindBuffer(gl::COPY_WRITE_BUFFER, self.get_id()) };
65 }
66
67 fn copy(&self, read_offset: isize, write_offset: isize, size: isize) {
68 unsafe { gl::CopyBufferSubData(gl::COPY_READ_BUFFER, gl::COPY_WRITE_BUFFER, read_offset, write_offset, size) };
69 }
70
71 fn copy_from(&self, other: impl GlBuffer, read_offset: isize, write_offset: isize, size: isize) {
72 other.bind_read();
73 unsafe { gl::CopyBufferSubData(gl::COPY_READ_BUFFER, gl::COPY_WRITE_BUFFER, read_offset, write_offset, size) };
74 }
75
76 fn is_binded(&self) -> bool {
77 Self::current_bind() == self.get_id()
78 }
79}
80
81macro_rules! impl_buffer {
82 ($Name: ident, $target: expr, $binding: expr) => {
83 #[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord)]
84 pub struct $Name(u32);
85
86 impl $Name {
87 pub fn new() -> Self {
88 let mut handle = 0;
89 unsafe { gl::GenBuffers(1, &mut handle) };
90 Self(handle)
91 }
92 }
93
94 impl GlObject for $Name {
95 fn get_id(&self) -> u32 { self.0 }
96 }
97
98 impl GlTarget for $Name {
99 fn target() -> u32 { $target }
100 fn binding() -> u32 { $binding }
101 }
102
103 impl GlBind for $Name {
104 fn bind(&self) {
105 unsafe { gl::BindBuffer(Self::target(), self.0) };
106 }
107
108 fn unbind(&self) {
109 unsafe { gl::BindBuffer(Self::target(), 0) };
110 }
111 }
112
113 impl GlBuffer for $Name {}
114
115 impl Drop for $Name {
116 fn drop(&mut self) {
117 unsafe { gl::DeleteBuffers(1, &mut self.0) };
118 }
119 }
120 }
121}
122
123impl_buffer!(ArrayBuffer, gl::ARRAY_BUFFER, gl::ARRAY_BUFFER_BINDING);
124impl_buffer!(ElementArrayBuffer, gl::ELEMENT_ARRAY_BUFFER, gl::ELEMENT_ARRAY_BUFFER_BINDING);
125impl_buffer!(UniformBuffer, gl::UNIFORM_BUFFER, gl::UNIFORM_BUFFER_BINDING);
126impl_buffer!(TextureBuffer, gl::TEXTURE_BUFFER, gl::TEXTURE_BUFFER_BINDING);