| @@ -6,6 +6,12 @@ version = "0.1.4" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| checksum = "d9fe5e32de01730eb1f6b7f5b51c17e03e2325bf40a74f754f04f130043affff" | |||
| [[package]] | |||
| name = "adler32" | |||
| version = "1.2.0" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" | |||
| [[package]] | |||
| name = "ahash" | |||
| version = "0.3.8" | |||
| @@ -87,6 +93,27 @@ version = "1.3.4" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" | |||
| [[package]] | |||
| name = "bzip2" | |||
| version = "0.3.3" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| checksum = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b" | |||
| dependencies = [ | |||
| "bzip2-sys", | |||
| "libc", | |||
| ] | |||
| [[package]] | |||
| name = "bzip2-sys" | |||
| version = "0.1.9+1.0.8" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| checksum = "ad3b39a260062fca31f7b0b12f207e8f2590a67d32ec7d59c20484b07ea7285e" | |||
| dependencies = [ | |||
| "cc", | |||
| "libc", | |||
| "pkg-config", | |||
| ] | |||
| [[package]] | |||
| name = "calloop" | |||
| version = "0.6.5" | |||
| @@ -252,6 +279,15 @@ dependencies = [ | |||
| "objc", | |||
| ] | |||
| [[package]] | |||
| name = "crc32fast" | |||
| version = "1.2.1" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" | |||
| dependencies = [ | |||
| "cfg-if 1.0.0", | |||
| ] | |||
| [[package]] | |||
| name = "crossbeam-channel" | |||
| version = "0.5.0" | |||
| @@ -406,6 +442,18 @@ dependencies = [ | |||
| "termcolor", | |||
| ] | |||
| [[package]] | |||
| name = "flate2" | |||
| version = "1.0.14" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| checksum = "2cfff41391129e0a856d6d822600b8d71179d46879e310417eb9c762eb178b42" | |||
| dependencies = [ | |||
| "cfg-if 0.1.10", | |||
| "crc32fast", | |||
| "libc", | |||
| "miniz_oxide", | |||
| ] | |||
| [[package]] | |||
| name = "fnv" | |||
| version = "1.0.7" | |||
| @@ -817,6 +865,15 @@ dependencies = [ | |||
| "autocfg", | |||
| ] | |||
| [[package]] | |||
| name = "miniz_oxide" | |||
| version = "0.3.7" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" | |||
| dependencies = [ | |||
| "adler32", | |||
| ] | |||
| [[package]] | |||
| name = "mio" | |||
| version = "0.6.22" | |||
| @@ -1348,6 +1405,8 @@ dependencies = [ | |||
| "specs", | |||
| "thiserror", | |||
| "tokio", | |||
| "vfs", | |||
| "vfs-zip", | |||
| ] | |||
| [[package]] | |||
| @@ -1473,6 +1532,26 @@ version = "0.9.2" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" | |||
| [[package]] | |||
| name = "vfs" | |||
| version = "0.4.0" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| checksum = "7cc382cffc2f8d6f9490b96d42a7408d6aa719c2db86491b8b31780208ac9d86" | |||
| dependencies = [ | |||
| "thiserror", | |||
| ] | |||
| [[package]] | |||
| name = "vfs-zip" | |||
| version = "0.2.1" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| checksum = "d68a369614cd12ca384ca6e75ab0a5ac3a5acbfe8003622e20808a322b9bb652" | |||
| dependencies = [ | |||
| "flate2", | |||
| "vfs", | |||
| "zip", | |||
| ] | |||
| [[package]] | |||
| name = "walkdir" | |||
| version = "2.3.1" | |||
| @@ -1689,3 +1768,16 @@ name = "xml-rs" | |||
| version = "0.8.3" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a" | |||
| [[package]] | |||
| name = "zip" | |||
| version = "0.5.8" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| checksum = "543adf038106b64cfca4711c82c917d785e3540e04f7996554488f988ec43124" | |||
| dependencies = [ | |||
| "byteorder", | |||
| "bzip2", | |||
| "crc32fast", | |||
| "flate2", | |||
| "thiserror", | |||
| ] | |||
| @@ -1,4 +1,5 @@ | |||
| use std::fs::read_to_string; | |||
| use std::fs::File; | |||
| use std::io::Read; | |||
| use std::path::Path; | |||
| use std::ptr::{null, null_mut}; | |||
| use std::str::from_utf8; | |||
| @@ -24,9 +25,10 @@ impl Program { | |||
| Self::from_shaders_result(iter.into_iter().map(Ok)) | |||
| } | |||
| pub fn from_shaders_result<I>(iter: I) -> Result<Self, Error> | |||
| pub fn from_shaders_result<I, E>(iter: I) -> Result<Self, E> | |||
| where | |||
| I: IntoIterator<Item = Result<Shader, Error>>, | |||
| I: IntoIterator<Item = Result<Shader, E>>, | |||
| E: From<Error>, | |||
| { | |||
| let id = gl::create_program(); | |||
| let id = Error::err_if(&0, id)?; | |||
| @@ -59,9 +61,9 @@ impl Program { | |||
| buffer.as_mut_ptr() as *mut gl::types::GLchar, | |||
| ); | |||
| let msg = from_utf8(&buffer)?; | |||
| let msg = from_utf8(&buffer).map_err(Error::Utf8Error)?; | |||
| return Err(Error::ShaderLink(msg.into())); | |||
| return Err(Error::ShaderLink(msg.into()).into()); | |||
| } | |||
| Ok(Program { id }) | |||
| @@ -140,13 +142,23 @@ impl Shader { | |||
| Ok(Self { id }) | |||
| } | |||
| pub fn from_reader<R>(type_: Type, mut reader: R) -> Result<Self, Error> | |||
| where | |||
| R: Read, | |||
| { | |||
| let mut source = String::new(); | |||
| reader.read_to_string(&mut source)?; | |||
| Self::from_string(type_, source) | |||
| } | |||
| pub fn from_file<P>(type_: Type, path: P) -> Result<Self, Error> | |||
| where | |||
| P: AsRef<Path>, | |||
| { | |||
| let source = read_to_string(&path)?; | |||
| let source = File::open(&path)?; | |||
| match Self::from_string(type_, source) { | |||
| match Self::from_reader(type_, source) { | |||
| Ok(v) => Ok(v), | |||
| Err(Error::ShaderCompile { code, error }) => Err(Error::ShaderCompile { | |||
| code: format!("{}\n{}", path.as_ref().display(), code), | |||
| @@ -17,3 +17,5 @@ shrev = "1.1" | |||
| specs = "0.16" | |||
| thiserror = "1.0" | |||
| tokio = "0.3" | |||
| vfs = "0.4" | |||
| vfs-zip = "0.2" | |||
| @@ -2,4 +2,25 @@ pub mod camera; | |||
| pub mod events; | |||
| pub mod frame_counter; | |||
| pub mod geometry; | |||
| pub mod vfs; | |||
| pub mod window; | |||
| use std::iter::Iterator; | |||
| use std::ops::Deref; | |||
| use self::vfs::Vfs; | |||
| use glc::shader::{Program, Shader, Type}; | |||
| use crate::Error; | |||
| pub fn load_program<I>(vfs: &Vfs, iter: I) -> Result<Program, Error> | |||
| where | |||
| I: IntoIterator<Item = (Type, &'static str)>, | |||
| { | |||
| Program::from_shaders_result(iter.into_iter().map(|(t, p)| { | |||
| let file = vfs.deref().join(p)?.open_file()?; | |||
| let shader = Shader::from_reader(t, file)?; | |||
| Ok(shader) | |||
| })) | |||
| } | |||
| @@ -0,0 +1,72 @@ | |||
| use std::collections::HashSet; | |||
| use std::env::{current_dir, current_exe}; | |||
| use std::fs::File; | |||
| use std::ops::Deref; | |||
| use log::info; | |||
| use vfs::{ | |||
| impls::{overlay::OverlayFS, physical::PhysicalFS}, | |||
| VfsPath, | |||
| }; | |||
| use vfs_zip::ZipReadOnly as ZipFS; | |||
| use crate::Error; | |||
| pub struct Vfs(pub VfsPath); | |||
| impl Vfs { | |||
| pub fn new() -> Result<Self, Error> { | |||
| let dirs = vec![ | |||
| current_exe() | |||
| .ok() | |||
| .as_ref() | |||
| .and_then(|p| p.parent()) | |||
| .map(|p| p.to_owned()), | |||
| current_exe() | |||
| .ok() | |||
| .as_ref() | |||
| .and_then(|p| p.parent()) | |||
| .map(|p| p.join("space-crush")), | |||
| current_dir().ok(), | |||
| current_dir().ok().map(|p| p.join("space-crush")), | |||
| ] | |||
| .into_iter() | |||
| .filter_map(|d| d); | |||
| let mut paths = HashSet::new(); | |||
| let mut layers = Vec::new(); | |||
| for dir in dirs.clone() { | |||
| if paths.insert(dir.clone()) { | |||
| info!("Adding layer to VFS: {}", dir.display()); | |||
| let layer = VfsPath::new(PhysicalFS::new(dir)); | |||
| layers.push(layer); | |||
| } | |||
| } | |||
| for dir in dirs { | |||
| let path = dir.join("resources.bin"); | |||
| if path.is_file() && paths.insert(path.to_owned()) { | |||
| info!("Adding layer to VFS: {}", dir.display()); | |||
| let zip = File::open(path)?; | |||
| let layer = VfsPath::new(ZipFS::new_relaxed(zip)?); | |||
| layers.push(layer); | |||
| } | |||
| } | |||
| Ok(Self(VfsPath::new(OverlayFS::new(&layers)))) | |||
| } | |||
| } | |||
| impl Deref for Vfs { | |||
| type Target = VfsPath; | |||
| fn deref(&self) -> &Self::Target { | |||
| &self.0 | |||
| } | |||
| } | |||
| @@ -19,7 +19,7 @@ impl Window { | |||
| let context = loop { | |||
| let multisampling = match multisampling.next() { | |||
| Some(multisampling) => multisampling, | |||
| None => return Err(Error::UnableToCreateContext), | |||
| None => return Err(Error::CreateContext), | |||
| }; | |||
| info!("Create OpenGL context (multisampling={})", multisampling); | |||
| @@ -6,7 +6,7 @@ use specs::{Dispatcher, DispatcherBuilder, World}; | |||
| use crate::Error; | |||
| use misc::{events::Events, geometry::Geometry, window::Window}; | |||
| use misc::{events::Events, geometry::Geometry, vfs::Vfs, window::Window}; | |||
| use render::{Init, Test}; | |||
| use systems::{State, StateUpdate}; | |||
| @@ -22,6 +22,9 @@ impl<'a, 'b> App<'a, 'b> { | |||
| let events = Events::new(world); | |||
| let window = Window::new(events.handle())?; | |||
| world.insert(Vfs::new()?); | |||
| world.insert(Geometry::new()?); | |||
| let mut dispatcher = DispatcherBuilder::new() | |||
| .with(StateUpdate::new(world), "state_update", &[]) | |||
| .with_thread_local(Init::new(world)?) | |||
| @@ -29,8 +32,6 @@ impl<'a, 'b> App<'a, 'b> { | |||
| .build(); | |||
| dispatcher.setup(world); | |||
| world.insert(Geometry::new()?); | |||
| Ok(Self { | |||
| is_running: true, | |||
| events, | |||
| @@ -1,6 +1,6 @@ | |||
| use glc::{ | |||
| misc::Bindable, | |||
| shader::{Program, Shader, Type}, | |||
| shader::{Program, Type}, | |||
| }; | |||
| use log::{error, info}; | |||
| use shrev::{EventChannel, ReaderId}; | |||
| @@ -10,6 +10,7 @@ use crate::Error; | |||
| use super::super::misc::{ | |||
| camera::Camera, events::WindowEvent, frame_counter::FrameCounter, geometry::Geometry, | |||
| load_program, vfs::Vfs, | |||
| }; | |||
| /* Global */ | |||
| @@ -37,21 +38,20 @@ pub struct Init { | |||
| impl Init { | |||
| pub fn new(world: &mut World) -> Result<Self, Error> { | |||
| let shaders = vec![ | |||
| (Type::Vertex, include_str!("shader/noise.vert")), | |||
| (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())), | |||
| world.insert(Global::new()?); | |||
| let vfs = world.fetch::<Vfs>(); | |||
| let program = load_program( | |||
| &vfs, | |||
| vec![ | |||
| (Type::Vertex, "resources/shader/noise.vert"), | |||
| (Type::Fragment, "resources/shader/noise.frag"), | |||
| ], | |||
| )?; | |||
| let window_events_id = world | |||
| .fetch_mut::<EventChannel<WindowEvent>>() | |||
| .register_reader(); | |||
| world.insert(Global::new()?); | |||
| Ok(Self { | |||
| program, | |||
| window_events_id, | |||
| @@ -1,14 +1,17 @@ | |||
| use glc::{ | |||
| matrix::{Angle, Matrix4f}, | |||
| misc::Bindable, | |||
| shader::{Program, Shader, Type, Uniform}, | |||
| shader::{Program, Type, Uniform}, | |||
| vector::Vector3f, | |||
| }; | |||
| use specs::{ReadExpect, System, World}; | |||
| use crate::Error; | |||
| use super::{super::misc::geometry::Geometry, init::Global}; | |||
| use super::{ | |||
| super::misc::{geometry::Geometry, load_program, vfs::Vfs}, | |||
| init::Global, | |||
| }; | |||
| pub struct Test { | |||
| program: Program, | |||
| @@ -17,14 +20,13 @@ pub struct Test { | |||
| impl Test { | |||
| pub fn new(world: &World) -> Result<Self, Error> { | |||
| let shaders = vec![ | |||
| (Type::Vertex, include_str!("shader/quad.vert")), | |||
| (Type::Fragment, include_str!("shader/quad.frag")), | |||
| ]; | |||
| let program = Program::from_shaders_result( | |||
| shaders | |||
| .into_iter() | |||
| .map(|(t, s)| Shader::from_string(t, s.into())), | |||
| let vfs = world.fetch::<Vfs>(); | |||
| let program = load_program( | |||
| &vfs, | |||
| vec![ | |||
| (Type::Vertex, "resources/shader/quad.vert"), | |||
| (Type::Fragment, "resources/shader/quad.frag"), | |||
| ], | |||
| )?; | |||
| let global = world.fetch::<Global>(); | |||
| @@ -1,9 +1,22 @@ | |||
| use std::io::Error as IoError; | |||
| use glc::error::Error as GlcError; | |||
| use glutin::{ContextError as GlutinContextError, CreationError as GlutinCreationError}; | |||
| use thiserror::Error; | |||
| use vfs::VfsError; | |||
| use vfs_zip::Error as VfsZipError; | |||
| #[derive(Debug, Error)] | |||
| pub enum Error { | |||
| #[error("IO Error: {0}")] | |||
| IoError(IoError), | |||
| #[error("VFS Error: {0}")] | |||
| VfsError(VfsError), | |||
| #[error("VFS ZIP Error: {0}")] | |||
| VfsZipError(VfsZipError), | |||
| #[error("GLC Error: {0}")] | |||
| GlcError(GlcError), | |||
| @@ -14,7 +27,28 @@ pub enum Error { | |||
| GlutinCreationError(GlutinCreationError), | |||
| #[error("Unable to create OpenGL context")] | |||
| UnableToCreateContext, | |||
| CreateContext, | |||
| #[error("Unable to initialize VFS")] | |||
| InitVFS, | |||
| } | |||
| impl From<IoError> for Error { | |||
| fn from(err: IoError) -> Self { | |||
| Self::IoError(err) | |||
| } | |||
| } | |||
| impl From<VfsError> for Error { | |||
| fn from(err: VfsError) -> Self { | |||
| Self::VfsError(err) | |||
| } | |||
| } | |||
| impl From<VfsZipError> for Error { | |||
| fn from(err: VfsZipError) -> Self { | |||
| Self::VfsZipError(err) | |||
| } | |||
| } | |||
| impl From<GlcError> for Error { | |||