tea/
vertex.rs

1use crate::{GlBind, GlObject, GlTarget, GlAttrib};
2use std::ffi::c_void;
3
4static mut CURRENT_VAO: u32 = 0;
5
6pub trait VertexData {
7    type Output;
8    fn stride() -> usize {
9        std::mem::size_of::<Self::Output>()
10    }
11
12    fn get_format() -> VertexFormat;
13}
14
15#[derive(Default, Debug, PartialEq, Eq, Clone)]
16pub struct VertexFormat(Vec<AttribSlot>);
17
18impl VertexFormat {
19    pub fn attribs(&self) -> &Vec<AttribSlot> {
20        &self.0
21    }
22}
23
24#[derive(Default, Debug)]
25pub struct VertexFormatBuilder {
26    location: u32,
27    offset: i32,
28    format: VertexFormat,
29}
30
31impl VertexFormatBuilder {
32    pub fn new() -> Self {
33        VertexFormatBuilder::default()
34    }
35
36    pub fn push<T: GlAttrib>(&mut self, normalized: bool) -> &mut Self {
37        let attrib = AttribSlot {
38            location: self.location,
39            type_: T::gl_enum(),
40            size: T::size() as i32,
41            normalized,
42            offset: self.offset
43        };
44        self.location += 1;
45        self.offset += T::stride() as i32;
46        self.format.0.push(attrib);
47        self
48    }
49
50    pub fn build(&self) -> VertexFormat {
51        self.format.clone()
52    }
53}
54
55#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
56pub struct AttribSlot {
57    pub location: u32,
58    pub type_: u32,
59    pub size: i32,
60    pub normalized: bool,
61    pub offset: i32
62}
63
64impl AttribSlot {
65    pub fn new<T: GlAttrib>(location: u32, normalized: bool, offset: i32) -> AttribSlot {
66        AttribSlot {
67            location,
68            type_: T::gl_enum(),
69            size: T::size() as i32,
70            normalized,
71            offset
72        }
73    }
74}
75
76#[derive(Default, Debug, PartialEq, Eq, Ord, PartialOrd)]
77pub struct VertexArray(u32);
78
79impl VertexArray {
80    pub fn new() -> Result<VertexArray, String> {
81        let mut handle: u32 = 0;
82        unsafe { gl::GenVertexArrays(1, &mut handle) };
83        Ok(VertexArray(handle))
84    }
85
86    pub fn check_bind(&self) {
87        let cur_vao = Self::current_bind();
88        assert_eq!(cur_vao, self.0);
89    }
90
91    pub fn setup_for<T: VertexData>(&self) {
92        self.check_bind();
93        let format = T::get_format();
94        for a in format.0 {
95            unsafe {
96                gl::EnableVertexAttribArray(a.location);
97                gl::VertexAttribPointer(a.location, a.size, a.type_, a.normalized as u8, T::stride() as i32, a.offset as *const c_void);
98            }
99            println!("{:?}", a);
100
101        }
102    }
103
104    pub fn enable_attrib(&self, index: u32) {
105        unsafe { gl::EnableVertexAttribArray(index) };
106    }
107
108    pub fn attrib_pointer<T: GlAttrib>(&self, index: u32, stride: i32, start: i32) {
109        T::setup_attrib(index, false, stride, start);
110    }
111}
112
113impl GlBind for VertexArray {
114    fn bind(&self) {
115        unsafe { CURRENT_VAO = self.0 };
116        unsafe { gl::BindVertexArray(self.0) };
117    }
118
119    fn unbind(&self) {
120        unsafe {
121            gl::BindVertexArray(0);
122            CURRENT_VAO = 0;
123        }
124    }
125}
126
127impl GlTarget for VertexArray {
128    fn target() -> u32 { gl::NONE }
129    fn binding() -> u32 { gl::VERTEX_ARRAY_BINDING }
130    fn current_bind() -> u32 { unsafe { CURRENT_VAO } }
131}
132
133impl GlObject for VertexArray {
134    fn get_id(&self) -> u32 {
135        self.0
136    }
137}
138
139impl Drop for VertexArray {
140    fn drop(&mut self) {
141        unsafe { gl::DeleteVertexArrays(1, &self.0) };
142    }
143}
144
145#[macro_export]
146macro_rules! impl_vertexdata {
147    ($Name: ident, $($field: ident),+) => {
148        #[repr(C)]
149        #[derive(Debug, Copy, Clone)]
150        pub struct $Name($($field),+);
151        
152        impl VertexData for $Name {
153            type Output = $Name;
154            fn get_format() -> VertexFormat {
155                VertexFormatBuilder::new()
156                    $(.push::<$field>(false))+
157                    .build()
158            }
159        }
160    };
161}