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}