Skip to content
Permalink
Browse files

Resolve #587.

I'm sick of this and want to just move on with life.  Any other
issue with hidpi anything is going to be closed as "dependency bug"
until winit eventually switches to physical coordinates by default,
which admittedly they're probably going to.

As a consequence, Apple platforms are no longer supported.
See https://drewdevault.com/2017/10/26/Fuck-you-nvidia.html but
search-and-replace NVidia with Apple.  It's the exact same sort
of problem and I'm done with it.

I'm sorry.
  • Loading branch information...
icefoxen committed Apr 23, 2019
1 parent d5a33c3 commit 2f02c72cf31401a1e6ab55edc745f6227c99fb67
Showing with 29 additions and 130 deletions.
  1. +4 −3 README.md
  2. +1 −15 docs/BuildingForEveryPlatform.md
  3. +0 −2 examples/02_hello_world.rs
  4. +1 −1 examples/eventloop.rs
  5. +0 −20 src/conf.rs
  6. +7 −15 src/context.rs
  7. +3 −7 src/event.rs
  8. +11 −55 src/graphics/context.rs
  9. +0 −1 src/graphics/image.rs
  10. +2 −11 src/graphics/mod.rs
@@ -50,9 +50,10 @@ your own libraries atop ggez.

## Supported platforms

* Fully supported: Windows, Linux, macOS
* Fully supported: Windows, Linux
* Work in progress: Web/WASM/Emscripten
* Not officially supported yet (but maybe you can help!): Android, iOS
* Not officially supported yet (but maybe you can help!): Android
* Will never officially support but might work anyway: Mac, iOS

For details, see [docs/BuildingForEveryPlatform.md](docs/BuildingForEveryPlatform.md)

@@ -153,7 +154,7 @@ ggez is built upon `winit` for windowing and events, `rodio` for sound,
and a 2D drawing engine implemented in `gfx` using the OpenGL backend
(which currently defaults to use OpenGL 3.2). It *should* be
entirely thread-safe outside of the basic event-handling loop, and
portable to Windows, Linux and Mac.
portable to Windows nad Linux.

ggez is Pure Rust(tm).

@@ -2,7 +2,7 @@

Greetings, one and all. Today we shall explore how to build and
deploy a `ggez` game for every possible platform. For platforms like
Linux and Mac it's pretty darn simple. For ones like Android it gets
Linux it's pretty darn simple. For ones like Android it gets
harder and you have to jump through hoops. The purpose of this is to
document the hoops and give you a cookbook on the best jumping methods
and trajectories. We will progress generally from the easiest to
@@ -77,16 +77,6 @@ TODO: Double-check this with 0.5

You should be able to just copy-paste the executable file and the `resources` directory to wherever you want.

# Mac

Should be able to just install Rust and run the game, same as the basic setup
instructions.

## Distributing

TODO: Fix this now that I have access to a mac.

???

# Windows

@@ -102,10 +92,6 @@ Just copy-paste the exe and resource files to the destination computer.

Not officially supported yet. ;_; See https://github.com/ggez/ggez/issues/70
# iOS
Not officially supported yet. ;_; See https://github.com/ggez/ggez/issues/70

