|
- use crate::{
- buffer::{Buffer, Target},
- error::Error,
- misc::{AsEnum, BindGuard, Bindable},
- };
-
- /* VertexArray */
-
- pub struct VertexArray {
- id: gl::GLuint,
- buffers: Vec<Buffer>,
- }
-
- impl VertexArray {
- pub fn builder() -> Builder {
- Builder::default()
- }
-
- pub fn buffers(&self) -> &Vec<Buffer> {
- &self.buffers
- }
-
- pub fn buffers_mut(&mut self) -> &mut Vec<Buffer> {
- &mut self.buffers
- }
- }
-
- impl Drop for VertexArray {
- fn drop(&mut self) {
- gl::delete_vertex_arrays(1, &self.id);
- }
- }
-
- impl Bindable for VertexArray {
- fn bind(&self) {
- gl::bind_vertex_array(self.id);
- }
-
- fn unbind(&self) {
- gl::bind_vertex_array(0);
- }
- }
-
- /* Builder */
-
- #[derive(Default)]
- pub struct Builder {
- bindings: Vec<Binding>,
- }
-
- impl Builder {
- pub fn bind_buffer(mut self, buffer: Buffer) -> BindingBuilder {
- let binding = Binding {
- buffer,
- pointers: Vec::new(),
- };
-
- self.bindings.push(binding);
-
- BindingBuilder { builder: self }
- }
-
- pub fn build(self) -> Result<VertexArray, 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));
-
- for pointer in binding.pointers {
- Error::checked(|| gl::enable_vertex_attrib_array(pointer.index))?;
-
- 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)
- }
- }
-
- /* BindingBuilder */
-
- pub struct BindingBuilder {
- builder: Builder,
- }
-
- impl BindingBuilder {
- pub fn bind_buffer(self, buffer: Buffer) -> 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)
- }
-
- pub fn build(self) -> Result<VertexArray, Error> {
- self.builder.build()
- }
- }
-
- /* DataType */
-
- #[allow(non_camel_case_types)]
- 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 {
- buffer: Buffer,
- pointers: Vec<Pointer>,
- }
-
- /* Pointer */
-
- struct Pointer {
- index: gl::GLuint,
- size: gl::GLint,
- type_: DataType,
- normalize: bool,
- stride: gl::GLsizei,
- offset: gl::GLsizei,
- divisor: Option<gl::GLuint>,
- }
|