| @@ -1 +1 @@ | |||||
| Subproject commit 4a29fa124c3dfde75949d606d014de1cd554e923 | |||||
| Subproject commit b2e25967b55b968d8955d285a67fceaa6a257271 | |||||
| @@ -0,0 +1,267 @@ | |||||
| use std::mem::size_of; | |||||
| use std::ops::{Deref, DerefMut}; | |||||
| use std::ptr::null; | |||||
| use std::slice::from_raw_parts_mut; | |||||
| use crate::{error::Error, misc::AsEnum}; | |||||
| /* ArrayBuffer */ | |||||
| pub struct ArrayBuffer { | |||||
| id: gl::GLuint, | |||||
| target: Target, | |||||
| size: usize, | |||||
| } | |||||
| impl ArrayBuffer { | |||||
| pub fn new(target: Target) -> Result<Self, Error> { | |||||
| let mut id = 0; | |||||
| Error::checked(|| gl::create_buffers(1, &mut id))?; | |||||
| Ok(Self { | |||||
| id, | |||||
| target, | |||||
| size: 0, | |||||
| }) | |||||
| } | |||||
| pub fn id(&self) -> gl::GLuint { | |||||
| 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>(); | |||||
| Error::checked(|| { | |||||
| gl::named_buffer_data( | |||||
| self.id, | |||||
| size as gl::GLsizeiptr, | |||||
| data.as_ptr() as *const _, | |||||
| usage.as_enum(), | |||||
| ) | |||||
| })?; | |||||
| self.size = size; | |||||
| Ok(()) | |||||
| } | |||||
| pub fn buffer_size(&mut self, usage: Usage, size: usize) -> Result<(), Error> { | |||||
| Error::checked(|| { | |||||
| gl::named_buffer_data(self.id, size as gl::GLsizeiptr, null(), usage.as_enum()) | |||||
| })?; | |||||
| self.size = size; | |||||
| Ok(()) | |||||
| } | |||||
| pub fn map<T>(&self) -> Result<Map<'_, T>, Error> { | |||||
| Ok(Map { | |||||
| data: self.inner_map(gl::READ_ONLY)?, | |||||
| buf: self, | |||||
| }) | |||||
| } | |||||
| pub fn map_mut<T>(&mut self, write_only: bool) -> Result<MapMut<'_, T>, Error> { | |||||
| Ok(MapMut { | |||||
| data: self.inner_map(if write_only { | |||||
| gl::WRITE_ONLY | |||||
| } else { | |||||
| gl::READ_WRITE | |||||
| })?, | |||||
| buf: self, | |||||
| }) | |||||
| } | |||||
| pub fn map_range<T>( | |||||
| &self, | |||||
| byte_offset: usize, | |||||
| value_count: Option<usize>, | |||||
| ) -> Result<Map<'_, T>, Error> { | |||||
| Ok(Map { | |||||
| data: self.inner_map_range(gl::READ_ONLY, byte_offset, value_count)?, | |||||
| buf: self, | |||||
| }) | |||||
| } | |||||
| pub fn map_range_mut<T>( | |||||
| &mut self, | |||||
| write_only: bool, | |||||
| byte_offset: usize, | |||||
| value_count: Option<usize>, | |||||
| ) -> Result<MapMut<'_, T>, Error> { | |||||
| let access = if write_only { | |||||
| gl::WRITE_ONLY | |||||
| } else { | |||||
| gl::READ_WRITE | |||||
| }; | |||||
| Ok(MapMut { | |||||
| data: self.inner_map_range(access, byte_offset, value_count)?, | |||||
| buf: self, | |||||
| }) | |||||
| } | |||||
| fn inner_map<T>(&self, access: gl::GLenum) -> Result<&mut [T], Error> { | |||||
| let ptr = Error::err_if(&null(), gl::map_named_buffer(self.id, access))?; | |||||
| let count = self.size / size_of::<T>(); | |||||
| Ok(unsafe { from_raw_parts_mut(ptr as *mut T, count) }) | |||||
| } | |||||
| pub fn inner_map_range<T>( | |||||
| &self, | |||||
| access: gl::GLenum, | |||||
| byte_offset: usize, | |||||
| value_count: Option<usize>, | |||||
| ) -> Result<&mut [T], Error> { | |||||
| let count = value_count.unwrap_or_else(|| { | |||||
| if self.size > byte_offset { | |||||
| (self.size - byte_offset) / size_of::<T>() | |||||
| } else { | |||||
| 0 | |||||
| } | |||||
| }); | |||||
| if byte_offset + count * size_of::<T>() > self.size { | |||||
| return Err(Error::InvalidParameter); | |||||
| } | |||||
| let size = count * size_of::<T>(); | |||||
| let ptr = Error::err_if( | |||||
| &null(), | |||||
| gl::map_named_buffer_range(self.id, byte_offset as isize, size as isize, access), | |||||
| )?; | |||||
| Ok(unsafe { from_raw_parts_mut(ptr as *mut T, count) }) | |||||
| } | |||||
| } | |||||
| /* Map */ | |||||
| pub struct Map<'a, T> { | |||||
| buf: &'a ArrayBuffer, | |||||
| data: &'a [T], | |||||
| } | |||||
| impl<T> Drop for Map<'_, T> { | |||||
| fn drop(&mut self) { | |||||
| gl::unmap_named_buffer(self.buf.id); | |||||
| } | |||||
| } | |||||
| impl<T> Deref for Map<'_, T> { | |||||
| type Target = [T]; | |||||
| fn deref(&self) -> &Self::Target { | |||||
| self.data | |||||
| } | |||||
| } | |||||
| /* MapMut */ | |||||
| pub struct MapMut<'a, T> { | |||||
| buf: &'a ArrayBuffer, | |||||
| data: &'a mut [T], | |||||
| } | |||||
| impl<T> Drop for MapMut<'_, T> { | |||||
| fn drop(&mut self) { | |||||
| gl::unmap_named_buffer(self.buf.id); | |||||
| } | |||||
| } | |||||
| impl<T> Deref for MapMut<'_, T> { | |||||
| type Target = [T]; | |||||
| fn deref(&self) -> &Self::Target { | |||||
| self.data | |||||
| } | |||||
| } | |||||
| impl<T> DerefMut for MapMut<'_, T> { | |||||
| fn deref_mut(&mut self) -> &mut Self::Target { | |||||
| self.data | |||||
| } | |||||
| } | |||||
| /* Target */ | |||||
| #[derive(Debug, Copy, Clone, Eq, PartialEq)] | |||||
| pub enum Target { | |||||
| ArrayBuffer, | |||||
| AtomicCounterBuffer, | |||||
| CopyReadBuffer, | |||||
| CopyWriteBuffer, | |||||
| DispatchIndirectBuffer, | |||||
| DrawIndirectBuffer, | |||||
| ElementArrayBuffer, | |||||
| PixelPackBuffer, | |||||
| PixelUnpackBuffer, | |||||
| QueryBuffer, | |||||
| ShaderStorageBuffer, | |||||
| TextureBuffer, | |||||
| TransformFeedbackBuffer, | |||||
| UniformBuffer, | |||||
| } | |||||
| impl AsEnum for Target { | |||||
| fn as_enum(&self) -> gl::GLenum { | |||||
| match self { | |||||
| Self::ArrayBuffer => gl::ARRAY_BUFFER, | |||||
| Self::AtomicCounterBuffer => gl::ATOMIC_COUNTER_BUFFER, | |||||
| Self::CopyReadBuffer => gl::COPY_READ_BUFFER, | |||||
| Self::CopyWriteBuffer => gl::COPY_WRITE_BUFFER, | |||||
| Self::DispatchIndirectBuffer => gl::DISPATCH_INDIRECT_BUFFER, | |||||
| Self::DrawIndirectBuffer => gl::DRAW_INDIRECT_BUFFER, | |||||
| Self::ElementArrayBuffer => gl::ELEMENT_ARRAY_BUFFER, | |||||
| Self::PixelPackBuffer => gl::PIXEL_PACK_BUFFER, | |||||
| Self::PixelUnpackBuffer => gl::PIXEL_UNPACK_BUFFER, | |||||
| Self::QueryBuffer => gl::QUERY_BUFFER, | |||||
| Self::ShaderStorageBuffer => gl::SHADER_STORAGE_BUFFER, | |||||
| Self::TextureBuffer => gl::TEXTURE_BUFFER, | |||||
| Self::TransformFeedbackBuffer => gl::TRANSFORM_FEEDBACK_BUFFER, | |||||
| Self::UniformBuffer => gl::UNIFORM_BUFFER, | |||||
| } | |||||
| } | |||||
| } | |||||
| /* Usage */ | |||||
| pub enum Usage { | |||||
| StreamDraw, | |||||
| StreamRead, | |||||
| StreamCopy, | |||||
| StaticDraw, | |||||
| StaticRead, | |||||
| StatidCopy, | |||||
| DynamicDraw, | |||||
| DynamicRead, | |||||
| DynamicCopy, | |||||
| } | |||||
| impl AsEnum for Usage { | |||||
| fn as_enum(&self) -> gl::GLenum { | |||||
| match self { | |||||
| Self::StreamDraw => gl::STREAM_DRAW, | |||||
| Self::StreamRead => gl::STREAM_READ, | |||||
| Self::StreamCopy => gl::STREAM_COPY, | |||||
| Self::StaticDraw => gl::STATIC_DRAW, | |||||
| Self::StaticRead => gl::STATIC_READ, | |||||
| Self::StatidCopy => gl::STATIC_COPY, | |||||
| Self::DynamicDraw => gl::DYNAMIC_DRAW, | |||||
| Self::DynamicRead => gl::DYNAMIC_READ, | |||||
| Self::DynamicCopy => gl::DYNAMIC_COPY, | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -19,6 +19,9 @@ pub enum Error { | |||||
| #[error("Error while linking shader program: {0}")] | #[error("Error while linking shader program: {0}")] | ||||
| ShaderLink(String), | ShaderLink(String), | ||||
| #[error("Invalid Parameter!")] | |||||
| InvalidParameter, | |||||
| } | } | ||||
| impl Error { | impl Error { | ||||
| @@ -32,6 +35,20 @@ impl Error { | |||||
| Ok(value) | Ok(value) | ||||
| } | } | ||||
| } | } | ||||
| pub fn checked<F, T>(f: F) -> Result<T, Self> | |||||
| where | |||||
| F: FnOnce() -> T, | |||||
| { | |||||
| gl::get_error(); | |||||
| let ret = f(); | |||||
| match gl::get_error() { | |||||
| 0 => Ok(ret), | |||||
| err => Err(Self::GlError(err)), | |||||
| } | |||||
| } | |||||
| } | } | ||||
| impl From<IoError> for Error { | impl From<IoError> for Error { | ||||
| @@ -1,2 +1,4 @@ | |||||
| pub mod array_buffer; | |||||
| pub mod error; | pub mod error; | ||||
| pub mod misc; | |||||
| pub mod shader; | pub mod shader; | ||||
| @@ -0,0 +1,3 @@ | |||||
| pub trait AsEnum { | |||||
| fn as_enum(&self) -> gl::GLenum; | |||||
| } | |||||
| @@ -1,99 +1,54 @@ | |||||
| use std::fs::read_to_string; | use std::fs::read_to_string; | ||||
| use std::iter::FromIterator; | |||||
| use std::path::Path; | 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; | |||||
| use crate::{error::Error, misc::AsEnum}; | |||||
| #[derive(Debug, Copy, Clone, Eq, PartialEq)] | |||||
| pub enum Type { | |||||
| Vertex, | |||||
| Compute, | |||||
| Fragment, | |||||
| Geometry, | |||||
| TesslationControl, | |||||
| TesslationEvaluation, | |||||
| } | |||||
| /* Shader */ | |||||
| /* Programm */ | |||||
| pub struct Shader { | |||||
| id: Option<gl::GLuint>, | |||||
| type_: Type, | |||||
| source: String, | |||||
| compiled: bool, | |||||
| #[derive(Default)] | |||||
| pub struct Program { | |||||
| id: gl::GLuint, | |||||
| } | } | ||||
| impl Shader { | |||||
| pub fn from_string(type_: Type, source: String) -> Self { | |||||
| Self { | |||||
| id: None, | |||||
| type_, | |||||
| source, | |||||
| compiled: false, | |||||
| } | |||||
| impl Program { | |||||
| pub fn from_shaders<I>(iter: I) -> Result<Self, Error> | |||||
| where | |||||
| I: IntoIterator<Item = Shader>, | |||||
| { | |||||
| Self::from_shaders_result(iter.into_iter().map(Ok)) | |||||
| } | } | ||||
| pub fn from_file<P>(type_: Type, path: P) -> Result<Self, Error> | |||||
| pub fn from_shaders_result<I>(iter: I) -> Result<Self, Error> | |||||
| where | where | ||||
| P: AsRef<Path>, | |||||
| I: IntoIterator<Item = Result<Shader, Error>>, | |||||
| { | { | ||||
| let source = read_to_string(path)?; | |||||
| let id = gl::create_program(); | |||||
| let id = Error::err_if(&0, id)?; | |||||
| Ok(Self::from_string(type_, source)) | |||||
| } | |||||
| pub fn id(&mut self) -> Result<gl::GLuint, Error> { | |||||
| if self.id.is_none() { | |||||
| let type_ = match self.type_ { | |||||
| Type::Vertex => gl::VERTEX_SHADER, | |||||
| Type::Compute => gl::COMPUTE_SHADER, | |||||
| Type::Fragment => gl::FRAGMENT_SHADER, | |||||
| Type::Geometry => gl::GEOMETRY_SHADER, | |||||
| Type::TesslationControl => gl::TESS_CONTROL_SHADER, | |||||
| Type::TesslationEvaluation => gl::TESS_EVALUATION_SHADER, | |||||
| }; | |||||
| let id = gl::create_shader(type_); | |||||
| let id = Error::err_if(&0, id)?; | |||||
| self.id = Some(id) | |||||
| let shaders = iter.into_iter().collect::<Result<Vec<_>, _>>()?; | |||||
| for shader in &shaders { | |||||
| gl::attach_shader(id, shader.id()); | |||||
| } | } | ||||
| Ok(self.id.unwrap()) | |||||
| } | |||||
| gl::link_program(id); | |||||
| pub fn id_opt(&self) -> Option<gl::GLuint> { | |||||
| self.id | |||||
| } | |||||
| pub fn type_(&self) -> Type { | |||||
| self.type_ | |||||
| } | |||||
| pub fn compile(&mut self) -> Result<(), Error> { | |||||
| if self.compiled { | |||||
| return Ok(()); | |||||
| for shader in &shaders { | |||||
| gl::detach_shader(id, shader.id()); | |||||
| } | } | ||||
| let id = self.id()?; | |||||
| let source = self.source.as_ptr() as *const i8; | |||||
| let source: *const *const i8 = &source; | |||||
| gl::shader_source(id, 1, source, null()); | |||||
| gl::compile_shader(id); | |||||
| let mut success = 1; | let mut success = 1; | ||||
| gl::get_shader_iv(id, gl::COMPILE_STATUS, &mut success); | |||||
| gl::get_program_iv(id, gl::LINK_STATUS, &mut success); | |||||
| if success != 1 { | if success != 1 { | ||||
| let mut len = 0; | let mut len = 0; | ||||
| gl::get_shader_iv(id, gl::INFO_LOG_LENGTH, &mut len); | |||||
| gl::get_program_iv(id, gl::INFO_LOG_LENGTH, &mut len); | |||||
| let mut buffer = Vec::<u8>::with_capacity(len as usize + 1); | let mut buffer = Vec::<u8>::with_capacity(len as usize + 1); | ||||
| buffer.resize(len as usize, 0); | buffer.resize(len as usize, 0); | ||||
| gl::get_shader_info_log( | |||||
| gl::get_program_info_log( | |||||
| id, | id, | ||||
| len, | len, | ||||
| null_mut(), | null_mut(), | ||||
| @@ -102,85 +57,59 @@ impl Shader { | |||||
| let msg = from_utf8(&buffer)?; | let msg = from_utf8(&buffer)?; | ||||
| return Err(Error::ShaderCompile(msg.into())); | |||||
| } | |||||
| self.compiled = true; | |||||
| Ok(()) | |||||
| } | |||||
| } | |||||
| impl Drop for Shader { | |||||
| fn drop(&mut self) { | |||||
| if let Some(id) = &self.id { | |||||
| gl::delete_shader(*id); | |||||
| } | |||||
| } | |||||
| } | |||||
| /* Programm */ | |||||
| #[derive(Default)] | |||||
| pub struct Program { | |||||
| id: Option<gl::GLuint>, | |||||
| shaders: Vec<Shader>, | |||||
| compiled: bool, | |||||
| } | |||||
| impl Program { | |||||
| pub fn id(&mut self) -> Result<gl::GLuint, Error> { | |||||
| if self.id.is_none() { | |||||
| let id = gl::create_program(); | |||||
| let id = Error::err_if(&0, id)?; | |||||
| self.id = Some(id) | |||||
| return Err(Error::ShaderLink(msg.into())); | |||||
| } | } | ||||
| Ok(self.id.unwrap()) | |||||
| Ok(Program { id }) | |||||
| } | } | ||||
| pub fn id_opt(&self) -> Option<gl::GLuint> { | |||||
| pub fn id(&self) -> gl::GLuint { | |||||
| self.id | self.id | ||||
| } | } | ||||
| pub fn bind(&self) { | pub fn bind(&self) { | ||||
| if let Some(id) = &self.id { | |||||
| gl::use_program(*id); | |||||
| } else { | |||||
| gl::use_program(0); | |||||
| } | |||||
| gl::use_program(self.id); | |||||
| } | } | ||||
| pub fn unbind(&self) { | pub fn unbind(&self) { | ||||
| gl::use_program(0); | gl::use_program(0); | ||||
| } | } | ||||
| } | |||||
| pub fn link(&mut self, keep_shaders: bool) -> Result<(), Error> { | |||||
| if self.compiled { | |||||
| return Ok(()); | |||||
| } | |||||
| impl Drop for Program { | |||||
| fn drop(&mut self) { | |||||
| gl::delete_program(self.id); | |||||
| } | |||||
| } | |||||
| let id = self.id()?; | |||||
| /* Shader */ | |||||
| for shader in &mut self.shaders { | |||||
| shader.compile()?; | |||||
| } | |||||
| pub struct Shader { | |||||
| id: gl::GLuint, | |||||
| } | |||||
| for shader in &mut self.shaders { | |||||
| gl::attach_shader(id, shader.id()?); | |||||
| } | |||||
| impl Shader { | |||||
| pub fn from_string(type_: Type, source: String) -> Result<Self, Error> { | |||||
| let id = gl::create_shader(type_.as_enum()); | |||||
| let id = Error::err_if(&0, id)?; | |||||
| let source = source.as_ptr() as *const i8; | |||||
| let source: *const *const i8 = &source; | |||||
| gl::shader_source(id, 1, source, null()); | |||||
| gl::compile_shader(id); | |||||
| let mut success = 1; | let mut success = 1; | ||||
| gl::get_program_iv(id, gl::LINK_STATUS, &mut success); | |||||
| gl::get_shader_iv(id, gl::COMPILE_STATUS, &mut success); | |||||
| if success != 1 { | if success != 1 { | ||||
| let mut len = 0; | let mut len = 0; | ||||
| gl::get_program_iv(id, gl::INFO_LOG_LENGTH, &mut len); | |||||
| gl::get_shader_iv(id, gl::INFO_LOG_LENGTH, &mut len); | |||||
| let mut buffer = Vec::<u8>::with_capacity(len as usize + 1); | let mut buffer = Vec::<u8>::with_capacity(len as usize + 1); | ||||
| buffer.resize(len as usize, 0); | buffer.resize(len as usize, 0); | ||||
| gl::get_program_info_log( | |||||
| gl::get_shader_info_log( | |||||
| id, | id, | ||||
| len, | len, | ||||
| null_mut(), | null_mut(), | ||||
| @@ -189,49 +118,53 @@ impl Program { | |||||
| let msg = from_utf8(&buffer)?; | let msg = from_utf8(&buffer)?; | ||||
| return Err(Error::ShaderLink(msg.into())); | |||||
| return Err(Error::ShaderCompile(msg.into())); | |||||
| } | } | ||||
| for shader in &mut self.shaders { | |||||
| gl::detach_shader(id, shader.id()?); | |||||
| } | |||||
| Ok(Self { id }) | |||||
| } | |||||
| if !keep_shaders { | |||||
| self.shaders.clear(); | |||||
| } | |||||
| pub fn from_file<P>(type_: Type, path: P) -> Result<Self, Error> | |||||
| where | |||||
| P: AsRef<Path>, | |||||
| { | |||||
| let source = read_to_string(path)?; | |||||
| self.compiled = true; | |||||
| Self::from_string(type_, source) | |||||
| } | |||||
| Ok(()) | |||||
| pub fn id(&self) -> gl::GLuint { | |||||
| self.id | |||||
| } | } | ||||
| } | } | ||||
| impl Extend<Shader> for Program { | |||||
| fn extend<I>(&mut self, iter: I) | |||||
| where | |||||
| I: IntoIterator<Item = Shader>, | |||||
| { | |||||
| self.shaders.extend(iter); | |||||
| impl Drop for Shader { | |||||
| fn drop(&mut self) { | |||||
| gl::delete_shader(self.id); | |||||
| } | } | ||||
| } | } | ||||
| impl FromIterator<Shader> for Program { | |||||
| fn from_iter<I>(iter: I) -> Self | |||||
| where | |||||
| I: IntoIterator<Item = Shader>, | |||||
| { | |||||
| Self { | |||||
| id: None, | |||||
| shaders: iter.into_iter().collect(), | |||||
| compiled: false, | |||||
| } | |||||
| } | |||||
| /* Type */ | |||||
| #[derive(Debug, Copy, Clone, Eq, PartialEq)] | |||||
| pub enum Type { | |||||
| Vertex, | |||||
| Compute, | |||||
| Fragment, | |||||
| Geometry, | |||||
| TesslationControl, | |||||
| TesslationEvaluation, | |||||
| } | } | ||||
| impl Drop for Program { | |||||
| fn drop(&mut self) { | |||||
| if let Some(id) = &self.id { | |||||
| gl::delete_program(*id); | |||||
| impl AsEnum for Type { | |||||
| fn as_enum(&self) -> gl::GLenum { | |||||
| match self { | |||||
| Self::Vertex => gl::VERTEX_SHADER, | |||||
| Self::Compute => gl::COMPUTE_SHADER, | |||||
| Self::Fragment => gl::FRAGMENT_SHADER, | |||||
| Self::Geometry => gl::GEOMETRY_SHADER, | |||||
| Self::TesslationControl => gl::TESS_CONTROL_SHADER, | |||||
| Self::TesslationEvaluation => gl::TESS_EVALUATION_SHADER, | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -10,7 +10,7 @@ async-ecs = "0.1" | |||||
| async-ecs-derive = "0.1" | async-ecs-derive = "0.1" | ||||
| env_logger = "0.8" | env_logger = "0.8" | ||||
| futures = "0.3" | futures = "0.3" | ||||
| gl = { version = "0.1", features = [ "use_log_crate" ] } | |||||
| gl = { version = "0.1", features = [ "use_log_crate", "generate_debug" ] } | |||||
| glc = "0.1" | glc = "0.1" | ||||
| glutin = "0.25" | glutin = "0.25" | ||||
| log = { version = "0.4", features = [ "max_level_trace", "release_max_level_warn" ] } | log = { version = "0.4", features = [ "max_level_trace", "release_max_level_warn" ] } | ||||
| @@ -1,20 +1,26 @@ | |||||
| use async_ecs::World; | |||||
| use async_ecs::{Dispatcher, World}; | |||||
| use crate::{render::Background, Error}; | |||||
| pub struct App { | pub struct App { | ||||
| world: World, | world: World, | ||||
| dispatcher: Dispatcher, | |||||
| } | } | ||||
| impl App { | impl App { | ||||
| pub fn new() -> Self { | |||||
| let world = World::default(); | |||||
| pub fn new() -> Result<Self, Error> { | |||||
| let mut world = World::default(); | |||||
| let dispatcher = Dispatcher::setup_builder(&mut world) | |||||
| .with_local(Background::new()?, "render_background", &[])? | |||||
| .build(); | |||||
| Self { world } | |||||
| Ok(Self { world, dispatcher }) | |||||
| } | } | ||||
| pub fn progress(&mut self) { | |||||
| let _world = &mut self.world; | |||||
| pub async fn progress(&mut self) -> Result<(), Error> { | |||||
| self.dispatcher.dispatch(&self.world).await?; | |||||
| self.world.maintain().await; | |||||
| gl::clear_color(0.1, 0.1, 0.1, 1.0); | |||||
| gl::clear(gl::COLOR_BUFFER_BIT); | |||||
| Ok(()) | |||||
| } | } | ||||
| } | } | ||||
| @@ -0,0 +1,34 @@ | |||||
| use async_ecs::dispatcher::Error as DispatcherError; | |||||
| use glc::error::Error as GlcError; | |||||
| use glutin::CreationError as GlutinCreationError; | |||||
| use thiserror::Error; | |||||
| #[derive(Debug, Error)] | |||||
| pub enum Error { | |||||
| #[error("GLC Error: {0}")] | |||||
| GlcError(GlcError), | |||||
| #[error("ECS Dispatcher Error: {0}")] | |||||
| DispatcherError(DispatcherError), | |||||
| #[error("glutin Creation Error: {0}")] | |||||
| GlutinCreationError(GlutinCreationError), | |||||
| } | |||||
| impl From<GlcError> for Error { | |||||
| fn from(err: GlcError) -> Self { | |||||
| Self::GlcError(err) | |||||
| } | |||||
| } | |||||
| impl From<DispatcherError> for Error { | |||||
| fn from(err: DispatcherError) -> Self { | |||||
| Self::DispatcherError(err) | |||||
| } | |||||
| } | |||||
| impl From<GlutinCreationError> for Error { | |||||
| fn from(err: GlutinCreationError) -> Self { | |||||
| Self::GlutinCreationError(err) | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,6 @@ | |||||
| mod app; | |||||
| mod error; | |||||
| mod render; | |||||
| pub use app::App; | |||||
| pub use error::Error; | |||||
| @@ -1,22 +1,17 @@ | |||||
| mod app; | |||||
| use std::io::Error as IoError; | |||||
| use glutin::{ | use glutin::{ | ||||
| dpi::{PhysicalPosition, PhysicalSize}, | dpi::{PhysicalPosition, PhysicalSize}, | ||||
| event::{Event, WindowEvent}, | event::{Event, WindowEvent}, | ||||
| event_loop::{ControlFlow, EventLoop}, | event_loop::{ControlFlow, EventLoop}, | ||||
| platform::desktop::EventLoopExtDesktop, | platform::desktop::EventLoopExtDesktop, | ||||
| window::WindowBuilder, | window::WindowBuilder, | ||||
| ContextBuilder, CreationError, GlProfile, | |||||
| ContextBuilder, GlProfile, | |||||
| }; | }; | ||||
| use log::info; | |||||
| use thiserror::Error; | |||||
| use log::{error, info}; | |||||
| use tokio::{runtime::Builder, task::LocalSet}; | use tokio::{runtime::Builder, task::LocalSet}; | ||||
| use app::App; | |||||
| use space_crush::{App, Error}; | |||||
| fn main() -> Result<(), Error> { | |||||
| fn main() { | |||||
| env_logger::builder() | env_logger::builder() | ||||
| .filter_level(log::LevelFilter::Trace) | .filter_level(log::LevelFilter::Trace) | ||||
| .format_timestamp_nanos() | .format_timestamp_nanos() | ||||
| @@ -25,9 +20,12 @@ fn main() -> Result<(), Error> { | |||||
| let rt = Builder::new_multi_thread() | let rt = Builder::new_multi_thread() | ||||
| .worker_threads(num_cpus::get() + 4) | .worker_threads(num_cpus::get() + 4) | ||||
| .enable_all() | .enable_all() | ||||
| .build()?; | |||||
| .build() | |||||
| .unwrap(); | |||||
| rt.block_on(async move { LocalSet::new().run_until(run()).await }) | |||||
| if let Err(err) = rt.block_on(async move { LocalSet::new().run_until(run()).await }) { | |||||
| error!("Error while executinr application: {}", err); | |||||
| } | |||||
| } | } | ||||
| async fn run() -> Result<(), Error> { | async fn run() -> Result<(), Error> { | ||||
| @@ -56,7 +54,7 @@ async fn run() -> Result<(), Error> { | |||||
| gl::load_with(|s| context.get_proc_address(s)); | gl::load_with(|s| context.get_proc_address(s)); | ||||
| let mut run = true; | let mut run = true; | ||||
| let mut app = App::new(); | |||||
| let mut app = App::new()?; | |||||
| loop { | loop { | ||||
| event_loop.run_return(|event, _target, flow_control| { | event_loop.run_return(|event, _target, flow_control| { | ||||
| @@ -81,7 +79,7 @@ async fn run() -> Result<(), Error> { | |||||
| break; | break; | ||||
| } | } | ||||
| app.progress(); | |||||
| app.progress().await?; | |||||
| context.swap_buffers().unwrap(); | context.swap_buffers().unwrap(); | ||||
| } | } | ||||
| @@ -91,26 +89,5 @@ async fn run() -> Result<(), Error> { | |||||
| Ok(()) | Ok(()) | ||||
| } | } | ||||
| #[derive(Debug, Error)] | |||||
| enum Error { | |||||
| #[error("IO Error: {0}")] | |||||
| IoError(IoError), | |||||
| #[error("OpenGL Context Error: {0}")] | |||||
| OpenGlContext(CreationError), | |||||
| } | |||||
| impl From<IoError> for Error { | |||||
| fn from(err: IoError) -> Self { | |||||
| Self::IoError(err) | |||||
| } | |||||
| } | |||||
| impl From<CreationError> for Error { | |||||
| fn from(err: CreationError) -> Self { | |||||
| Self::OpenGlContext(err) | |||||
| } | |||||
| } | |||||
| const WINDOW_WIDTH: u32 = 1280; | const WINDOW_WIDTH: u32 = 1280; | ||||
| const WINDOW_HEIGHT: u32 = 720; | const WINDOW_HEIGHT: u32 = 720; | ||||
| @@ -0,0 +1,82 @@ | |||||
| use std::mem::size_of; | |||||
| use async_ecs::System; | |||||
| use glc::{ | |||||
| array_buffer::{ArrayBuffer, Target, Usage}, | |||||
| shader::{Program, Shader, Type}, | |||||
| }; | |||||
| use crate::Error; | |||||
| pub struct Background { | |||||
| program: Program, | |||||
| array_buffer: ArrayBuffer, | |||||
| } | |||||
| impl Background { | |||||
| pub fn new() -> Result<Self, Error> { | |||||
| let shaders = vec![(Type::Fragment, include_str!("shader/noise.frag"))]; | |||||
| let program = Program::from_shaders_result( | |||||
| shaders | |||||
| .into_iter() | |||||
| .map(|(t, s)| Shader::from_string(t, s.into())), | |||||
| )?; | |||||
| let mut array_buffer = ArrayBuffer::new(Target::ArrayBuffer)?; | |||||
| array_buffer.buffer_size(Usage::StaticDraw, 4 * size_of::<Vertex>())?; | |||||
| { | |||||
| let mut buf = array_buffer.map_mut(false)?; | |||||
| buf[0] = Vertex { | |||||
| x: -1.0, | |||||
| y: -1.0, | |||||
| s: -1.0, | |||||
| t: -1.0, | |||||
| }; | |||||
| buf[1] = Vertex { | |||||
| x: 1.0, | |||||
| y: -1.0, | |||||
| s: 1.0, | |||||
| t: -1.0, | |||||
| }; | |||||
| buf[2] = Vertex { | |||||
| x: 1.0, | |||||
| y: 1.0, | |||||
| s: 1.0, | |||||
| t: 1.0, | |||||
| }; | |||||
| buf[3] = Vertex { | |||||
| x: -1.0, | |||||
| y: 1.0, | |||||
| s: -1.0, | |||||
| t: 1.0, | |||||
| }; | |||||
| } | |||||
| Ok(Self { | |||||
| program, | |||||
| array_buffer, | |||||
| }) | |||||
| } | |||||
| } | |||||
| impl<'a> System<'a> for Background { | |||||
| type SystemData = (); | |||||
| fn run(&mut self, (): Self::SystemData) { | |||||
| let _program = &self.program; | |||||
| let _array_buffer = &self.array_buffer; | |||||
| gl::clear_color(0.1, 0.1, 0.1, 1.0); | |||||
| gl::clear(gl::COLOR_BUFFER_BIT); | |||||
| } | |||||
| } | |||||
| #[repr(C, packed)] | |||||
| #[derive(Debug, Copy, Clone, PartialEq)] | |||||
| struct Vertex { | |||||
| pub x: f32, | |||||
| pub y: f32, | |||||
| pub s: f32, | |||||
| pub t: f32, | |||||
| } | |||||
| @@ -0,0 +1,3 @@ | |||||
| mod background; | |||||
| pub use background::Background; | |||||
| @@ -0,0 +1,17 @@ | |||||
| const float NOISE_RANGE = 0.05; | |||||
| const float NOISE_BASE = 0.05; | |||||
| float random(vec4 seed) | |||||
| { | |||||
| return fract(sin(dot(seed, vec4(12.9898, 78.233, 45.164, 53.1324))) * 43758.5453); | |||||
| } | |||||
| void main(void) | |||||
| { | |||||
| float rnd = random(gl_ModelViewProjectionMatrix * gl_FragCoord); | |||||
| vec4 color = vec4(NOISE_BASE + NOISE_RANGE * rnd); | |||||
| color.a = 1.0; | |||||
| gl_FragColor = color; | |||||
| } | |||||