| @@ -588,6 +588,14 @@ dependencies = [ | |||||
| "xml-rs", | "xml-rs", | ||||
| ] | ] | ||||
| [[package]] | |||||
| name = "glc" | |||||
| version = "0.1.0" | |||||
| dependencies = [ | |||||
| "gl", | |||||
| "thiserror", | |||||
| ] | |||||
| [[package]] | [[package]] | ||||
| name = "glutin" | name = "glutin" | ||||
| version = "0.25.1" | version = "0.25.1" | ||||
| @@ -1361,6 +1369,7 @@ dependencies = [ | |||||
| "env_logger", | "env_logger", | ||||
| "futures", | "futures", | ||||
| "gl", | "gl", | ||||
| "glc", | |||||
| "glutin", | "glutin", | ||||
| "log", | "log", | ||||
| "num_cpus", | "num_cpus", | ||||
| @@ -3,8 +3,9 @@ members = [ | |||||
| "asparit", | "asparit", | ||||
| "async-ecs", | "async-ecs", | ||||
| "async-ecs-derive", | "async-ecs-derive", | ||||
| "space-crush", | |||||
| "gl", | "gl", | ||||
| "glc", | |||||
| "space-crush", | |||||
| ] | ] | ||||
| default-members = [ | default-members = [ | ||||
| "space-crush", | "space-crush", | ||||
| @@ -14,5 +15,6 @@ default-members = [ | |||||
| asparit = { path = "./asparit" } | asparit = { path = "./asparit" } | ||||
| async-ecs = { path = "./async-ecs" } | async-ecs = { path = "./async-ecs" } | ||||
| async-ecs-derive = { path = "./async-ecs-derive" } | async-ecs-derive = { path = "./async-ecs-derive" } | ||||
| space-crush = { path = "./space-crush" } | |||||
| gl = { path = "./gl" } | gl = { path = "./gl" } | ||||
| glc = { path = "./glc" } | |||||
| space-crush = { path = "./space-crush" } | |||||
| @@ -1,7 +1,7 @@ | |||||
| use std::ops::Deref; | use std::ops::Deref; | ||||
| use std::rc::Rc; | use std::rc::Rc; | ||||
| use super::bindings::InnerGl; | |||||
| use super::bindings::{types, Gl as InnerGl}; | |||||
| #[derive(Clone)] | #[derive(Clone)] | ||||
| pub struct Gl(Rc<InnerGl>); | pub struct Gl(Rc<InnerGl>); | ||||
| @@ -2,6 +2,7 @@ mod bindings; | |||||
| #[cfg(feature = "generate_struct")] | #[cfg(feature = "generate_struct")] | ||||
| mod gl; | mod gl; | ||||
| pub use bindings::types::*; | |||||
| #[cfg(feature = "generate_struct")] | #[cfg(feature = "generate_struct")] | ||||
| pub use bindings::Gl as InnerGl; | pub use bindings::Gl as InnerGl; | ||||
| pub use bindings::*; | pub use bindings::*; | ||||
| @@ -0,0 +1,9 @@ | |||||
| [package] | |||||
| name = "glc" | |||||
| version = "0.1.0" | |||||
| authors = ["Bergmann89 <info@bergmann89.de>"] | |||||
| edition = "2018" | |||||
| [dependencies] | |||||
| gl = { version = "0.1", features = [ "generate_global" ] } | |||||
| thiserror = "1.0" | |||||
| @@ -0,0 +1,47 @@ | |||||
| use std::io::Error as IoError; | |||||
| use std::str::Utf8Error; | |||||
| use thiserror::Error; | |||||
| #[derive(Debug, Error)] | |||||
| pub enum Error { | |||||
| #[error("IO Error: {0}")] | |||||
| IoError(IoError), | |||||
| #[error("UTF-8 Error: {0}")] | |||||
| Utf8Error(Utf8Error), | |||||
| #[error("OpenGL Error: {0}")] | |||||
| GlError(gl::GLenum), | |||||
| #[error("Error while compiling shader object: {0}")] | |||||
| ShaderCompile(String), | |||||
| #[error("Error while linking shader program: {0}")] | |||||
| ShaderLink(String), | |||||
| } | |||||
| impl Error { | |||||
| pub fn err_if<T>(err: &T, value: T) -> Result<T, Error> | |||||
| where | |||||
| T: PartialEq<T>, | |||||
| { | |||||
| if value.eq(err) { | |||||
| Err(Error::GlError(gl::get_error())) | |||||
| } else { | |||||
| Ok(value) | |||||
| } | |||||
| } | |||||
| } | |||||
| impl From<IoError> for Error { | |||||
| fn from(err: IoError) -> Self { | |||||
| Self::IoError(err) | |||||
| } | |||||
| } | |||||
| impl From<Utf8Error> for Error { | |||||
| fn from(err: Utf8Error) -> Self { | |||||
| Self::Utf8Error(err) | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,2 @@ | |||||
| pub mod error; | |||||
| pub mod shader; | |||||
| @@ -0,0 +1,237 @@ | |||||
| 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; | |||||
| #[derive(Debug, Copy, Clone, Eq, PartialEq)] | |||||
| pub enum Type { | |||||
| Vertex, | |||||
| Compute, | |||||
| Fragment, | |||||
| Geometry, | |||||
| TesslationControl, | |||||
| TesslationEvaluation, | |||||
| } | |||||
| /* Shader */ | |||||
| pub struct Shader { | |||||
| id: Option<gl::GLuint>, | |||||
| type_: Type, | |||||
| source: String, | |||||
| compiled: bool, | |||||
| } | |||||
| impl Shader { | |||||
| pub fn from_string(type_: Type, source: String) -> Self { | |||||
| Self { | |||||
| id: None, | |||||
| type_, | |||||
| source, | |||||
| compiled: false, | |||||
| } | |||||
| } | |||||
| pub fn from_file<P>(type_: Type, path: P) -> Result<Self, Error> | |||||
| where | |||||
| P: AsRef<Path>, | |||||
| { | |||||
| let source = read_to_string(path)?; | |||||
| 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) | |||||
| } | |||||
| Ok(self.id.unwrap()) | |||||
| } | |||||
| 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(()); | |||||
| } | |||||
| 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); | |||||
| if success != 1 { | |||||
| let mut len = 0; | |||||
| 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_shader_info_log( | |||||
| id, | |||||
| len, | |||||
| null_mut(), | |||||
| buffer.as_mut_ptr() as *mut gl::types::GLchar, | |||||
| ); | |||||
| 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) | |||||
| } | |||||
| Ok(self.id.unwrap()) | |||||
| } | |||||
| pub fn id_opt(&self) -> Option<gl::GLuint> { | |||||
| self.id | |||||
| } | |||||
| pub fn bind(&self) { | |||||
| if let Some(id) = &self.id { | |||||
| gl::use_program(*id); | |||||
| } else { | |||||
| gl::use_program(0); | |||||
| } | |||||
| } | |||||
| pub fn unbind(&self) { | |||||
| gl::use_program(0); | |||||
| } | |||||
| pub fn link(&mut self, keep_shaders: bool) -> Result<(), Error> { | |||||
| if self.compiled { | |||||
| return Ok(()); | |||||
| } | |||||
| let id = self.id()?; | |||||
| for shader in &mut self.shaders { | |||||
| shader.compile()?; | |||||
| } | |||||
| for shader in &mut self.shaders { | |||||
| gl::attach_shader(id, shader.id()?); | |||||
| } | |||||
| let mut success = 1; | |||||
| gl::get_program_iv(id, gl::LINK_STATUS, &mut success); | |||||
| if success != 1 { | |||||
| let mut len = 0; | |||||
| 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_program_info_log( | |||||
| id, | |||||
| len, | |||||
| null_mut(), | |||||
| buffer.as_mut_ptr() as *mut gl::types::GLchar, | |||||
| ); | |||||
| let msg = from_utf8(&buffer)?; | |||||
| return Err(Error::ShaderLink(msg.into())); | |||||
| } | |||||
| for shader in &mut self.shaders { | |||||
| gl::detach_shader(id, shader.id()?); | |||||
| } | |||||
| if !keep_shaders { | |||||
| self.shaders.clear(); | |||||
| } | |||||
| self.compiled = true; | |||||
| Ok(()) | |||||
| } | |||||
| } | |||||
| impl Extend<Shader> for Program { | |||||
| fn extend<I>(&mut self, iter: I) | |||||
| where | |||||
| I: IntoIterator<Item = Shader>, | |||||
| { | |||||
| self.shaders.extend(iter); | |||||
| } | |||||
| } | |||||
| 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, | |||||
| } | |||||
| } | |||||
| } | |||||
| impl Drop for Program { | |||||
| fn drop(&mut self) { | |||||
| if let Some(id) = &self.id { | |||||
| gl::delete_program(*id); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -10,9 +10,10 @@ 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", "generate_global" ] } | |||||
| gl = { version = "0.1", features = [ "use_log_crate" ] } | |||||
| glc = "0.1" | |||||
| glutin = "0.25" | glutin = "0.25" | ||||
| log = { version = "0.4", features = [ "max_level_debug", "release_max_level_warn" ] } | |||||
| log = { version = "0.4", features = [ "max_level_trace", "release_max_level_warn" ] } | |||||
| num_cpus = "1.13" | num_cpus = "1.13" | ||||
| rand = "0.7" | rand = "0.7" | ||||
| thiserror = "1.0" | thiserror = "1.0" | ||||
| @@ -0,0 +1,20 @@ | |||||
| use async_ecs::World; | |||||
| pub struct App { | |||||
| world: World, | |||||
| } | |||||
| impl App { | |||||
| pub fn new() -> Self { | |||||
| let world = World::default(); | |||||
| Self { world } | |||||
| } | |||||
| pub fn progress(&mut self) { | |||||
| let _world = &mut self.world; | |||||
| gl::clear_color(0.1, 0.1, 0.1, 1.0); | |||||
| gl::clear(gl::COLOR_BUFFER_BIT); | |||||
| } | |||||
| } | |||||
| @@ -1,3 +1,5 @@ | |||||
| mod app; | |||||
| use std::io::Error as IoError; | use std::io::Error as IoError; | ||||
| use glutin::{ | use glutin::{ | ||||
| @@ -12,9 +14,11 @@ use log::info; | |||||
| use thiserror::Error; | use thiserror::Error; | ||||
| use tokio::{runtime::Builder, task::LocalSet}; | use tokio::{runtime::Builder, task::LocalSet}; | ||||
| use app::App; | |||||
| fn main() -> Result<(), Error> { | fn main() -> Result<(), Error> { | ||||
| env_logger::builder() | env_logger::builder() | ||||
| .filter_level(log::LevelFilter::Debug) | |||||
| .filter_level(log::LevelFilter::Trace) | |||||
| .format_timestamp_nanos() | .format_timestamp_nanos() | ||||
| .init(); | .init(); | ||||
| @@ -49,9 +53,10 @@ async fn run() -> Result<(), Error> { | |||||
| )); | )); | ||||
| let context = unsafe { context.make_current().unwrap() }; | let context = unsafe { context.make_current().unwrap() }; | ||||
| 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(); | |||||
| loop { | loop { | ||||
| event_loop.run_return(|event, _target, flow_control| { | event_loop.run_return(|event, _target, flow_control| { | ||||
| @@ -76,8 +81,7 @@ async fn run() -> Result<(), Error> { | |||||
| break; | break; | ||||
| } | } | ||||
| gl::clear_color(0.1, 0.1, 0.1, 1.0); | |||||
| gl::clear(gl::COLOR_BUFFER_BIT); | |||||
| app.progress(); | |||||
| context.swap_buffers().unwrap(); | context.swap_buffers().unwrap(); | ||||
| } | } | ||||