@@ -140,9 +140,9 @@ dependencies = [ | |||||
[[package]] | [[package]] | ||||
name = "cc" | name = "cc" | ||||
version = "1.0.65" | |||||
version = "1.0.66" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "95752358c8f7552394baf48cd82695b345628ad3f170d607de3ca03b8dacca15" | |||||
checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" | |||||
[[package]] | [[package]] | ||||
name = "cfg-if" | name = "cfg-if" | ||||
@@ -178,15 +178,6 @@ dependencies = [ | |||||
"winapi 0.3.9", | "winapi 0.3.9", | ||||
] | ] | ||||
[[package]] | |||||
name = "cloudabi" | |||||
version = "0.1.0" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" | |||||
dependencies = [ | |||||
"bitflags", | |||||
] | |||||
[[package]] | [[package]] | ||||
name = "cocoa" | name = "cocoa" | ||||
version = "0.23.0" | version = "0.23.0" | ||||
@@ -738,7 +729,7 @@ dependencies = [ | |||||
"glyph_brush_draw_cache", | "glyph_brush_draw_cache", | ||||
"glyph_brush_layout", | "glyph_brush_layout", | ||||
"log", | "log", | ||||
"ordered-float 1.1.0", | |||||
"ordered-float 1.1.1", | |||||
"rustc-hash", | "rustc-hash", | ||||
"twox-hash", | "twox-hash", | ||||
] | ] | ||||
@@ -881,15 +872,15 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" | |||||
[[package]] | [[package]] | ||||
name = "libc" | name = "libc" | ||||
version = "0.2.80" | |||||
version = "0.2.81" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" | |||||
checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" | |||||
[[package]] | [[package]] | ||||
name = "libloading" | name = "libloading" | ||||
version = "0.6.5" | |||||
version = "0.6.6" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "1090080fe06ec2648d0da3881d9453d97e71a45f00eb179af7fdd7e3f686fdb0" | |||||
checksum = "e9367bdfa836b7e3cf895867f7a570283444da90562980ec2263d6e1569b16bc" | |||||
dependencies = [ | dependencies = [ | ||||
"cfg-if 1.0.0", | "cfg-if 1.0.0", | ||||
"winapi 0.3.9", | "winapi 0.3.9", | ||||
@@ -1012,9 +1003,9 @@ dependencies = [ | |||||
[[package]] | [[package]] | ||||
name = "mio" | name = "mio" | ||||
version = "0.6.22" | |||||
version = "0.6.23" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" | |||||
checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" | |||||
dependencies = [ | dependencies = [ | ||||
"cfg-if 0.1.10", | "cfg-if 0.1.10", | ||||
"fuchsia-zircon", | "fuchsia-zircon", | ||||
@@ -1043,9 +1034,9 @@ dependencies = [ | |||||
[[package]] | [[package]] | ||||
name = "miow" | name = "miow" | ||||
version = "0.2.1" | |||||
version = "0.2.2" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" | |||||
checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" | |||||
dependencies = [ | dependencies = [ | ||||
"kernel32-sys", | "kernel32-sys", | ||||
"net2", | "net2", | ||||
@@ -1106,9 +1097,9 @@ checksum = "c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d" | |||||
[[package]] | [[package]] | ||||
name = "net2" | name = "net2" | ||||
version = "0.2.35" | |||||
version = "0.2.36" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "3ebc3ec692ed7c9a255596c67808dee269f64655d8baf7b4f0638e51ba1d6853" | |||||
checksum = "d7cf75f38f16cb05ea017784dc6dbfd354f76c223dba37701734c4f5a9337d02" | |||||
dependencies = [ | dependencies = [ | ||||
"cfg-if 0.1.10", | "cfg-if 0.1.10", | ||||
"libc", | "libc", | ||||
@@ -1215,18 +1206,18 @@ checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" | |||||
[[package]] | [[package]] | ||||
name = "ordered-float" | name = "ordered-float" | ||||
version = "1.1.0" | |||||
version = "1.1.1" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "3741934be594d77de1c8461ebcbbe866f585ea616a9753aa78f2bdc69f0e4579" | |||||
checksum = "3305af35278dd29f46fcdd139e0b1fbfae2153f0e5928b39b035542dd31e37b7" | |||||
dependencies = [ | dependencies = [ | ||||
"num-traits", | "num-traits", | ||||
] | ] | ||||
[[package]] | [[package]] | ||||
name = "ordered-float" | name = "ordered-float" | ||||
version = "2.0.0" | |||||
version = "2.0.1" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "9fe9037165d7023b1228bc4ae9a2fa1a2b0095eca6c2998c624723dfd01314a5" | |||||
checksum = "dacdec97876ef3ede8c50efc429220641a0b11ba0048b4b0c357bccbc47c5204" | |||||
dependencies = [ | dependencies = [ | ||||
"num-traits", | "num-traits", | ||||
] | ] | ||||
@@ -1271,12 +1262,11 @@ dependencies = [ | |||||
[[package]] | [[package]] | ||||
name = "parking_lot_core" | name = "parking_lot_core" | ||||
version = "0.8.0" | |||||
version = "0.8.1" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b" | |||||
checksum = "d7c6d9b8427445284a09c55be860a15855ab580a417ccad9da88f5a06787ced0" | |||||
dependencies = [ | dependencies = [ | ||||
"cfg-if 0.1.10", | |||||
"cloudabi", | |||||
"cfg-if 1.0.0", | |||||
"instant", | "instant", | ||||
"libc", | "libc", | ||||
"redox_syscall", | "redox_syscall", | ||||
@@ -1523,9 +1513,12 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" | |||||
[[package]] | [[package]] | ||||
name = "serde" | name = "serde" | ||||
version = "1.0.117" | |||||
version = "1.0.118" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a" | |||||
checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" | |||||
dependencies = [ | |||||
"serde_derive", | |||||
] | |||||
[[package]] | [[package]] | ||||
name = "serde-value" | name = "serde-value" | ||||
@@ -1533,7 +1526,7 @@ version = "0.6.0" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "5a65a7291a8a568adcae4c10a677ebcedbc6c9cec91c054dee2ce40b0e3290eb" | checksum = "5a65a7291a8a568adcae4c10a677ebcedbc6c9cec91c054dee2ce40b0e3290eb" | ||||
dependencies = [ | dependencies = [ | ||||
"ordered-float 1.1.0", | |||||
"ordered-float 1.1.1", | |||||
"serde", | "serde", | ||||
] | ] | ||||
@@ -1621,9 +1614,12 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" | |||||
[[package]] | [[package]] | ||||
name = "smallvec" | name = "smallvec" | ||||
version = "1.5.0" | |||||
version = "1.5.1" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "7acad6f34eb9e8a259d3283d1e8c1d34d7415943d4895f65cc73813c7396fc85" | |||||
checksum = "ae524f056d7d770e174287294f562e95044c68e88dec909a00d2094805db9d75" | |||||
dependencies = [ | |||||
"serde", | |||||
] | |||||
[[package]] | [[package]] | ||||
name = "smithay-client-toolkit" | name = "smithay-client-toolkit" | ||||
@@ -1657,11 +1653,14 @@ dependencies = [ | |||||
"log", | "log", | ||||
"log4rs", | "log4rs", | ||||
"num_cpus", | "num_cpus", | ||||
"ordered-float 2.0.0", | |||||
"ordered-float 2.0.1", | |||||
"rand", | "rand", | ||||
"serde", | |||||
"serde_json", | |||||
"serde_yaml", | "serde_yaml", | ||||
"shred", | "shred", | ||||
"shrev", | "shrev", | ||||
"smallvec", | |||||
"specs", | "specs", | ||||
"thiserror", | "thiserror", | ||||
"tokio", | "tokio", | ||||
@@ -1699,9 +1698,9 @@ checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" | |||||
[[package]] | [[package]] | ||||
name = "syn" | name = "syn" | ||||
version = "1.0.50" | |||||
version = "1.0.53" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "443b4178719c5a851e1bde36ce12da21d74a0e60b4d982ec3385a933c812f0f6" | |||||
checksum = "8833e20724c24de12bbaba5ad230ea61c3eafb05b881c7c9d3cfe8638b187e68" | |||||
dependencies = [ | dependencies = [ | ||||
"proc-macro2", | "proc-macro2", | ||||
"quote", | "quote", | ||||
@@ -1761,9 +1760,9 @@ dependencies = [ | |||||
[[package]] | [[package]] | ||||
name = "tokio" | name = "tokio" | ||||
version = "0.3.4" | |||||
version = "0.3.5" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "9dfe2523e6fa84ddf5e688151d4e5fddc51678de9752c6512a24714c23818d61" | |||||
checksum = "a12a3eb39ee2c231be64487f1fcbe726c8f2514876a55480a5ab8559fc374252" | |||||
dependencies = [ | dependencies = [ | ||||
"autocfg", | "autocfg", | ||||
"pin-project-lite", | "pin-project-lite", | ||||
@@ -2046,6 +2045,7 @@ dependencies = [ | |||||
"parking_lot", | "parking_lot", | ||||
"percent-encoding", | "percent-encoding", | ||||
"raw-window-handle", | "raw-window-handle", | ||||
"serde", | |||||
"smithay-client-toolkit", | "smithay-client-toolkit", | ||||
"wayland-client", | "wayland-client", | ||||
"winapi 0.3.9", | "winapi 0.3.9", | ||||
@@ -8,16 +8,19 @@ edition = "2018" | |||||
futures = "0.3" | futures = "0.3" | ||||
gl = { version = "0.1", features = [ "use_log_crate" ] } | gl = { version = "0.1", features = [ "use_log_crate" ] } | ||||
glc = "0.1" | glc = "0.1" | ||||
glutin = "0.25" | |||||
glutin = { version = "0.25", features = [ "serde" ] } | |||||
glyph_brush = "0.7" | glyph_brush = "0.7" | ||||
log = { version = "0.4", features = [ "max_level_trace", "release_max_level_warn" ] } | log = { version = "0.4", features = [ "max_level_trace", "release_max_level_warn" ] } | ||||
log4rs = "0.13" | log4rs = "0.13" | ||||
num_cpus = "1.13" | num_cpus = "1.13" | ||||
ordered-float = "2.0" | ordered-float = "2.0" | ||||
rand = "0.7" | rand = "0.7" | ||||
serde = { version = "1.0", features = ["derive"] } | |||||
serde_json = "1.0" | |||||
serde_yaml = "0.8" | serde_yaml = "0.8" | ||||
shred = { version = "0.10", features = [ "shred-derive" ] } | shred = { version = "0.10", features = [ "shred-derive" ] } | ||||
shrev = "1.1" | shrev = "1.1" | ||||
smallvec = { version = "1.5", features = [ "serde" ] } | |||||
specs = "0.16" | specs = "0.16" | ||||
thiserror = "1.0" | thiserror = "1.0" | ||||
tokio = "0.3" | tokio = "0.3" | ||||
@@ -0,0 +1,31 @@ | |||||
{ | |||||
"video": { | |||||
"resolution": [ | |||||
1280, | |||||
720 | |||||
], | |||||
"multisampling": 16, | |||||
"fullscreen": false, | |||||
"windowed": true | |||||
}, | |||||
"input": { | |||||
"key_camera_move_up": [ | |||||
"W", | |||||
"Up" | |||||
], | |||||
"key_camera_move_down": [ | |||||
"S", | |||||
"Down" | |||||
], | |||||
"key_camera_move_left": [ | |||||
"A", | |||||
"Left" | |||||
], | |||||
"key_camera_move_right": [ | |||||
"D", | |||||
"Right" | |||||
], | |||||
"speed_camera_move": 1.0, | |||||
"speed_camera_zoom": 100.0 | |||||
} | |||||
} |
@@ -1,38 +1,89 @@ | |||||
use glutin::{ | use glutin::{ | ||||
dpi::{PhysicalPosition, PhysicalSize}, | dpi::{PhysicalPosition, PhysicalSize}, | ||||
event_loop::EventLoop, | event_loop::EventLoop, | ||||
window::Window as GlutinWindow, | |||||
window::WindowBuilder, | |||||
monitor::VideoMode, | |||||
window::{Fullscreen, Window as GlutinWindow, WindowBuilder}, | |||||
Api, ContextBuilder, ContextWrapper, GlProfile, GlRequest, PossiblyCurrent, | Api, ContextBuilder, ContextWrapper, GlProfile, GlRequest, PossiblyCurrent, | ||||
}; | }; | ||||
use log::info; | |||||
use log::{error, info}; | |||||
use crate::Error; | use crate::Error; | ||||
use super::super::resources::Config; | |||||
pub struct Window { | pub struct Window { | ||||
context: ContextWrapper<PossiblyCurrent, GlutinWindow>, | context: ContextWrapper<PossiblyCurrent, GlutinWindow>, | ||||
} | } | ||||
impl Window { | impl Window { | ||||
pub fn new<T>(event_loop: &EventLoop<T>) -> Result<Self, Error> { | |||||
pub fn new<T>(event_loop: &EventLoop<T>, config: &Config) -> Result<Self, Error> { | |||||
let monitor = event_loop | |||||
.primary_monitor() | |||||
.or_else(|| event_loop.available_monitors().next()); | |||||
let (fullscreen, border) = match (config.video.windowed, config.video.fullscreen) { | |||||
(false, true) => { | |||||
let mut video_mode: Option<VideoMode> = None; | |||||
if let Some(monitor) = monitor { | |||||
for mode in monitor.video_modes() { | |||||
video_mode = Some(match video_mode { | |||||
Some(current) => { | |||||
if mode.size().width <= config.video.resolution.0 | |||||
&& mode.size().height <= config.video.resolution.1 | |||||
&& mode.size().width >= current.size().width | |||||
&& mode.size().height >= current.size().height | |||||
&& mode.bit_depth() >= current.bit_depth() | |||||
&& mode.refresh_rate() >= current.refresh_rate() | |||||
{ | |||||
mode | |||||
} else { | |||||
current | |||||
} | |||||
} | |||||
None => mode, | |||||
}); | |||||
} | |||||
} | |||||
match video_mode { | |||||
Some(video_mode) => (Some(Fullscreen::Exclusive(video_mode)), false), | |||||
None => { | |||||
error!("Unable to find video mode for exclusive fullscreen!"); | |||||
(Some(Fullscreen::Borderless(None)), false) | |||||
} | |||||
} | |||||
} | |||||
(true, true) => (Some(Fullscreen::Borderless(None)), false), | |||||
(false, false) => (None, false), | |||||
(true, false) => (None, true), | |||||
}; | |||||
let mut multisampling = [16u16, 8, 4, 2, 1, 0].iter(); | let mut multisampling = [16u16, 8, 4, 2, 1, 0].iter(); | ||||
let context = loop { | let context = loop { | ||||
let multisampling = match multisampling.next() { | let multisampling = match multisampling.next() { | ||||
Some(multisampling) => multisampling, | |||||
Some(multisampling) => *multisampling, | |||||
None => return Err(Error::CreateContext), | None => return Err(Error::CreateContext), | ||||
}; | }; | ||||
if config.video.multisampling < multisampling { | |||||
continue; | |||||
} | |||||
info!("Create OpenGL context (multisampling={})", multisampling); | info!("Create OpenGL context (multisampling={})", multisampling); | ||||
let window_builder = WindowBuilder::new() | let window_builder = WindowBuilder::new() | ||||
.with_title("space-crush") | .with_title("space-crush") | ||||
.with_visible(true) | .with_visible(true) | ||||
.with_inner_size(PhysicalSize::new(WINDOW_WIDTH, WINDOW_HEIGHT)); | |||||
.with_decorations(border) | |||||
.with_fullscreen(fullscreen.clone()) | |||||
.with_inner_size::<PhysicalSize<u32>>(config.video.resolution.into()); | |||||
let ret = ContextBuilder::new() | let ret = ContextBuilder::new() | ||||
.with_double_buffer(Some(true)) | .with_double_buffer(Some(true)) | ||||
.with_hardware_acceleration(Some(true)) | .with_hardware_acceleration(Some(true)) | ||||
.with_pixel_format(24, 8) | .with_pixel_format(24, 8) | ||||
.with_multisampling(*multisampling) | |||||
.with_multisampling(multisampling) | |||||
.with_vsync(false) | .with_vsync(false) | ||||
.with_gl(GlRequest::Specific(Api::OpenGl, (4, 5))) | .with_gl(GlRequest::Specific(Api::OpenGl, (4, 5))) | ||||
.with_gl_profile(GlProfile::Core) | .with_gl_profile(GlProfile::Core) | ||||
@@ -68,6 +119,3 @@ impl Window { | |||||
Ok(()) | Ok(()) | ||||
} | } | ||||
} | } | ||||
const WINDOW_WIDTH: u32 = 1280; | |||||
const WINDOW_HEIGHT: u32 = 720; |
@@ -9,7 +9,7 @@ use crate::Error; | |||||
use misc::{Events, TextManager, Window}; | use misc::{Events, TextManager, Window}; | ||||
use render::{Debug, Init, Test}; | use render::{Debug, Init, Test}; | ||||
use resources::{Camera, Geometry, State}; | |||||
use resources::{Camera, Config, Geometry, State}; | |||||
use systems::StateUpdate; | use systems::StateUpdate; | ||||
pub struct App<'a, 'b> { | pub struct App<'a, 'b> { | ||||
@@ -21,9 +21,11 @@ pub struct App<'a, 'b> { | |||||
impl<'a, 'b> App<'a, 'b> { | impl<'a, 'b> App<'a, 'b> { | ||||
pub fn new(world: &mut World) -> Result<Self, Error> { | pub fn new(world: &mut World) -> Result<Self, Error> { | ||||
let config = Config::new(world)?; | |||||
let events = Events::new(world); | let events = Events::new(world); | ||||
let window = Window::new(events.handle())?; | |||||
let window = Window::new(events.handle(), &config)?; | |||||
world.insert(config); | |||||
world.insert(Camera::new()?); | world.insert(Camera::new()?); | ||||
world.insert(Geometry::new()?); | world.insert(Geometry::new()?); | ||||
world.insert(State::default()); | world.insert(State::default()); | ||||
@@ -11,8 +11,8 @@ use specs::{prelude::*, ReadExpect, System, World, WriteExpect}; | |||||
use crate::Error; | use crate::Error; | ||||
use super::super::{ | use super::super::{ | ||||
misc::{MouseEvent, VirtualKeyCode, WorldHelper}, | |||||
resources::{Camera, Geometry, State}, | |||||
misc::{MouseEvent, WorldHelper}, | |||||
resources::{Camera, Config, Geometry, State}, | |||||
}; | }; | ||||
pub struct Init { | pub struct Init { | ||||
@@ -42,6 +42,7 @@ impl Init { | |||||
pub struct InitData<'a> { | pub struct InitData<'a> { | ||||
camera: WriteExpect<'a, Camera>, | camera: WriteExpect<'a, Camera>, | ||||
state: ReadExpect<'a, State>, | state: ReadExpect<'a, State>, | ||||
config: ReadExpect<'a, Config>, | |||||
geometry: ReadExpect<'a, Geometry>, | geometry: ReadExpect<'a, Geometry>, | ||||
mouse_events: ReadExpect<'a, EventChannel<MouseEvent>>, | mouse_events: ReadExpect<'a, EventChannel<MouseEvent>>, | ||||
} | } | ||||
@@ -53,6 +54,7 @@ impl<'a> System<'a> for Init { | |||||
let InitData { | let InitData { | ||||
mut camera, | mut camera, | ||||
state, | state, | ||||
config, | |||||
geometry, | geometry, | ||||
mouse_events, | mouse_events, | ||||
} = data; | } = data; | ||||
@@ -72,7 +74,8 @@ impl<'a> System<'a> for Init { | |||||
let events = mouse_events.read(&mut self.mouse_event_id); | let events = mouse_events.read(&mut self.mouse_event_id); | ||||
for event in events { | for event in events { | ||||
if let MouseEvent::ScrollY(delta) = event { | if let MouseEvent::ScrollY(delta) = event { | ||||
let z = CAMERA_ZOOM_SPEED / (CAMERA_ZOOM_SPEED - delta); | |||||
let s = config.input.speed_camera_zoom; | |||||
let z = s / (s - delta); | |||||
let m = Matrix4f::translate((state.mouse_pos.0, state.mouse_pos.1, 0.0).into()) | let m = Matrix4f::translate((state.mouse_pos.0, state.mouse_pos.1, 0.0).into()) | ||||
* Matrix4f::scale(z.into()) | * Matrix4f::scale(z.into()) | ||||
* Matrix4f::translate((-state.mouse_pos.0, -state.mouse_pos.1, 0.0).into()); | * Matrix4f::translate((-state.mouse_pos.0, -state.mouse_pos.1, 0.0).into()); | ||||
@@ -84,20 +87,19 @@ impl<'a> System<'a> for Init { | |||||
} | } | ||||
/* move camera */ | /* move camera */ | ||||
let up = state.key_state(KEY_CAMERA_UP) || state.key_state(KEY_CAMERA_UP_ALT); | |||||
let down = state.key_state(KEY_CAMERA_DOWN) || state.key_state(KEY_CAMERA_DOWN_ALT); | |||||
let left = state.key_state(KEY_CAMERA_LEFT) || state.key_state(KEY_CAMERA_LEFT_ALT); | |||||
let right = state.key_state(KEY_CAMERA_RIGHT) || state.key_state(KEY_CAMERA_RIGHT_ALT); | |||||
let translate = Vector3f::new( | |||||
if left { CAMERA_MOVE_SPEED_KEY } else { 0.0 } | |||||
+ if right { -CAMERA_MOVE_SPEED_KEY } else { 0.0 }, | |||||
if up { -CAMERA_MOVE_SPEED_KEY } else { 0.0 } | |||||
+ if down { CAMERA_MOVE_SPEED_KEY } else { 0.0 }, | |||||
0.0, | |||||
); | |||||
let up = state.key_state(&config.input.key_camera_move_up); | |||||
let down = state.key_state(&config.input.key_camera_move_down); | |||||
let left = state.key_state(&config.input.key_camera_move_left); | |||||
let right = state.key_state(&config.input.key_camera_move_right); | |||||
if up || down || left || right { | if up || down || left || right { | ||||
let s = config.input.speed_camera_move; | |||||
let translate = Vector3f::new( | |||||
if left { s } else { 0.0 } + if right { -s } else { 0.0 }, | |||||
if up { -s } else { 0.0 } + if down { s } else { 0.0 }, | |||||
0.0, | |||||
); | |||||
let m = Matrix4f::translate(translate); | let m = Matrix4f::translate(translate); | ||||
if let Err(err) = camera.update_with(move |v| m * v) { | if let Err(err) = camera.update_with(move |v| m * v) { | ||||
error!("Error while moving camera: {}", err); | error!("Error while moving camera: {}", err); | ||||
@@ -110,16 +112,3 @@ impl<'a> System<'a> for Init { | |||||
self.program.unbind(); | self.program.unbind(); | ||||
} | } | ||||
} | } | ||||
const CAMERA_MOVE_SPEED_KEY: f32 = 2.0; | |||||
const CAMERA_ZOOM_SPEED: f32 = 100.0; | |||||
const KEY_CAMERA_UP: VirtualKeyCode = VirtualKeyCode::Up; | |||||
const KEY_CAMERA_DOWN: VirtualKeyCode = VirtualKeyCode::Down; | |||||
const KEY_CAMERA_LEFT: VirtualKeyCode = VirtualKeyCode::Left; | |||||
const KEY_CAMERA_RIGHT: VirtualKeyCode = VirtualKeyCode::Right; | |||||
const KEY_CAMERA_UP_ALT: VirtualKeyCode = VirtualKeyCode::W; | |||||
const KEY_CAMERA_DOWN_ALT: VirtualKeyCode = VirtualKeyCode::S; | |||||
const KEY_CAMERA_LEFT_ALT: VirtualKeyCode = VirtualKeyCode::A; | |||||
const KEY_CAMERA_RIGHT_ALT: VirtualKeyCode = VirtualKeyCode::D; |
@@ -0,0 +1,137 @@ | |||||
use log::warn; | |||||
use serde::{Deserialize, Serialize}; | |||||
use serde_json::from_reader; | |||||
use smallvec::{smallvec, SmallVec}; | |||||
use specs::World; | |||||
use crate::{misc::Vfs, Error}; | |||||
use super::super::misc::{VirtualKeyCode, WorldHelper}; | |||||
#[derive(Debug, Default, Serialize, Deserialize)] | |||||
pub struct Config { | |||||
#[serde(default)] | |||||
pub video: Video, | |||||
#[serde(default)] | |||||
pub input: Input, | |||||
} | |||||
#[derive(Debug, Serialize, Deserialize)] | |||||
pub struct Video { | |||||
#[serde(default = "defaults::resolution")] | |||||
pub resolution: (u32, u32), | |||||
#[serde(default = "defaults::multisampling")] | |||||
pub multisampling: u16, | |||||
#[serde(default = "defaults::fullscreen")] | |||||
pub fullscreen: bool, | |||||
#[serde(default = "defaults::windowed")] | |||||
pub windowed: bool, | |||||
} | |||||
#[derive(Debug, Serialize, Deserialize)] | |||||
pub struct Input { | |||||
#[serde(default = "defaults::key_camera_move_up")] | |||||
pub key_camera_move_up: VirtualKeyCodes, | |||||
#[serde(default = "defaults::key_camera_move_down")] | |||||
pub key_camera_move_down: VirtualKeyCodes, | |||||
#[serde(default = "defaults::key_camera_move_left")] | |||||
pub key_camera_move_left: VirtualKeyCodes, | |||||
#[serde(default = "defaults::key_camera_move_right")] | |||||
pub key_camera_move_right: VirtualKeyCodes, | |||||
#[serde(default = "defaults::speed_camera_move")] | |||||
pub speed_camera_move: f32, | |||||
#[serde(default = "defaults::speed_camera_zoom")] | |||||
pub speed_camera_zoom: f32, | |||||
} | |||||
type VirtualKeyCodes = SmallVec<[VirtualKeyCode; 2]>; | |||||
impl Config { | |||||
pub fn new(world: &World) -> Result<Self, Error> { | |||||
let vfs = world.resource::<Vfs>()?; | |||||
let config = match vfs.join("config.json")?.open_file() { | |||||
Ok(mut file) => from_reader(&mut file)?, | |||||
Err(err) => { | |||||
warn!( | |||||
"Unable to load config file, falling back to default config: {}", | |||||
err | |||||
); | |||||
Config::default() | |||||
} | |||||
}; | |||||
Ok(config) | |||||
} | |||||
} | |||||
impl Default for Video { | |||||
fn default() -> Self { | |||||
Self { | |||||
resolution: defaults::resolution(), | |||||
multisampling: defaults::multisampling(), | |||||
fullscreen: defaults::fullscreen(), | |||||
windowed: defaults::windowed(), | |||||
} | |||||
} | |||||
} | |||||
impl Default for Input { | |||||
fn default() -> Self { | |||||
Self { | |||||
key_camera_move_up: defaults::key_camera_move_up(), | |||||
key_camera_move_down: defaults::key_camera_move_down(), | |||||
key_camera_move_left: defaults::key_camera_move_left(), | |||||
key_camera_move_right: defaults::key_camera_move_right(), | |||||
speed_camera_move: defaults::speed_camera_move(), | |||||
speed_camera_zoom: defaults::speed_camera_zoom(), | |||||
} | |||||
} | |||||
} | |||||
mod defaults { | |||||
use super::*; | |||||
pub fn resolution() -> (u32, u32) { | |||||
(1280, 720) | |||||
} | |||||
pub fn multisampling() -> u16 { | |||||
0 | |||||
} | |||||
pub fn fullscreen() -> bool { | |||||
true | |||||
} | |||||
pub fn windowed() -> bool { | |||||
true | |||||
} | |||||
pub fn key_camera_move_up() -> VirtualKeyCodes { | |||||
smallvec![VirtualKeyCode::W, VirtualKeyCode::Up] | |||||
} | |||||
pub fn key_camera_move_down() -> VirtualKeyCodes { | |||||
smallvec![VirtualKeyCode::S, VirtualKeyCode::Down] | |||||
} | |||||
pub fn key_camera_move_left() -> VirtualKeyCodes { | |||||
smallvec![VirtualKeyCode::A, VirtualKeyCode::Left] | |||||
} | |||||
pub fn key_camera_move_right() -> VirtualKeyCodes { | |||||
smallvec![VirtualKeyCode::D, VirtualKeyCode::Right] | |||||
} | |||||
pub fn speed_camera_move() -> f32 { | |||||
2.0 | |||||
} | |||||
pub fn speed_camera_zoom() -> f32 { | |||||
100.0 | |||||
} | |||||
} |
@@ -1,7 +1,9 @@ | |||||
mod camera; | mod camera; | ||||
mod config; | |||||
mod geometry; | mod geometry; | ||||
mod state; | mod state; | ||||
pub use camera::Camera; | pub use camera::Camera; | ||||
pub use config::Config; | |||||
pub use geometry::Geometry; | pub use geometry::Geometry; | ||||
pub use state::State; | pub use state::State; |
@@ -1,6 +1,7 @@ | |||||
#![allow(dead_code)] | #![allow(dead_code)] | ||||
use std::collections::HashSet; | use std::collections::HashSet; | ||||
use std::iter::IntoIterator; | |||||
use super::super::misc::{MouseButton, VirtualKeyCode}; | use super::super::misc::{MouseButton, VirtualKeyCode}; | ||||
@@ -9,37 +10,50 @@ pub struct State { | |||||
pub mouse_pos: (f32, f32), | pub mouse_pos: (f32, f32), | ||||
pub resolution: (u32, u32), | pub resolution: (u32, u32), | ||||
pub close_requested: bool, | pub close_requested: bool, | ||||
pub key_states: HashSet<KeyState>, | |||||
} | |||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] | |||||
pub enum KeyState { | |||||
KeyCode(VirtualKeyCode), | |||||
MouseButton(MouseButton), | |||||
pub key_states: HashSet<VirtualKeyCode>, | |||||
pub button_states: HashSet<MouseButton>, | |||||
} | } | ||||
impl State { | impl State { | ||||
pub fn key_state(&self, code: VirtualKeyCode) -> bool { | |||||
self.key_states.contains(&KeyState::KeyCode(code)) | |||||
pub fn key_state<'a, I>(&self, codes: I) -> bool | |||||
where | |||||
I: IntoIterator<Item = &'a VirtualKeyCode>, | |||||
{ | |||||
for code in codes.into_iter() { | |||||
if self.key_states.contains(code) { | |||||
return true; | |||||
} | |||||
} | |||||
false | |||||
} | } | ||||
pub fn button_state(&self, button: MouseButton) -> bool { | |||||
self.key_states.contains(&KeyState::MouseButton(button)) | |||||
pub fn button_state<'a, I>(&self, buttons: I) -> bool | |||||
where | |||||
I: IntoIterator<Item = &'a MouseButton>, | |||||
{ | |||||
for button in buttons.into_iter() { | |||||
if self.button_states.contains(button) { | |||||
return true; | |||||
} | |||||
} | |||||
false | |||||
} | } | ||||
pub fn set_key_state(&mut self, code: VirtualKeyCode, value: bool) { | pub fn set_key_state(&mut self, code: VirtualKeyCode, value: bool) { | ||||
if value { | if value { | ||||
self.key_states.insert(KeyState::KeyCode(code)); | |||||
self.key_states.insert(code); | |||||
} else { | } else { | ||||
self.key_states.remove(&KeyState::KeyCode(code)); | |||||
self.key_states.remove(&code); | |||||
} | } | ||||
} | } | ||||
pub fn set_button_state(&mut self, button: MouseButton, value: bool) { | pub fn set_button_state(&mut self, button: MouseButton, value: bool) { | ||||
if value { | if value { | ||||
self.key_states.insert(KeyState::MouseButton(button)); | |||||
self.button_states.insert(button); | |||||
} else { | } else { | ||||
self.key_states.remove(&KeyState::MouseButton(button)); | |||||
self.button_states.remove(&button); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -3,7 +3,8 @@ use std::io::Error as IoError; | |||||
use glc::error::Error as GlcError; | use glc::error::Error as GlcError; | ||||
use glutin::{ContextError as GlutinContextError, CreationError as GlutinCreationError}; | use glutin::{ContextError as GlutinContextError, CreationError as GlutinCreationError}; | ||||
use glyph_brush::ab_glyph::InvalidFont; | use glyph_brush::ab_glyph::InvalidFont; | ||||
use serde_yaml::Error as YmlError; | |||||
use serde_json::Error as JsonError; | |||||
use serde_yaml::Error as YamlError; | |||||
use thiserror::Error; | use thiserror::Error; | ||||
use vfs::VfsError; | use vfs::VfsError; | ||||
use vfs_zip::Error as VfsZipError; | use vfs_zip::Error as VfsZipError; | ||||
@@ -19,8 +20,11 @@ pub enum Error { | |||||
#[error("VFS ZIP Error: {0}")] | #[error("VFS ZIP Error: {0}")] | ||||
VfsZipError(VfsZipError), | VfsZipError(VfsZipError), | ||||
#[error("YML Error: {0}")] | |||||
YmlError(YmlError), | |||||
#[error("JSON Error: {0}")] | |||||
JsonError(JsonError), | |||||
#[error("YAML Error: {0}")] | |||||
YamlError(YamlError), | |||||
#[error("GLC Error: {0}")] | #[error("GLC Error: {0}")] | ||||
GlcError(GlcError), | GlcError(GlcError), | ||||
@@ -65,9 +69,15 @@ impl From<VfsZipError> for Error { | |||||
} | } | ||||
} | } | ||||
impl From<YmlError> for Error { | |||||
fn from(err: YmlError) -> Self { | |||||
Self::YmlError(err) | |||||
impl From<JsonError> for Error { | |||||
fn from(err: JsonError) -> Self { | |||||
Self::JsonError(err) | |||||
} | |||||
} | |||||
impl From<YamlError> for Error { | |||||
fn from(err: YamlError) -> Self { | |||||
Self::YamlError(err) | |||||
} | } | ||||
} | } | ||||
@@ -35,7 +35,7 @@ pub fn init(vfs: &Vfs) { | |||||
fn load_from_file(vfs: &Vfs) -> Result<Config, Error> { | fn load_from_file(vfs: &Vfs) -> Result<Config, Error> { | ||||
let mut config = String::default(); | let mut config = String::default(); | ||||
vfs.join("resources/log4rs.yml")? | |||||
vfs.join("log4rs.yml")? | |||||
.open_file()? | .open_file()? | ||||
.read_to_string(&mut config)?; | .read_to_string(&mut config)?; | ||||