use std::mem::size_of; use crate::opengl::buffer::Buffer; use crate::vertex::Vertex; #[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)] const VERTEX_STRIDE: i32 = size_of::() as i32; #[derive(Debug)] pub struct VertexArray { array: gl::types::GLuint, } impl VertexArray { pub fn new() -> Self { let mut array = 0; unsafe { gl::CreateVertexArrays(1, &mut array); } Self { array } } /// Draws the currently bound vertex array. pub fn draw_arrays(primitive_kind: PrimitiveKind, start_index: u32, cnt: u32) { unsafe { #[allow(clippy::cast_possible_wrap)] gl::DrawArrays( primitive_kind.into_gl(), start_index as gl::types::GLint, cnt as gl::types::GLsizei, ); } } /// Draws the currently bound vertex array. pub fn draw_elements(primitive_kind: PrimitiveKind, offset: u32, cnt: u32) { unsafe { #[allow(clippy::cast_possible_wrap)] gl::DrawElements( primitive_kind.into_gl(), cnt as gl::types::GLsizei, gl::UNSIGNED_INT, (offset as gl::types::GLint) as *const _, ); } } pub fn bind_element_buffer(&mut self, element_buffer: &Buffer) { unsafe { gl::VertexArrayElementBuffer(self.array, element_buffer.object()); } } pub fn bind_vertex_buffer( &mut self, binding_index: u32, vertex_buffer: &Buffer, offset: isize, ) { unsafe { gl::VertexArrayVertexBuffer( self.array, binding_index, vertex_buffer.object(), offset, VERTEX_STRIDE, ); } } pub fn enable_attrib(&mut self, attrib_index: u32) { unsafe { gl::EnableVertexArrayAttrib(self.array, attrib_index as gl::types::GLuint); } } pub fn set_attrib_format( &mut self, attrib_index: u32, data_type: DataType, normalized: bool, offset: u32, ) { unsafe { #[allow(clippy::cast_possible_wrap)] gl::VertexArrayAttribFormat( self.array, attrib_index, data_type.size() as gl::types::GLint, data_type as u32, if normalized { gl::TRUE } else { gl::FALSE }, offset, ); } } /// Associate a vertex attribute and a vertex buffer binding. pub fn set_attrib_vertex_buf_binding( &mut self, attrib_index: u32, vertex_buf_binding_index: u32, ) { unsafe { gl::VertexArrayAttribBinding( self.array, attrib_index, vertex_buf_binding_index, ); } } pub fn bind(&self) { unsafe { gl::BindVertexArray(self.array) } } /// Does a weak clone of this vertex array. The vertex array itself is NOT copied in /// any way this function only copies the internal vertex array ID. /// /// # Safety /// The returned `VertexArray` must not be dropped if another `VertexArray` /// referencing the same vertex array ID is used later. pub unsafe fn clone_unsafe(&self) -> Self { Self { array: self.array } } } impl Drop for VertexArray { fn drop(&mut self) { unsafe { gl::DeleteVertexArrays(1, &self.array); } } } #[derive(Debug)] pub enum PrimitiveKind { Triangles, } impl PrimitiveKind { fn into_gl(self) -> gl::types::GLenum { match self { Self::Triangles => gl::TRIANGLES, } } } #[derive(Debug, Clone, Copy)] #[repr(u32)] pub enum DataType { Float = gl::FLOAT, } impl DataType { pub fn size(self) -> u32 { #[allow(clippy::cast_possible_truncation)] match self { Self::Float => size_of::() as u32, } } }