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