|
- use crate::{
- buffer::{Buffer, BufferRef, Target},
- error::Error,
- misc::{AsEnum, BindGuard, Bindable},
- };
-
- /* VertexArray */
-
- pub struct VertexArray<T = Buffer> {
- id: gl::GLuint,
- buffers: Vec<T>,
- }
-
- impl<T> VertexArray<T> {
- pub fn builder() -> Builder<T> {
- Builder::default()
- }
-
- pub fn buffers(&self) -> &[T] {
- &self.buffers
- }
-
- pub fn buffers_mut(&mut self) -> &mut [T] {
- &mut self.buffers
- }
- }
-
- impl<T> Drop for VertexArray<T> {
- fn drop(&mut self) {
- gl::delete_vertex_arrays(1, &self.id);
- }
- }
-
- impl<T> Bindable for VertexArray<T> {
- fn bind(&self) {
- gl::bind_vertex_array(self.id);
- }
-
- fn unbind(&self) {
- gl::bind_vertex_array(0);
- }
- }
-
- /* Builder */
-
- pub struct Builder<T> {
- bindings: Vec<Binding<T>>,
- }
-
- impl<T> Builder<T> {
- pub fn bind_buffer(mut self, buffer: T) -> BindingBuilder<T> {
- let binding = Binding {
- buffer,
- pointers: Vec::new(),
- };
-
- self.bindings.push(binding);
-
- BindingBuilder { builder: self }
- }
- }
-
- impl<T> Builder<T>
- where
- for<'a> &'a T: BufferRef,
- {
- pub fn build(self) -> Result<VertexArray<T>, Error> {
- let mut id = 0;
-
- Error::checked(|| gl::create_vertex_arrays(1, &mut id))?;
-
- let mut vertex_array = VertexArray {
- id,
- buffers: Vec::new(),
- };
-
- let guard = BindGuard::new(&vertex_array);
-
- let mut buffers = Vec::new();
- for binding in self.bindings {
- let guard = BindGuard::new((Target::ArrayBuffer, binding.buffer.as_ref()));
-
- for pointer in binding.pointers {
- Error::checked(|| gl::enable_vertex_attrib_array(pointer.index))?;
-
- match pointer.type_ {
- DataType::Byte
- | DataType::UnsignedByte
- | DataType::Short
- | DataType::UnsignedShort
- | DataType::Int
- | DataType::UnsignedInt => Error::checked(|| {
- gl::vertex_attrib_i_pointer(
- pointer.index,
- pointer.size,
- pointer.type_.as_enum(),
- pointer.stride,
- pointer.offset as *const _,
- )
- })?,
- _ => Error::checked(|| {
- gl::vertex_attrib_pointer(
- pointer.index,
- pointer.size,
- pointer.type_.as_enum(),
- if pointer.normalize {
- gl::TRUE
- } else {
- gl::FALSE
- },
- pointer.stride,
- pointer.offset as *const _,
- )
- })?,
- }
-
- if let Some(divisor) = pointer.divisor {
- Error::checked(|| gl::vertex_attrib_divisor(pointer.index, divisor))?;
- }
- }
-
- drop(guard);
-
- buffers.push(binding.buffer);
- }
-
- drop(guard);
-
- vertex_array.buffers = buffers;
-
- Ok(vertex_array)
- }
- }
-
- impl<T> Clone for Builder<T>
- where
- T: Clone,
- {
- fn clone(&self) -> Self {
- Self {
- bindings: self.bindings.clone(),
- }
- }
- }
-
- impl<T> Default for Builder<T> {
- fn default() -> Self {
- Self {
- bindings: Vec::new(),
- }
- }
- }
-
- /* BindingBuilder */
-
- pub struct BindingBuilder<T> {
- builder: Builder<T>,
- }
-
- impl<T> BindingBuilder<T> {
- pub fn bind_buffer(self, buffer: T) -> Self {
- self.builder.bind_buffer(buffer)
- }
-
- pub fn vertex_attrib_pointer(
- mut self,
- index: gl::GLuint,
- size: gl::GLint,
- type_: DataType,
- normalize: bool,
- stride: gl::GLsizei,
- offset: gl::GLsizei,
- ) -> Result<Self, Error> {
- for binding in &self.builder.bindings {
- for pointer in &binding.pointers {
- if pointer.index == index {
- return Err(Error::VertexArrayIndexAlreadyInUse(index));
- }
- }
- }
-
- let pointer = Pointer {
- index,
- size,
- type_,
- normalize,
- stride,
- offset,
- divisor: None,
- };
-
- self.builder
- .bindings
- .last_mut()
- .unwrap()
- .pointers
- .push(pointer);
-
- Ok(self)
- }
-
- pub fn vertex_attrib_divisor(mut self, divisor: gl::GLuint) -> Result<Self, Error> {
- let binding = self.builder.bindings.last_mut().unwrap();
- let pointer = binding
- .pointers
- .last_mut()
- .ok_or(Error::VertexArrayExpectedPointer)?;
-
- pointer.divisor = Some(divisor);
-
- Ok(self)
- }
- }
-
- impl<T> BindingBuilder<T>
- where
- for<'a> &'a T: BufferRef,
- {
- pub fn build(self) -> Result<VertexArray<T>, Error> {
- self.builder.build()
- }
- }
-
- impl<T> Clone for BindingBuilder<T>
- where
- T: Clone,
- {
- fn clone(&self) -> Self {
- Self {
- builder: self.builder.clone(),
- }
- }
- }
-
- /* DataType */
-
- #[allow(non_camel_case_types)]
- #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
- pub enum DataType {
- Byte,
- UnsignedByte,
- Short,
- UnsignedShort,
- Int,
- UnsignedInt,
- HalfFloat,
- Float,
- Double,
- Fixed,
- Int_2_10_10_10_Rev,
- UnsignedInt_2_10_10_10_Rev,
- UnsignedInt_10f_11f_11f_Rev,
- }
-
- impl AsEnum for DataType {
- fn as_enum(&self) -> gl::GLenum {
- match self {
- Self::Byte => gl::BYTE,
- Self::UnsignedByte => gl::UNSIGNED_BYTE,
- Self::Short => gl::SHORT,
- Self::UnsignedShort => gl::UNSIGNED_SHORT,
- Self::Int => gl::INT,
- Self::UnsignedInt => gl::UNSIGNED_INT,
- Self::HalfFloat => gl::HALF_FLOAT,
- Self::Float => gl::FLOAT,
- Self::Double => gl::DOUBLE,
- Self::Fixed => gl::FIXED,
- Self::Int_2_10_10_10_Rev => gl::INT_2_10_10_10_REV,
- Self::UnsignedInt_2_10_10_10_Rev => gl::UNSIGNED_INT_2_10_10_10_REV,
- Self::UnsignedInt_10f_11f_11f_Rev => gl::UNSIGNED_INT_10F_11F_11F_REV,
- }
- }
- }
-
- /* Binding */
-
- struct Binding<T> {
- buffer: T,
- pointers: Vec<Pointer>,
- }
-
- impl<T> Clone for Binding<T>
- where
- T: Clone,
- {
- fn clone(&self) -> Self {
- Self {
- buffer: self.buffer.clone(),
- pointers: self.pointers.clone(),
- }
- }
- }
-
- /* Pointer */
-
- #[derive(Clone, Debug)]
- pub struct Pointer {
- pub index: gl::GLuint,
- pub size: gl::GLint,
- pub type_: DataType,
- pub normalize: bool,
- pub stride: gl::GLsizei,
- pub offset: gl::GLsizei,
- pub divisor: Option<gl::GLuint>,
- }
|