# Web/wasm/emscripten
Not officially supported yet. ;_; See https://github.com/ggez/ggez/issues/71
@@ -78,8 +78,6 @@ pub fn main() -> GameResult {
let cb = ggez::ContextBuilder::new("helloworld", "ggez").add_resource_path(resource_dir);
let (ctx, event_loop) = &mut cb.build()?;

println!("HIDPI: {}", graphics::hidpi_factor(ctx));

let state = &mut MainState::new(ctx)?;
event::run(ctx, event_loop, state)
}
@@ -30,7 +30,7 @@ pub fn main() -> GameResult {
events_loop.poll_events(|event| {
// This tells `ggez` to update it's internal states, should the event require that.
// These include cursor position, view updating on resize, etc.
ctx.process_event(&event);
let event = ctx.process_event(event);
match event {
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => ggez::quit(ctx),
@@ -47,7 +47,6 @@ pub enum FullscreenType {
/// max_width: 0.0,
/// min_height: 0.0,
/// max_height: 0.0,
/// hidpi: false,
/// resizable: false,
/// }
/// # , WindowMode::default());}
@@ -81,19 +80,6 @@ pub struct WindowMode {
/// Maximum height for resizable windows; 0 means no limit
#[default = 0.0]
pub max_height: f32,
/// Whether or not to scale all "pixel" coordinates to deal with
/// high DPI screens.
///
/// A very good overview of this is available in
/// [the `winit` docs](https://docs.rs/winit/0.18.0/winit/dpi/index.html).
/// If this is false (the default), one pixel in ggez equates to one
/// physical pixel on the screen. If it is `true`, then ggez will
/// scale *all* pixel coordinates by the scaling factor returned by
/// [`graphics::get_hidpi_factor()`](../graphics/fn.get_hidpi_factor.html).
///
/// BUGGO: Currently unimplemented. hidpi is always forcefully ignored.
#[default = false]
pub hidpi: bool,
/// Whether or not the window is resizable
#[default = false]
pub resizable: bool,
@@ -144,12 +130,6 @@ impl WindowMode {
self.resizable = resizable;
self
}

/// Sets whether or not to allow hidpi.
pub fn hidpi(mut self, hidpi: bool) -> Self {
self.hidpi = hidpi;
self
}
}

/// A builder structure containing window settings
@@ -122,8 +122,7 @@ impl Context {
/// This also returns a new version of the `Event` that has been modified
/// for ggez's optional overriding of hidpi. For full discussion see
/// <https://github.com/tomaka/winit/issues/591#issuecomment-403096230>.
pub fn process_event(&mut self, event: &winit::Event) -> winit::Event {
let event = self.gfx_context.hack_event_hidpi(event);
pub fn process_event(&mut self, event: winit::Event) -> winit::Event {
match event.clone() {
winit_event::Event::WindowEvent { event, .. } => match event {
winit_event::WindowEvent::Resized(_) => {
@@ -133,11 +132,9 @@ impl Context {
position: logical_position,
..
} => {
let actual_position =
logical_position.to_physical(self.gfx_context.hidpi_factor as f64);
self.mouse_context.set_last_position(Point2::new(
actual_position.x as f32,
actual_position.y as f32,
logical_position.x as f32,
logical_position.y as f32,
));
}
winit_event::WindowEvent::MouseInput { button, state, .. } => {
@@ -165,21 +162,16 @@ impl Context {
.set_modifiers(keyboard::KeyMods::from(modifiers));
self.keyboard_context.set_key(keycode, pressed);
}
winit_event::WindowEvent::HiDpiFactorChanged(new_hidpi_factor) => {
// TODO: Test how this actually works... does winit's hidpi factor change and
// we have to account for it here, or does winit just tell us when something
// changes?
// Well this is actually really hard to test without the right hardware, soooo,
// I guess I'll just leave it as this for now.
self.gfx_context.hidpi_factor = new_hidpi_factor as f32;
winit_event::WindowEvent::HiDpiFactorChanged(_) => {
// Nope.
}
_ => (),
},
winit_event::Event::DeviceEvent { event, .. } => match event {
winit_event::DeviceEvent::MouseMotion { delta: (x, y) } => {
self.mouse_context.set_last_delta(Point2::new(
x as f32 * self.gfx_context.hidpi_factor,
y as f32 * self.gfx_context.hidpi_factor,
x as f32,
y as f32,
));
}
_ => (),
@@ -165,19 +165,15 @@ where
while ctx.continuing {
ctx.timer_context.tick();
events_loop.poll_events(|event| {
let event = ctx.process_event(&event);
let event = ctx.process_event(event);
match event {
Event::WindowEvent { event, .. } => match event {
WindowEvent::Resized(logical_size) => {
// TODO: HECKIN HIDPI is probably going to screw up every time anyone tries
// to handle resizes in their own event loop now.
let actual_size =
logical_size.to_physical(ctx.gfx_context.hidpi_factor as f64);
// let actual_size = logical_size;
state.resize_event(
ctx,
actual_size.width as f32,
actual_size.height as f32,
logical_size.width as f32,
logical_size.height as f32,
);
}
WindowEvent::CloseRequested => {
@@ -31,7 +31,6 @@ where
color_format: gfx::format::Format,
depth_format: gfx::format::Format,
srgb: bool,
pub(crate) hidpi_factor: f32,

pub(crate) backend_spec: B,
pub(crate) window: glutin::WindowedContext,
@@ -98,25 +97,6 @@ impl GraphicsContextGeneric<GlBackendSpec> {
gfx::format::ChannelType::Unorm,
);

// MONGLE HIDPI
// See https://docs.rs/winit/0.18.0/winit/dpi/index.html for
// an excellent explaination of how this works.
// See https://github.com/ggez/ggez/issues/587 for an entry point
// into why this behavior is now a personal nemesis of mine.
//
// TODO: We assume that the hidpi factor we use is always the hidpi
// factor of the primary monitor. Depending on how clever winit
// tries to be, this might result in AWFUL things happening if a window
// is dragged from a hidpi to normal monitor and back...
// If so we might have to do cruel things in our resize event handler.
let hidpi_factor = events_loop.get_primary_monitor().get_hidpi_factor() as f32;
// Subvert winit's hidpi and make it so the window is created
// with the physical size the user asks for.
let subverted_size = glutin::dpi::LogicalSize::new(
(window_mode.width / hidpi_factor) as f64,
(window_mode.height / hidpi_factor) as f64,
);

// WINDOW SETUP
let gl_builder = glutin::ContextBuilder::new()
.with_gl(glutin::GlRequest::Specific(
@@ -129,9 +109,10 @@ impl GraphicsContextGeneric<GlBackendSpec> {
.with_pixel_format(24, 8)
.with_vsync(window_setup.vsync);

let window_size = dpi::LogicalSize::from((window_mode.width as f64, window_mode.height as f64));
let mut window_builder = winit::WindowBuilder::new()
.with_title(window_setup.title.clone())
.with_dimensions(subverted_size)
.with_dimensions(window_size)
.with_transparency(window_setup.transparent)
.with_resizable(window_mode.resizable);

@@ -165,6 +146,7 @@ impl GraphicsContextGeneric<GlBackendSpec> {
} = window
.get_inner_size()
.ok_or_else(|| GameError::VideoError("Window doesn't exist!".to_owned()))?;
let hidpi_factor = window.get_hidpi_factor();
debug!(
"Window created, desired size {}x{}, hidpi factor {}.",
window_mode.width, window_mode.height, hidpi_factor
@@ -289,7 +271,6 @@ impl GraphicsContextGeneric<GlBackendSpec> {
color_format,
depth_format,
srgb,
hidpi_factor,

backend_spec: backend,
window,
@@ -533,8 +514,8 @@ where
// TODO: find out if single-dimension constraints are possible.
let min_dimensions = if mode.min_width > 0.0 && mode.min_height > 0.0 {
Some(dpi::LogicalSize {
width: (mode.min_width / self.hidpi_factor).into(),
height: (mode.min_height / self.hidpi_factor).into(),
width: mode.min_width as f64,
height: mode.min_height as f64,
})
} else {
None
@@ -543,8 +524,8 @@ where

let max_dimensions = if mode.max_width > 0.0 && mode.max_height > 0.0 {
Some(dpi::LogicalSize {
width: (mode.max_width / self.hidpi_factor).into(),
height: (mode.max_height / self.hidpi_factor).into(),
width: mode.max_width as f64,
height: mode.max_height as f64,
})
} else {
None
@@ -557,15 +538,15 @@ where
window.set_fullscreen(None);
window.set_decorations(!mode.borderless);
window.set_inner_size(dpi::LogicalSize {
width: (mode.width / self.hidpi_factor).into(),
height: (mode.height / self.hidpi_factor).into(),
width: mode.width as f64,
height: mode.height as f64,
});
}
FullscreenType::True => {
window.set_fullscreen(Some(monitor));
window.set_inner_size(dpi::LogicalSize {
width: (mode.width / self.hidpi_factor).into(),
height: (mode.height / self.hidpi_factor).into(),
width: mode.width as f64,
height: mode.height as f64,
});
}
FullscreenType::Desktop => {
@@ -619,29 +600,4 @@ where
false
}
}

/// This is a filthy hack allow users to override hidpi
/// scaling if they want to. Everything that winit touches
/// is scaled by the hidpi factor that it uses, such as monitor
/// resolutions and mouse positions. If you want display-independent
/// scaling this is Good, if you want pixel-perfect scaling this
/// is Bad. We are currently operating on the assumption that you want
/// pixel-perfect scaling.
///
/// See <https://github.com/tomaka/winit/issues/591#issuecomment-403096230>
/// and related issues for fuller discussion.
/// TODO: Unimplemented yet because I don't know the best way to fix hidpi. :|
pub(crate) fn hack_event_hidpi(&self, event: &winit::Event) -> winit::Event {
event.clone()
}

// TODO: Heckin' figure out DPI.
// /// Takes a coordinate in winit's Logical scale (aka everything we touch)
// /// and turns it into the equivalent in PhysicalScale, allowing us to
// /// override the DPI if necessary.
// pub(crate) fn to_physical_dpi(&self, x: f32, y: f32) -> (f32, f32) {
// let logical = dpi::LogicalPosition::new(f64::from(x), f64::from(y));
// let physical = dpi::PhysicalPosition::from_logical(logical, self.hidpi_factor.into());
// (physical.x as f32, physical.y as f32)
// }
}
@@ -329,7 +329,6 @@ impl Drawable for Image {
let src_height = param.src.h;
// We have to mess with the scale to make everything
// be its-unit-size-in-pixels.
use nalgebra;
let real_scale = nalgebra::Vector2::new(
param.scale.x * src_width * f32::from(self.width),
param.scale.y * src_height * f32::from(self.height),
@@ -244,7 +244,6 @@ impl BackendSpec for GlBackendSpec {
),
glutin::CreationError,
> {
use gfx_window_glutin;
gfx_window_glutin::init_raw(
window_builder,
gl_builder,
@@ -284,7 +283,6 @@ impl BackendSpec for GlBackendSpec {
// gfx_window_glutin::update_views()
let dim = color_view.get_dimensions();
assert_eq!(dim, depth_view.get_dimensions());
use gfx_window_glutin;
if let Some((cv, dv)) =
gfx_window_glutin::update_views_raw(window, dim, color_format, depth_format)
{
@@ -880,25 +878,18 @@ pub fn size(context: &Context) -> (f32, f32) {
let gfx = &context.gfx_context;
gfx.window
.get_outer_size()
.map(|logical_size| logical_size.to_physical(context.gfx_context.hidpi_factor as f64))
.map(|physical_size| (physical_size.width as f32, physical_size.height as f32))
.map(|logical_size| (logical_size.width as f32, logical_size.height as f32))
.unwrap_or((0.0, 0.0))
}

/// Returns the hidpi pixel scaling factor that the operating
/// system says that ggez should be using.
pub fn hidpi_factor(context: &Context) -> f32 {
context.gfx_context.hidpi_factor
}

/// Returns the size of the window's underlying drawable in pixels as (width, height).
/// Returns zeros if window doesn't exist.
pub fn drawable_size(context: &Context) -> (f32, f32) {
let gfx = &context.gfx_context;
gfx.window
.get_inner_size()
.map(|logical_size| logical_size.to_physical(context.gfx_context.hidpi_factor as f64))
.map(|physical_size| (physical_size.width as f32, physical_size.height as f32))
.map(|logical_size| (logical_size.width as f32, logical_size.height as f32))
.unwrap_or((0.0, 0.0))
}

0 comments on commit 2f02c72

Please sign in to comment.
You can’t perform that action at this time.