tea/
buffer.rs

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);