1use std::fmt::Display;
5use std::fmt::Formatter;
6use std::fmt::Result as FmtResult;
7use std::marker::PhantomData;
8use std::mem::offset_of;
9
10use anyhow::Context as _;
11use anyhow::Result;
12
13use crate::sys;
14use crate::sys::Gl as _;
15
16
17#[derive(Debug, Eq, PartialEq)]
18pub enum AttribType {
19 Position,
20 Normal,
21 Texture,
22 Color,
23}
24
25impl Display for AttribType {
26 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
27 let ty = match self {
28 Self::Position => "position",
29 Self::Normal => "normal",
30 Self::Texture => "texture",
31 Self::Color => "color",
32 };
33 f.write_str(ty)
34 }
35}
36
37
38#[derive(Debug)]
39pub struct Attrib {
40 pub size: i32,
41 pub type_: sys::Type,
42 pub normalize: bool,
43 pub stride: i32,
44 pub offset: i32,
45}
46
47pub trait Attribs {
48 const ATTRIBS: &'static [(AttribType, Attrib)];
49}
50
51
52#[derive(Debug, Default)]
54#[repr(C)]
55pub struct VertexP3f {
56 pub x: f32,
57 pub y: f32,
58 pub z: f32,
59}
60
61impl Attribs for VertexP3f {
62 const ATTRIBS: &'static [(AttribType, Attrib)] = &[(
63 AttribType::Position,
64 Attrib {
65 size: 3,
66 type_: sys::Type::Float,
67 normalize: false,
68 stride: size_of::<Self>() as _,
69 offset: 0,
70 },
71 )];
72}
73
74
75#[derive(Debug, Default)]
77#[repr(C)]
78pub struct VertexP3fT2f {
79 pub x: f32,
81 pub y: f32,
82 pub z: f32,
83 pub u: f32,
85 pub v: f32,
86}
87
88impl Attribs for VertexP3fT2f {
89 const ATTRIBS: &'static [(AttribType, Attrib)] = &[
90 (
91 AttribType::Position,
92 Attrib {
93 size: 3,
94 type_: sys::Type::Float,
95 normalize: false,
96 stride: size_of::<Self>() as _,
97 offset: 0,
98 },
99 ),
100 (
101 AttribType::Texture,
102 Attrib {
103 size: 2,
104 type_: sys::Type::Float,
105 normalize: false,
106 stride: size_of::<Self>() as _,
107 offset: offset_of!(Self, u) as _,
108 },
109 ),
110 ];
111}
112
113
114#[derive(Debug, Default)]
116#[repr(C)]
117pub struct VertexP3fN3f {
118 pub x: f32,
120 pub y: f32,
121 pub z: f32,
122 pub nx: f32,
124 pub ny: f32,
125 pub nz: f32,
126}
127
128impl Attribs for VertexP3fN3f {
129 const ATTRIBS: &'static [(AttribType, Attrib)] = &[
130 (
131 AttribType::Position,
132 Attrib {
133 size: 3,
134 type_: sys::Type::Float,
135 normalize: false,
136 stride: size_of::<Self>() as _,
137 offset: 0,
138 },
139 ),
140 (
141 AttribType::Normal,
142 Attrib {
143 size: 3,
144 type_: sys::Type::Float,
145 normalize: false,
146 stride: size_of::<Self>() as _,
147 offset: offset_of!(Self, nx) as _,
148 },
149 ),
150 ];
151}
152
153
154#[derive(Debug, Default)]
156#[repr(C)]
157pub struct VertexP3fT2fN3f {
158 pub x: f32,
160 pub y: f32,
161 pub z: f32,
162 pub u: f32,
164 pub v: f32,
165 pub nx: f32,
167 pub ny: f32,
168 pub nz: f32,
169}
170
171impl Attribs for VertexP3fT2fN3f {
172 const ATTRIBS: &'static [(AttribType, Attrib)] = &[
173 (
174 AttribType::Position,
175 Attrib {
176 size: 3,
177 type_: sys::Type::Float,
178 normalize: false,
179 stride: size_of::<Self>() as _,
180 offset: 0,
181 },
182 ),
183 (
184 AttribType::Texture,
185 Attrib {
186 size: 2,
187 type_: sys::Type::Float,
188 normalize: false,
189 stride: size_of::<Self>() as _,
190 offset: offset_of!(Self, u) as _,
191 },
192 ),
193 (
194 AttribType::Normal,
195 Attrib {
196 size: 3,
197 type_: sys::Type::Float,
198 normalize: false,
199 stride: size_of::<Self>() as _,
200 offset: offset_of!(Self, nx) as _,
201 },
202 ),
203 ];
204}
205
206
207#[derive(Debug)]
209pub struct VertexBuffer<T> {
210 context: sys::Context,
212 vbo: sys::VertexBufferObject,
214 target: sys::VertexBufferTarget,
216 count: usize,
218 _phantom: PhantomData<T>,
220}
221
222impl<T> VertexBuffer<T>
223where
224 T: Sized,
225{
226 #[inline]
227 pub fn from_vertices(
228 vertices: &[T],
229 usage: sys::VertexBufferUsage,
230 context: &sys::Context,
231 ) -> Result<Self> {
232 Self::from_data(sys::VertexBufferTarget::Array, usage, vertices, context)
233 }
234
235 #[inline]
236 pub fn from_indices(
237 indices: &[T],
238 usage: sys::VertexBufferUsage,
239 context: &sys::Context,
240 ) -> Result<Self> {
241 Self::from_data(
242 sys::VertexBufferTarget::ElementArray,
243 usage,
244 indices,
245 context,
246 )
247 }
248
249 fn from_data(
250 target: sys::VertexBufferTarget,
251 usage: sys::VertexBufferUsage,
252 data: &[T],
253 context: &sys::Context,
254 ) -> Result<Self> {
255 let vbo = context
256 .create_vertex_buffer()
257 .context("failed to create vertex buffer")?;
258
259 let slf = Self {
260 context: context.clone(),
261 vbo,
262 target,
263 count: data.len(),
264 _phantom: PhantomData,
265 };
266 let () = slf.bind();
267 let () = context.set_vertex_buffer_data(target, usage, data);
268 let () = slf.unbind();
269 Ok(slf)
270 }
271
272 pub fn update(&self, data: &[T], offset: usize) {
274 debug_assert!(
275 offset + data.len() <= self.count,
276 "{offset} | {} | {}",
277 data.len(),
278 self.count
279 );
280
281 let () = self.bind();
282 let () =
283 self
284 .context
285 .set_vertex_buffer_sub_data(self.target, data, i32::try_from(offset).unwrap());
286 let () = self.unbind();
287 }
288
289 #[inline]
290 pub fn bind(&self) {
291 let () = self
292 .context
293 .bind_vertex_buffer(self.target, Some(&self.vbo));
294 }
295
296 #[inline]
297 pub fn unbind(&self) {
298 let () = self.context.bind_vertex_buffer(self.target, None);
299 }
300
301 #[inline]
302 pub fn item_count(&self) -> usize {
303 self.count
304 }
305}
306
307impl<T> Drop for VertexBuffer<T> {
308 #[inline]
309 fn drop(&mut self) {
310 let () = self.context.delete_vertex_buffer(&self.vbo);
311 }
312}
313
314
315#[derive(Debug)]
317pub struct VertexArray {
318 context: sys::Context,
320 vao: sys::VertexArrayObject,
322}
323
324impl VertexArray {
325 pub fn new<V>(
326 vertex_buffer: &VertexBuffer<V>,
327 attrib_indices: &[(u32, AttribType)],
328 context: &sys::Context,
329 ) -> Result<Self>
330 where
331 V: Attribs,
332 {
333 let slf = Self {
334 context: context.clone(),
335 vao: context.create_vertex_array()?,
336 };
337 let () = slf.bind();
338 let () = vertex_buffer.bind();
339
340 let result = V::ATTRIBS.iter().try_for_each(|(attrib_type, attrib)| {
341 let (idx, _) = attrib_indices
342 .iter()
343 .find(|(_, ty)| ty == attrib_type)
344 .with_context(|| format!("failed to find {attrib_type} vertex attribute index"))?;
345
346 let () = context.enable_vertex_attrib_array(*idx);
347 let () = context.set_vertex_attrib_pointer(
348 *idx,
349 attrib.size,
350 attrib.type_,
351 attrib.normalize,
352 attrib.stride,
353 attrib.offset,
354 );
355 Ok(())
356 });
357
358 let () = vertex_buffer.unbind();
359 let () = slf.unbind();
360
361 result.map(|()| slf)
362 }
363
364 pub fn empty(context: &sys::Context) -> Result<Self> {
366 let slf = Self {
367 vao: context.create_vertex_array()?,
368 context: context.clone(),
369 };
370
371 Ok(slf)
372 }
373
374 #[inline]
375 pub fn bind(&self) {
376 let () = self.context.bind_vertex_array(Some(&self.vao));
377 }
378
379 #[inline]
380 fn unbind(&self) {
381 let () = self.context.bind_vertex_array(None);
382 }
383}
384
385impl Drop for VertexArray {
386 #[inline]
387 fn drop(&mut self) {
388 let () = self.context.delete_vertex_array(&self.vao);
389 }
390}