| @@ -3,7 +3,10 @@ use std::ops::{Deref, DerefMut}; | |||||
| use std::ptr::null; | use std::ptr::null; | ||||
| use std::slice::from_raw_parts_mut; | use std::slice::from_raw_parts_mut; | ||||
| use crate::{error::Error, misc::AsEnum}; | |||||
| use crate::{ | |||||
| error::Error, | |||||
| misc::{AsEnum, Bindable}, | |||||
| }; | |||||
| /* ArrayBuffer */ | /* ArrayBuffer */ | ||||
| @@ -30,14 +33,6 @@ impl ArrayBuffer { | |||||
| self.id | 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> { | pub fn buffer_data<T>(&mut self, usage: Usage, data: &[T]) -> Result<(), Error> { | ||||
| let size = data.len() * size_of::<T>(); | 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 */ | /* Map */ | ||||
| pub struct Map<'a, T> { | pub struct Map<'a, T> { | ||||
| @@ -20,6 +20,9 @@ pub enum Error { | |||||
| #[error("Error while linking shader program: {0}")] | #[error("Error while linking shader program: {0}")] | ||||
| ShaderLink(String), | ShaderLink(String), | ||||
| #[error("Vertex Array Index is already in use: {0}!")] | |||||
| VertexArrayIndexAlreadyInUse(gl::GLuint), | |||||
| #[error("Invalid Parameter!")] | #[error("Invalid Parameter!")] | ||||
| InvalidParameter, | InvalidParameter, | ||||
| } | } | ||||
| @@ -2,3 +2,4 @@ pub mod array_buffer; | |||||
| pub mod error; | pub mod error; | ||||
| pub mod misc; | pub mod misc; | ||||
| pub mod shader; | pub mod shader; | ||||
| pub mod vertex_array; | |||||
| @@ -1,3 +1,48 @@ | |||||
| pub trait AsEnum { | pub trait AsEnum { | ||||
| fn as_enum(&self) -> gl::GLenum; | 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::ptr::{null, null_mut}; | ||||
| use std::str::from_utf8; | use std::str::from_utf8; | ||||
| use crate::{error::Error, misc::AsEnum}; | |||||
| use crate::{ | |||||
| error::Error, | |||||
| misc::{AsEnum, Bindable}, | |||||
| }; | |||||
| /* Programm */ | /* Programm */ | ||||
| @@ -66,14 +69,6 @@ impl Program { | |||||
| pub fn id(&self) -> gl::GLuint { | pub fn id(&self) -> gl::GLuint { | ||||
| self.id | self.id | ||||
| } | } | ||||
| pub fn bind(&self) { | |||||
| gl::use_program(self.id); | |||||
| } | |||||
| pub fn unbind(&self) { | |||||
| gl::use_program(0); | |||||
| } | |||||
| } | } | ||||
| impl Drop for Program { | 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 */ | /* Shader */ | ||||
| pub struct 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::{ | use glc::{ | ||||
| array_buffer::{ArrayBuffer, Target, Usage}, | array_buffer::{ArrayBuffer, Target, Usage}, | ||||
| shader::{Program, Shader, Type}, | shader::{Program, Shader, Type}, | ||||
| vertex_array::{DataType, VertexArray}, | |||||
| }; | }; | ||||
| use crate::Error; | use crate::Error; | ||||
| pub struct Background { | pub struct Background { | ||||
| program: Program, | program: Program, | ||||
| array_buffer: ArrayBuffer, | |||||
| vertex_array: VertexArray, | |||||
| } | } | ||||
| impl Background { | 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 { | Ok(Self { | ||||
| program, | program, | ||||
| array_buffer, | |||||
| vertex_array, | |||||
| }) | }) | ||||
| } | } | ||||
| } | } | ||||
| @@ -65,7 +78,7 @@ impl<'a> System<'a> for Background { | |||||
| fn run(&mut self, (): Self::SystemData) { | fn run(&mut self, (): Self::SystemData) { | ||||
| let _program = &self.program; | 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_color(0.1, 0.1, 0.1, 1.0); | ||||
| gl::clear(gl::COLOR_BUFFER_BIT); | gl::clear(gl::COLOR_BUFFER_BIT); | ||||