@@ -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); | |||