| @@ -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}")] | |||
| ShaderLink(String), | |||
| #[error("Invalid Parameter!")] | |||
| InvalidParameter, | |||
| } | |||
| impl Error { | |||
| @@ -32,6 +35,20 @@ impl Error { | |||
| 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 { | |||
| @@ -1,2 +1,4 @@ | |||
| pub mod array_buffer; | |||
| pub mod error; | |||
| pub mod misc; | |||
| 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::iter::FromIterator; | |||
| use std::path::Path; | |||
| use std::ptr::{null, null_mut}; | |||
| 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 | |||
| 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; | |||
| gl::get_shader_iv(id, gl::COMPILE_STATUS, &mut success); | |||
| gl::get_program_iv(id, gl::LINK_STATUS, &mut success); | |||
| if success != 1 { | |||
| 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); | |||
| buffer.resize(len as usize, 0); | |||
| gl::get_shader_info_log( | |||
| gl::get_program_info_log( | |||
| id, | |||
| len, | |||
| null_mut(), | |||
| @@ -102,85 +57,59 @@ impl Shader { | |||
| 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 | |||
| } | |||
| 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) { | |||
| 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; | |||
| gl::get_program_iv(id, gl::LINK_STATUS, &mut success); | |||
| gl::get_shader_iv(id, gl::COMPILE_STATUS, &mut success); | |||
| if success != 1 { | |||
| 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); | |||
| buffer.resize(len as usize, 0); | |||
| gl::get_program_info_log( | |||
| gl::get_shader_info_log( | |||
| id, | |||
| len, | |||
| null_mut(), | |||
| @@ -189,49 +118,53 @@ impl Program { | |||
| 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" | |||
| env_logger = "0.8" | |||
| futures = "0.3" | |||
| gl = { version = "0.1", features = [ "use_log_crate" ] } | |||
| gl = { version = "0.1", features = [ "use_log_crate", "generate_debug" ] } | |||
| glc = "0.1" | |||
| glutin = "0.25" | |||
| 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 { | |||
| world: World, | |||
| dispatcher: Dispatcher, | |||
| } | |||
| 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::{ | |||
| dpi::{PhysicalPosition, PhysicalSize}, | |||
| event::{Event, WindowEvent}, | |||
| event_loop::{ControlFlow, EventLoop}, | |||
| platform::desktop::EventLoopExtDesktop, | |||
| window::WindowBuilder, | |||
| ContextBuilder, CreationError, GlProfile, | |||
| ContextBuilder, GlProfile, | |||
| }; | |||
| use log::info; | |||
| use thiserror::Error; | |||
| use log::{error, info}; | |||
| use tokio::{runtime::Builder, task::LocalSet}; | |||
| use app::App; | |||
| use space_crush::{App, Error}; | |||
| fn main() -> Result<(), Error> { | |||
| fn main() { | |||
| env_logger::builder() | |||
| .filter_level(log::LevelFilter::Trace) | |||
| .format_timestamp_nanos() | |||
| @@ -25,9 +20,12 @@ fn main() -> Result<(), Error> { | |||
| let rt = Builder::new_multi_thread() | |||
| .worker_threads(num_cpus::get() + 4) | |||
| .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> { | |||
| @@ -56,7 +54,7 @@ async fn run() -> Result<(), Error> { | |||
| gl::load_with(|s| context.get_proc_address(s)); | |||
| let mut run = true; | |||
| let mut app = App::new(); | |||
| let mut app = App::new()?; | |||
| loop { | |||
| event_loop.run_return(|event, _target, flow_control| { | |||
| @@ -81,7 +79,7 @@ async fn run() -> Result<(), Error> { | |||
| break; | |||
| } | |||
| app.progress(); | |||
| app.progress().await?; | |||
| context.swap_buffers().unwrap(); | |||
| } | |||
| @@ -91,26 +89,5 @@ async fn run() -> Result<(), Error> { | |||
| 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_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; | |||
| } | |||