| @@ -3,7 +3,10 @@ use std::ops::{Deref, DerefMut}; | |||
| use std::ptr::null; | |||
| use std::slice::from_raw_parts_mut; | |||
| use crate::{error::Error, misc::AsEnum}; | |||
| use crate::{ | |||
| error::Error, | |||
| misc::{AsEnum, Bindable}, | |||
| }; | |||
| /* ArrayBuffer */ | |||
| @@ -30,14 +33,6 @@ impl ArrayBuffer { | |||
| self.id | |||
| } | |||
| pub fn bind(&self) { | |||
| gl::bind_buffer(self.target.as_enum(), self.id); | |||
| } | |||
| pub fn unbind(&self) { | |||
| gl::bind_buffer(self.target.as_enum(), 0); | |||
| } | |||
| pub fn buffer_data<T>(&mut self, usage: Usage, data: &[T]) -> Result<(), Error> { | |||
| let size = data.len() * size_of::<T>(); | |||
| @@ -147,6 +142,16 @@ impl ArrayBuffer { | |||
| } | |||
| } | |||
| impl Bindable for ArrayBuffer { | |||
| fn bind(&self) { | |||
| gl::bind_buffer(self.target.as_enum(), self.id); | |||
| } | |||
| fn unbind(&self) { | |||
| gl::bind_buffer(self.target.as_enum(), 0); | |||
| } | |||
| } | |||
| /* Map */ | |||
| pub struct Map<'a, T> { | |||
| @@ -20,6 +20,9 @@ pub enum Error { | |||
| #[error("Error while linking shader program: {0}")] | |||
| ShaderLink(String), | |||
| #[error("Vertex Array Index is already in use: {0}!")] | |||
| VertexArrayIndexAlreadyInUse(gl::GLuint), | |||
| #[error("Invalid Parameter!")] | |||
| InvalidParameter, | |||
| } | |||
| @@ -2,3 +2,4 @@ pub mod array_buffer; | |||
| pub mod error; | |||
| pub mod misc; | |||
| pub mod shader; | |||
| pub mod vertex_array; | |||
| @@ -1,3 +1,48 @@ | |||
| pub trait AsEnum { | |||
| fn as_enum(&self) -> gl::GLenum; | |||
| } | |||
| pub trait Bindable { | |||
| fn bind(&self); | |||
| fn unbind(&self); | |||
| } | |||
| pub struct BindGuard<T> | |||
| where | |||
| T: Bindable, | |||
| { | |||
| bindable: T, | |||
| } | |||
| impl<T> BindGuard<T> | |||
| where | |||
| T: Bindable, | |||
| { | |||
| pub fn new(bindable: T) -> Self { | |||
| bindable.bind(); | |||
| Self { bindable } | |||
| } | |||
| } | |||
| impl<T> Drop for BindGuard<T> | |||
| where | |||
| T: Bindable, | |||
| { | |||
| fn drop(&mut self) { | |||
| self.bindable.unbind() | |||
| } | |||
| } | |||
| impl<T> Bindable for &T | |||
| where | |||
| T: Bindable, | |||
| { | |||
| fn bind(&self) { | |||
| (*self).bind(); | |||
| } | |||
| fn unbind(&self) { | |||
| (*self).bind(); | |||
| } | |||
| } | |||
| @@ -3,7 +3,10 @@ use std::path::Path; | |||
| use std::ptr::{null, null_mut}; | |||
| use std::str::from_utf8; | |||
| use crate::{error::Error, misc::AsEnum}; | |||
| use crate::{ | |||
| error::Error, | |||
| misc::{AsEnum, Bindable}, | |||
| }; | |||
| /* Programm */ | |||
| @@ -66,14 +69,6 @@ impl Program { | |||
| pub fn id(&self) -> gl::GLuint { | |||
| self.id | |||
| } | |||
| pub fn bind(&self) { | |||
| gl::use_program(self.id); | |||
| } | |||
| pub fn unbind(&self) { | |||
| gl::use_program(0); | |||
| } | |||
| } | |||
| impl Drop for Program { | |||
| @@ -82,6 +77,16 @@ impl Drop for Program { | |||
| } | |||
| } | |||
| impl Bindable for Program { | |||
| fn bind(&self) { | |||
| gl::use_program(self.id); | |||
| } | |||
| fn unbind(&self) { | |||
| gl::use_program(0); | |||
| } | |||
| } | |||
| /* Shader */ | |||
| pub struct Shader { | |||
| @@ -0,0 +1,204 @@ | |||
| use crate::{ | |||
| array_buffer::ArrayBuffer, | |||
| error::Error, | |||
| misc::{AsEnum, BindGuard, Bindable}, | |||
| }; | |||
| /* VertexArray */ | |||
| pub struct VertexArray { | |||
| id: gl::GLuint, | |||
| buffers: Vec<ArrayBuffer>, | |||
| } | |||
| impl VertexArray { | |||
| pub fn builder() -> Builder { | |||
| Builder::default() | |||
| } | |||
| pub fn buffers(&self) -> &Vec<ArrayBuffer> { | |||
| &self.buffers | |||
| } | |||
| pub fn buffers_mut(&mut self) -> &mut Vec<ArrayBuffer> { | |||
| &mut self.buffers | |||
| } | |||
| } | |||
| 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: ArrayBuffer) -> 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 vertex_array = VertexArray { | |||
| id, | |||
| buffers: Vec::new(), | |||
| }; | |||
| let guard = BindGuard::new(&vertex_array); | |||
| for binding in self.bindings { | |||
| let _guard = BindGuard::new(&binding.buffer); | |||
| for pointer in binding.pointers { | |||
| Error::checked(|| { | |||
| gl::enable_vertex_attrib_array(pointer.index); | |||
| 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 _, | |||
| ) | |||
| })?; | |||
| } | |||
| } | |||
| drop(guard); | |||
| Ok(vertex_array) | |||
| } | |||
| } | |||
| /* BindingBuilder */ | |||
| pub struct BindingBuilder { | |||
| builder: Builder, | |||
| } | |||
| impl BindingBuilder { | |||
| pub fn bind_buffer(self, buffer: ArrayBuffer) -> 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, | |||
| }; | |||
| self.builder | |||
| .bindings | |||
| .last_mut() | |||
| .unwrap() | |||
| .pointers | |||
| .push(pointer); | |||
| 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: ArrayBuffer, | |||
| pointers: Vec<Pointer>, | |||
| } | |||
| /* Pointer */ | |||
| struct Pointer { | |||
| index: gl::GLuint, | |||
| size: gl::GLint, | |||
| type_: DataType, | |||
| normalize: bool, | |||
| stride: gl::GLsizei, | |||
| offset: gl::GLsizei, | |||
| } | |||
| @@ -4,13 +4,14 @@ use async_ecs::System; | |||
| use glc::{ | |||
| array_buffer::{ArrayBuffer, Target, Usage}, | |||
| shader::{Program, Shader, Type}, | |||
| vertex_array::{DataType, VertexArray}, | |||
| }; | |||
| use crate::Error; | |||
| pub struct Background { | |||
| program: Program, | |||
| array_buffer: ArrayBuffer, | |||
| vertex_array: VertexArray, | |||
| } | |||
| impl Background { | |||
| @@ -53,9 +54,21 @@ impl Background { | |||
| }; | |||
| } | |||
| const STRIDE_POS: gl::GLsizei = size_of::<Vertex>() as gl::GLsizei; | |||
| const STRIDE_TEX: gl::GLsizei = size_of::<Vertex>() as gl::GLsizei; | |||
| const OFFSET_POS: gl::GLsizei = 0; | |||
| const OFFSET_TEX: gl::GLsizei = 2 * size_of::<f32>() as gl::GLsizei; | |||
| let vertex_array = VertexArray::builder() | |||
| .bind_buffer(array_buffer) | |||
| .vertex_attrib_pointer(0, 2, DataType::Float, false, STRIDE_POS, OFFSET_POS)? | |||
| .vertex_attrib_pointer(1, 2, DataType::Float, false, STRIDE_TEX, OFFSET_TEX)? | |||
| .build()?; | |||
| Ok(Self { | |||
| program, | |||
| array_buffer, | |||
| vertex_array, | |||
| }) | |||
| } | |||
| } | |||
| @@ -65,7 +78,7 @@ impl<'a> System<'a> for Background { | |||
| fn run(&mut self, (): Self::SystemData) { | |||
| let _program = &self.program; | |||
| let _array_buffer = &self.array_buffer; | |||
| let _vertex_array = &self.vertex_array; | |||
| gl::clear_color(0.1, 0.1, 0.1, 1.0); | |||
| gl::clear(gl::COLOR_BUFFER_BIT); | |||