diff --git a/.gitignore b/.gitignore index f5e086e..55489d5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # Generated by Cargo # will have compiled files and executables -/target/ +/target # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock diff --git a/Cargo.toml b/Cargo.toml index 8f566f0..9d275f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,23 +19,23 @@ default = ["opengl"] opengl = ["gfx_device_gl", "gfx_window_glutin", "glutin"] [build-dependencies] -includedir_codegen = "0.3" +includedir_codegen = "0.5" [dependencies] arrayvec = "0.4" bitflags = "1" -cgmath = { version = "0.15", features = ["mint"] } +cgmath = { version = "0.16", features = ["mint"] } derivative = "1.0" froggy = "0.4.4" -genmesh = "0.5" +genmesh = "0.6" gfx = "0.17.1" gfx_glyph = "0.13" gltf = { features = ["names", "utils", "import"], optional = true, version = "0.11.1" } -image = "0.18" -includedir = "0.3" -itertools = "0.7" +image = "0.20" +includedir = "0.5" +itertools = "0.8" log = "0.4" -obj = { version = "0.8.1", features = ["genmesh"] } +obj = { version = "0.9", features = ["genmesh"] } phf = "0.7.12" quick-error = "1.2" rodio = "0.8" @@ -44,13 +44,13 @@ vec_map = "0.8" # OpenGL gfx_device_gl = { version = "0.15", optional = true } -gfx_window_glutin = { version = "0.20", optional = true } -glutin = { version = "0.12", optional = true } +gfx_window_glutin = { version = "0.28", optional = true } +glutin = { version = "0.19", optional = true } [dev-dependencies] -env_logger = "0.5" +env_logger = "0.6" notify = "4" -rand = "0.3" +rand = "0.6" [[example]] name = "lights" diff --git a/examples/aviator/sky.rs b/examples/aviator/sky.rs index 5c5a114..3da0ba7 100644 --- a/examples/aviator/sky.rs +++ b/examples/aviator/sky.rs @@ -26,13 +26,13 @@ impl Sky { let template = factory.mesh(geo, material.clone()); for i in 0i32 .. rng.gen_range(3, 6) { let m = factory.mesh_instance(&template); - let rot: cgmath::Quaternion = rng.gen(); + let rot = cgmath::Quaternion::::new(rng.gen(), rng.gen(), rng.gen(), rng.gen()); let q = rot.normalize(); m.set_transform( [ i as f32 * 15.0, - rng.next_f32() * 10.0, - rng.next_f32() * 10.0, + rng.gen::() * 10.0, + rng.gen::() * 10.0, ], q, rng.gen_range(0.1, 1.0), diff --git a/src/geometry.rs b/src/geometry.rs index 1372910..fd59c6d 100644 --- a/src/geometry.rs +++ b/src/geometry.rs @@ -158,7 +158,7 @@ impl Geometry { ) -> Self { Self::generate( generators::Plane::new(), - |GenVertex { pos, .. }| [pos[0] * 0.5 * width, pos[1] * 0.5 * height, 0.0].into(), + |GenVertex { pos, .. }| [pos.x * 0.5 * width, pos.y * 0.5 * height, 0.0].into(), |v| v.normal.into(), ) } @@ -188,9 +188,9 @@ impl Geometry { generators::Cube::new(), |GenVertex { pos, .. }| { [ - pos[0] * 0.5 * width, - pos[1] * 0.5 * height, - pos[2] * 0.5 * depth, + pos.x * 0.5 * width, + pos.y * 0.5 * height, + pos.z * 0.5 * depth, ].into() }, |v| v.normal.into(), @@ -230,10 +230,10 @@ impl Geometry { generators::Cylinder::new(radius_segments), //Three.js has height along the Y axis for some reason |GenVertex { pos, .. }| { - let scale = (pos[2] + 1.0) * 0.5 * radius_top + (1.0 - pos[2]) * 0.5 * radius_bottom; - [pos[1] * scale, pos[2] * 0.5 * height, pos[0] * scale].into() + let scale = (pos.z + 1.0) * 0.5 * radius_top + (1.0 - pos.z) * 0.5 * radius_bottom; + [pos.y * scale, pos.z * 0.5 * height, pos.x * scale].into() }, - |GenVertex { normal, .. }| [normal[1], normal[2], normal[0]].into(), + |GenVertex { normal, .. }| [normal.y, normal.z, normal.x].into(), ) } @@ -257,8 +257,8 @@ impl Geometry { meridional_segments: usize, ) -> Self { Self::generate( - generators::SphereUV::new(equatorial_segments, meridional_segments), - |GenVertex { pos, .. }| [pos[0] * radius, pos[1] * radius, pos[2] * radius].into(), + generators::SphereUv::new(equatorial_segments, meridional_segments), + |GenVertex { pos, .. }| [pos.x * radius, pos.y * radius, pos.z * radius].into(), |v| v.normal.into(), ) } diff --git a/src/input/mod.rs b/src/input/mod.rs index 07fa690..86497df 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -245,7 +245,7 @@ impl Input { ) { self.delta.mouse_wheel.push(match delta { MouseScrollDelta::LineDelta(_, y) => y * PIXELS_PER_LINE, - MouseScrollDelta::PixelDelta(_, y) => y, + MouseScrollDelta::PixelDelta(delta) => delta.y as f32, }); } diff --git a/src/lib.rs b/src/lib.rs index 450af64..9850ef2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -358,4 +358,4 @@ pub use texture::{CubeMap, CubeMapPath, FilterMethod, Sampler, Texture, WrapMode #[cfg(feature = "opengl")] #[doc(inline)] -pub use window::{CursorState, Window}; +pub use window::Window; diff --git a/src/render/mod.rs b/src/render/mod.rs index e486010..ea10b6c 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -526,7 +526,8 @@ pub struct Renderer { map_default: Texture<[f32; 4]>, shadow_default: Texture, debug_quads: froggy::Storage, - size: (u32, u32), + size: glutin::dpi::LogicalSize, + dpi: f64, font_cache: HashMap, instance_cache: HashMap, /// `ShadowType` of this `Renderer`. @@ -543,7 +544,7 @@ impl Renderer { ) -> (Self, glutin::GlWindow, Factory) { use gfx::texture as t; - let (window, device, mut gl_factory, out_color, out_depth) = gfx_window_glutin::init(builder, context, event_loop); + let (window, device, mut gl_factory, out_color, out_depth) = gfx_window_glutin::init(builder, context, event_loop).unwrap(); let (_, srv_white) = gl_factory .create_texture_immutable::( t::Kind::D2(1, 1, t::AaMode::Single), @@ -634,6 +635,7 @@ impl Renderer { debug_quads: froggy::Storage::new(), font_cache: HashMap::new(), size: window.get_inner_size().unwrap(), + dpi: window.get_hidpi_factor(), }; let factory = Factory::new(gl_factory); (renderer, window, factory) @@ -650,12 +652,11 @@ impl Renderer { pub(crate) fn resize( &mut self, window: &glutin::GlWindow, + size: glutin::dpi::LogicalSize, ) { - let size = window.get_inner_size().unwrap(); - // skip updating view and self size if some // of the sides equals to zero (fixes crash on minimize on Windows machines) - if size.0 == 0 || size.1 == 0 { + if size.width == 0.0 || size.height == 0.0 { return; } @@ -663,9 +664,18 @@ impl Renderer { gfx_window_glutin::update_views(window, &mut self.out_color, &mut self.out_depth); } + pub(crate) fn dpi_change( + &mut self, + window: &glutin::GlWindow, + dpi: f64, + ) { + self.dpi = dpi; + gfx_window_glutin::update_views(window, &mut self.out_color, &mut self.out_depth); + } + /// Returns current viewport aspect ratio, i.e. width / height. pub fn aspect_ratio(&self) -> f32 { - self.size.0 as f32 / self.size.1 as f32 + self.size.to_physical(self.dpi).width as f32 / self.size.to_physical(self.dpi).height as f32 } /// Map screen pixel coordinates to Normalized Display Coordinates. @@ -677,8 +687,8 @@ impl Renderer { ) -> mint::Point2 { let point = point.into(); mint::Point2 { - x: 2.0 * point.x / self.size.0 as f32 - 1.0, - y: 1.0 - 2.0 * point.y / self.size.1 as f32, + x: 2.0 * point.x / self.size.to_physical(self.dpi).width as f32 - 1.0, + y: 1.0 - 2.0 * point.y / self.size.to_physical(self.dpi).height as f32, } } @@ -1113,12 +1123,12 @@ impl Renderer { if quad.pos[0] >= 0 { quad.pos[0] } else { - self.size.0 as i32 + quad.pos[0] - quad.size[0] + self.size.to_physical(self.dpi).width as i32 + quad.pos[0] - quad.size[0] }, if quad.pos[1] >= 0 { quad.pos[1] } else { - self.size.1 as i32 + quad.pos[1] - quad.size[1] + self.size.to_physical(self.dpi).height as i32 + quad.pos[1] - quad.size[1] }, ]; let p0 = self.map_to_ndc([pos[0] as f32, pos[1] as f32]); diff --git a/src/window.rs b/src/window.rs index 6364101..88e523d 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,7 +1,6 @@ //! Primitives for creating and controlling [`Window`](struct.Window.html). use glutin; -use glutin::GlContext; use mint; use render; @@ -12,8 +11,6 @@ use render::Renderer; use scene::Scene; use std::path::PathBuf; -pub use glutin::CursorState; - /// `Window` is the core entity of every `three-rs` application. /// /// It provides [user input](struct.Window.html#method.update), @@ -21,6 +18,7 @@ pub use glutin::CursorState; pub struct Window { event_loop: glutin::EventsLoop, window: glutin::GlWindow, + dpi: f64, /// See [`Input`](struct.Input.html). pub input: Input, /// See [`Renderer`](struct.Renderer.html). @@ -38,7 +36,7 @@ pub struct Window { /// Builder for creating new [`Window`](struct.Window.html) with desired parameters. #[derive(Debug, Clone)] pub struct Builder { - dimensions: (u32, u32), + dimensions: glutin::dpi::LogicalSize, fullscreen: bool, multisampling: u16, shader_directory: Option, @@ -47,13 +45,15 @@ pub struct Builder { } impl Builder { - /// Set the size of the viewport (the resolution) in pixels. Defaults to 1024x768. + /// Set the size of the viewport (the resolution) in logical pixels. + /// That is the dpi setting affects the amount of pixels used but the window will + /// take up the same amount of space regardless of dpi. Defaults to 1024x768. pub fn dimensions( &mut self, - width: u32, - height: u32, + width: f64, + height: f64, ) -> &mut Self { - self.dimensions = (width, height); + self.dimensions = glutin::dpi::LogicalSize::new(width, height); self } @@ -105,7 +105,7 @@ impl Builder { let builder = glutin::WindowBuilder::new() .with_fullscreen(monitor_id) - .with_dimensions(self.dimensions.0, self.dimensions.1) + .with_dimensions(self.dimensions) .with_title(self.title.clone()); let context = glutin::ContextBuilder::new() @@ -146,10 +146,12 @@ impl Builder { } let (renderer, window, mut factory) = Renderer::new(builder, context, &event_loop, &source_set); + let dpi = window.get_hidpi_factor(); let scene = factory.scene(); Window { event_loop, window, + dpi, input: Input::new(), renderer, factory, @@ -168,7 +170,7 @@ impl Window { /// Create new `Builder` with standard parameters. pub fn builder>(title: T) -> Builder { Builder { - dimensions: (1024, 768), + dimensions: glutin::dpi::LogicalSize::new(1024.0, 768.0), fullscreen: false, multisampling: 0, shader_directory: None, @@ -188,15 +190,17 @@ impl Window { self.window.swap_buffers().unwrap(); let window = &self.window; + let dpi = self.dpi; self.event_loop.poll_events(|event| { - use glutin::WindowEvent::{Closed, Focused, KeyboardInput, MouseInput, CursorMoved, MouseWheel, Resized}; + use glutin::WindowEvent; match event { glutin::Event::WindowEvent { event, .. } => match event { - Resized(..) => renderer.resize(window), - Focused(state) => input.window_focus(state), - Closed => running = false, - KeyboardInput { + WindowEvent::Resized(size) => renderer.resize(window, size), + WindowEvent::HiDpiFactorChanged(dpi) => renderer.dpi_change(window, dpi), + WindowEvent::Focused(state) => input.window_focus(state), + WindowEvent::CloseRequested | WindowEvent::Destroyed => running = false, + WindowEvent::KeyboardInput { input: glutin::KeyboardInput { state, virtual_keycode: Some(keycode), @@ -204,14 +208,12 @@ impl Window { }, .. } => input.keyboard_input(state, keycode), - MouseInput { state, button, .. } => input.mouse_input(state, button), - CursorMoved { - position: (x, y), .. - } => input.mouse_moved( - [x as f32, y as f32].into(), - renderer.map_to_ndc([x as f32, y as f32]), - ), - MouseWheel { delta, .. } => input.mouse_wheel_input(delta), + WindowEvent::MouseInput { state, button, .. } => input.mouse_input(state, button), + WindowEvent::CursorMoved { position, .. } => { + let pos = position.to_physical(dpi); + input.mouse_moved([pos.x as f32, pos.y as f32].into(), renderer.map_to_ndc([pos.x as f32, pos.y as f32])); + } + WindowEvent::MouseWheel { delta, .. } => input.mouse_wheel_input(delta), _ => {} }, glutin::Event::DeviceEvent { event, .. } => match event { @@ -239,24 +241,9 @@ impl Window { pub fn size(&self) -> mint::Vector2 { let size = self.window .get_inner_size() - .expect("Can't get window size"); - [size.0 as f32, size.1 as f32].into() - } - - /// Sets how the cursor should be handled. - /// - /// See the documentation for [`CursorState`] for the possible cursor states. - /// - /// Note that if you use [`CursorState::Grab`], you should use [`Input::mouse_delta_raw`] for - /// detecting mouse movement, as [`Input::mouse_delta`] will only report movement of the cursor - /// within the window. - /// - /// [`CursorState`]: enum.CursorState.html - /// [`CursorState::Grab`]: enum.CursorState.html#variant.Grab - /// [`Input::mouse_delta_raw`]: struct.Input.html#method.mouse_delta_raw - /// [`Input::mouse_delta`]: struct.Input.html#method.mouse_delta_raw - pub fn set_cursor_state(&self, state: CursorState) { - let _ = self.window.set_cursor_state(state); + .expect("Can't get window size") + .to_physical(self.dpi); + [size.width as f32, size.height as f32].into() } /// Returns underlaying `glutin::GlWindow`.