Factor the SDL code out in preparation for other ports
This commit is contained in:
parent
25558c2177
commit
a74c0abbec
|
@ -161,7 +161,11 @@ dependencies = [
|
|||
name = "demo"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pathfinder_demo 0.1.0",
|
||||
"pathfinder_geometry 0.3.0",
|
||||
"sdl2 0.32.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sdl2-sys 0.32.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -514,11 +518,10 @@ dependencies = [
|
|||
"pathfinder_gl 0.1.0",
|
||||
"pathfinder_gpu 0.1.0",
|
||||
"pathfinder_renderer 0.1.0",
|
||||
"pathfinder_simd 0.3.0",
|
||||
"pathfinder_svg 0.1.0",
|
||||
"pathfinder_ui 0.1.0",
|
||||
"rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sdl2 0.32.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sdl2-sys 0.32.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -694,8 +697,8 @@ dependencies = [
|
|||
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -758,7 +761,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rand_os"
|
||||
version = "0.1.2"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -771,11 +774,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rand_pcg"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -861,14 +864,6 @@ dependencies = [
|
|||
"xmlparser 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "0.2.7"
|
||||
|
@ -915,19 +910,6 @@ dependencies = [
|
|||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.88"
|
||||
|
@ -1221,8 +1203,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
|
||||
"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
|
||||
"checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832"
|
||||
"checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d"
|
||||
"checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05"
|
||||
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
|
||||
"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
|
||||
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
|
||||
"checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473"
|
||||
"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356"
|
||||
|
@ -1233,7 +1215,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f"
|
||||
"checksum regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2f35eedad5295fdf00a63d7d4b238135723f92b434ec06774dad15c7ab0861"
|
||||
"checksum roxmltree 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "02660467d0c2da1b6276042501aee6e15ec5b8ff59423243f185b294cd53acf3"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
|
||||
"checksum safe-transmute 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9604873ffe1980bc1f179103704a65c8aca141c248d9e52b7af95ff10578166e"
|
||||
"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9"
|
||||
|
@ -1241,8 +1222,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
|
||||
"checksum sdl2 0.32.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0ebf85f207d42e4da59fa31fff977be5ff0b224873506c4bd70cc1c94b331593"
|
||||
"checksum sdl2-sys 0.32.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e82803e85c2e6178d28886cef25b2c53afc2eecaeff739f2247f23ed3352e6c1"
|
||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)" = "9f301d728f2b94c9a7691c90f07b0b4e8a4517181d9461be94c04bddeb4bd850"
|
||||
"checksum serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)" = "beed18e6f5175aef3ba670e57c60ef3b1b74d250d962a26604bff4c80e970dd4"
|
||||
"checksum serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "27dce848e7467aa0e2fcaf0a413641499c0b745452aaca1194d24dedde9e13c9"
|
||||
|
|
|
@ -10,8 +10,6 @@ gl = "0.6"
|
|||
jemallocator = "0.1"
|
||||
nfd = "0.0.4"
|
||||
rayon = "1.0"
|
||||
sdl2 = "0.32"
|
||||
sdl2-sys = "0.32"
|
||||
usvg = "0.4"
|
||||
|
||||
[dependencies.image]
|
||||
|
@ -31,6 +29,9 @@ path = "../../gpu"
|
|||
[dependencies.pathfinder_renderer]
|
||||
path = "../../renderer"
|
||||
|
||||
[dependencies.pathfinder_simd]
|
||||
path = "../../simd"
|
||||
|
||||
[dependencies.pathfinder_svg]
|
||||
path = "../../svg"
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
use crate::device::{GroundLineVertexArray, GroundProgram, GroundSolidVertexArray};
|
||||
use crate::ui::{DemoUI, UIAction};
|
||||
use crate::window::{Event, Keycode, Window};
|
||||
use clap::{App, Arg};
|
||||
use image::ColorType;
|
||||
use jemallocator;
|
||||
|
@ -32,17 +33,11 @@ use pathfinder_renderer::z_buffer::ZBuffer;
|
|||
use pathfinder_svg::BuiltSVG;
|
||||
use pathfinder_ui::UIEvent;
|
||||
use rayon::ThreadPoolBuilder;
|
||||
use sdl2::EventPump;
|
||||
use sdl2::event::{Event, WindowEvent};
|
||||
use sdl2::keyboard::Keycode;
|
||||
use sdl2::video::{GLContext, GLProfile, Window};
|
||||
use sdl2_sys::{SDL_Event, SDL_UserEvent};
|
||||
use std::f32::consts::FRAC_PI_4;
|
||||
use std::mem;
|
||||
use std::panic;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process;
|
||||
use std::ptr;
|
||||
use std::sync::mpsc::{self, Receiver, Sender};
|
||||
use std::thread;
|
||||
use std::time::{Duration, Instant};
|
||||
|
@ -78,14 +73,13 @@ const MESSAGE_TIMEOUT_SECS: u64 = 5;
|
|||
|
||||
pub const GRIDLINE_COUNT: u8 = 10;
|
||||
|
||||
pub mod window;
|
||||
|
||||
mod device;
|
||||
mod ui;
|
||||
|
||||
pub struct DemoApp {
|
||||
window: Window,
|
||||
sdl_event_pump: EventPump,
|
||||
#[allow(dead_code)]
|
||||
gl_context: GLContext,
|
||||
pub struct DemoApp<W> where W: Window {
|
||||
window: W,
|
||||
|
||||
scale_factor: f32,
|
||||
|
||||
|
@ -111,40 +105,18 @@ pub struct DemoApp {
|
|||
ground_line_vertex_array: GroundLineVertexArray<GLDevice>,
|
||||
}
|
||||
|
||||
impl DemoApp {
|
||||
pub fn new() -> DemoApp {
|
||||
let sdl_context = sdl2::init().unwrap();
|
||||
let sdl_video = sdl_context.video().unwrap();
|
||||
let sdl_event = sdl_context.event().unwrap();
|
||||
|
||||
let gl_attributes = sdl_video.gl_attr();
|
||||
gl_attributes.set_context_profile(GLProfile::Core);
|
||||
gl_attributes.set_context_version(3, 3);
|
||||
gl_attributes.set_depth_size(24);
|
||||
gl_attributes.set_stencil_size(8);
|
||||
|
||||
let window =
|
||||
sdl_video.window("Pathfinder Demo", MAIN_FRAMEBUFFER_WIDTH, MAIN_FRAMEBUFFER_HEIGHT)
|
||||
.opengl()
|
||||
.resizable()
|
||||
.allow_highdpi()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let gl_context = window.gl_create_context().unwrap();
|
||||
gl::load_with(|name| sdl_video.gl_get_proc_address(name) as *const _);
|
||||
|
||||
let expire_message_event_id = unsafe { sdl_event.register_event().unwrap() };
|
||||
|
||||
let sdl_event_pump = sdl_context.event_pump().unwrap();
|
||||
impl<W> DemoApp<W> where W: Window {
|
||||
pub fn new() -> DemoApp<W> {
|
||||
let default_framebuffer_size = Point2DI32::new(MAIN_FRAMEBUFFER_WIDTH as i32,
|
||||
MAIN_FRAMEBUFFER_HEIGHT as i32);
|
||||
let window = W::new(default_framebuffer_size);
|
||||
let expire_message_event_id = window.create_user_event_id();
|
||||
|
||||
let device = GLDevice::new();
|
||||
let resources = Resources::locate();
|
||||
let options = Options::get(&resources);
|
||||
|
||||
let (window_width, _) = window.size();
|
||||
let (drawable_width, drawable_height) = window.drawable_size();
|
||||
let drawable_size = Point2DI32::new(drawable_width as i32, drawable_height as i32);
|
||||
let (window_size, drawable_size) = (window.size(), window.drawable_size());
|
||||
|
||||
let built_svg = load_scene(&options.input_path);
|
||||
let message = get_svg_building_message(&built_svg);
|
||||
|
@ -153,7 +125,7 @@ impl DemoApp {
|
|||
|
||||
let renderer = Renderer::new(device, &resources, drawable_size);
|
||||
let scene_thread_proxy = SceneThreadProxy::new(built_svg.scene, options.clone());
|
||||
update_drawable_size(&window, &scene_thread_proxy);
|
||||
scene_thread_proxy.set_drawable_size(window.drawable_size());
|
||||
|
||||
let camera = if options.three_d {
|
||||
Camera::new_3d(scene_view_box)
|
||||
|
@ -171,21 +143,12 @@ impl DemoApp {
|
|||
|
||||
let mut ui = DemoUI::new(&renderer.device, &resources, options);
|
||||
let mut message_epoch = 0;
|
||||
emit_message(&mut ui, &mut message_epoch, expire_message_event_id, message);
|
||||
|
||||
// Leak our SDL stuff. It'll last the entire duration of the process anyway, and it means
|
||||
// we don't have to deal with any nasty issues regarding synchronizing background threads
|
||||
// during shutdown.
|
||||
mem::forget(sdl_event);
|
||||
mem::forget(sdl_video);
|
||||
mem::forget(sdl_context);
|
||||
emit_message::<W>(&mut ui, &mut message_epoch, expire_message_event_id, message);
|
||||
|
||||
DemoApp {
|
||||
window,
|
||||
sdl_event_pump,
|
||||
gl_context,
|
||||
|
||||
scale_factor: drawable_width as f32 / window_width as f32,
|
||||
scale_factor: drawable_size.x() as f32 / window_size.x() as f32,
|
||||
|
||||
scene_view_box,
|
||||
scene_is_monochrome,
|
||||
|
@ -226,8 +189,7 @@ impl DemoApp {
|
|||
}
|
||||
|
||||
fn build_scene(&mut self) {
|
||||
let (drawable_width, drawable_height) = self.window.drawable_size();
|
||||
let drawable_size = Point2DI32::new(drawable_width as i32, drawable_height as i32);
|
||||
let drawable_size = self.window.drawable_size();
|
||||
|
||||
let render_transform = match self.camera {
|
||||
Camera::ThreeD { ref mut transform, ref mut velocity } => {
|
||||
|
@ -261,98 +223,96 @@ impl DemoApp {
|
|||
let mut ui_event = UIEvent::None;
|
||||
|
||||
if !self.dirty {
|
||||
self.events.push(self.sdl_event_pump.wait_event());
|
||||
self.events.push(self.window.get_event());
|
||||
} else {
|
||||
self.dirty = false;
|
||||
}
|
||||
|
||||
for event in self.sdl_event_pump.poll_iter() {
|
||||
while let Some(event) = self.window.try_get_event() {
|
||||
self.events.push(event);
|
||||
}
|
||||
|
||||
for event in self.events.drain(..) {
|
||||
match event {
|
||||
Event::Quit { .. } |
|
||||
Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
|
||||
Event::KeyDown(Keycode::Escape) => {
|
||||
self.exit = true;
|
||||
self.dirty = true;
|
||||
}
|
||||
Event::Window { win_event: WindowEvent::SizeChanged(..), .. } => {
|
||||
update_drawable_size(&self.window, &self.scene_thread_proxy);
|
||||
let drawable_size = current_drawable_size(&self.window);
|
||||
self.renderer.set_main_framebuffer_size(drawable_size);
|
||||
Event::WindowResized => {
|
||||
self.scene_thread_proxy.set_drawable_size(self.window.drawable_size());
|
||||
self.renderer.set_main_framebuffer_size(self.window.drawable_size());
|
||||
self.dirty = true;
|
||||
}
|
||||
Event::MouseButtonDown { x, y, .. } => {
|
||||
let point = Point2DI32::new(x, y).scale(self.scale_factor as i32);
|
||||
ui_event = UIEvent::MouseDown(point);
|
||||
Event::MouseDown(position) => {
|
||||
ui_event = UIEvent::MouseDown(position.scale(self.scale_factor as i32));
|
||||
}
|
||||
Event::MouseMotion { xrel, yrel, .. } if self.mouselook_enabled => {
|
||||
Event::MouseMoved { relative_position, .. } if self.mouselook_enabled => {
|
||||
if let Camera::ThreeD { ref mut transform, .. } = self.camera {
|
||||
transform.yaw += xrel as f32 * MOUSELOOK_ROTATION_SPEED;
|
||||
transform.pitch += yrel as f32 * MOUSELOOK_ROTATION_SPEED;
|
||||
let rotation = relative_position.to_f32().scale(MOUSELOOK_ROTATION_SPEED);
|
||||
transform.yaw += rotation.x();
|
||||
transform.pitch += rotation.y();
|
||||
self.dirty = true;
|
||||
}
|
||||
}
|
||||
Event::MouseMotion { x, y, xrel, yrel, mousestate, .. } if mousestate.left() => {
|
||||
let absolute_position = Point2DI32::new(x, y).scale(self.scale_factor as i32);
|
||||
let relative_position =
|
||||
Point2DI32::new(xrel, yrel).scale(self.scale_factor as i32);
|
||||
Event::MouseDragged { position, relative_position } => {
|
||||
let absolute_position = position.scale(self.scale_factor as i32);
|
||||
let relative_position = relative_position.scale(self.scale_factor as i32);
|
||||
ui_event = UIEvent::MouseDragged { absolute_position, relative_position };
|
||||
self.dirty = true;
|
||||
}
|
||||
Event::MultiGesture { d_dist, .. } => {
|
||||
Event::Zoom(d_dist) => {
|
||||
if let Camera::TwoD(ref mut transform) = self.camera {
|
||||
let position = get_mouse_position(&self.sdl_event_pump, self.scale_factor);
|
||||
let position = get_mouse_position(&self.window, self.scale_factor);
|
||||
*transform = transform.post_translate(-position);
|
||||
let scale_delta = 1.0 + d_dist * CAMERA_SCALE_SPEED_2D;
|
||||
*transform = transform.post_scale(Point2DF32::splat(scale_delta));
|
||||
*transform = transform.post_translate(position);
|
||||
}
|
||||
}
|
||||
Event::KeyDown { keycode: Some(Keycode::W), .. } => {
|
||||
Event::KeyDown(Keycode::Alphanumeric(b'w')) => {
|
||||
if let Camera::ThreeD { ref mut velocity, .. } = self.camera {
|
||||
let scale_factor = scale_factor_for_view_box(self.scene_view_box);
|
||||
velocity.set_z(-CAMERA_VELOCITY / scale_factor);
|
||||
self.dirty = true;
|
||||
}
|
||||
}
|
||||
Event::KeyDown { keycode: Some(Keycode::S), .. } => {
|
||||
Event::KeyDown(Keycode::Alphanumeric(b's')) => {
|
||||
if let Camera::ThreeD { ref mut velocity, .. } = self.camera {
|
||||
let scale_factor = scale_factor_for_view_box(self.scene_view_box);
|
||||
velocity.set_z(CAMERA_VELOCITY / scale_factor);
|
||||
self.dirty = true;
|
||||
}
|
||||
}
|
||||
Event::KeyDown { keycode: Some(Keycode::A), .. } => {
|
||||
Event::KeyDown(Keycode::Alphanumeric(b'a')) => {
|
||||
if let Camera::ThreeD { ref mut velocity, .. } = self.camera {
|
||||
let scale_factor = scale_factor_for_view_box(self.scene_view_box);
|
||||
velocity.set_x(-CAMERA_VELOCITY / scale_factor);
|
||||
self.dirty = true;
|
||||
}
|
||||
}
|
||||
Event::KeyDown { keycode: Some(Keycode::D), .. } => {
|
||||
Event::KeyDown(Keycode::Alphanumeric(b'd')) => {
|
||||
if let Camera::ThreeD { ref mut velocity, .. } = self.camera {
|
||||
let scale_factor = scale_factor_for_view_box(self.scene_view_box);
|
||||
velocity.set_x(CAMERA_VELOCITY / scale_factor);
|
||||
self.dirty = true;
|
||||
}
|
||||
}
|
||||
Event::KeyUp { keycode: Some(Keycode::W), .. } |
|
||||
Event::KeyUp { keycode: Some(Keycode::S), .. } => {
|
||||
Event::KeyUp(Keycode::Alphanumeric(b'w')) |
|
||||
Event::KeyUp(Keycode::Alphanumeric(b's')) => {
|
||||
if let Camera::ThreeD { ref mut velocity, .. } = self.camera {
|
||||
velocity.set_z(0.0);
|
||||
self.dirty = true;
|
||||
}
|
||||
}
|
||||
Event::KeyUp { keycode: Some(Keycode::A), .. } |
|
||||
Event::KeyUp { keycode: Some(Keycode::D), .. } => {
|
||||
Event::KeyUp(Keycode::Alphanumeric(b'a')) |
|
||||
Event::KeyUp(Keycode::Alphanumeric(b'd')) => {
|
||||
if let Camera::ThreeD { ref mut velocity, .. } = self.camera {
|
||||
velocity.set_x(0.0);
|
||||
self.dirty = true;
|
||||
}
|
||||
}
|
||||
Event::User { type_: event_id, code: expected_epoch, .. } if
|
||||
Event::User { message_type: event_id, message_data: expected_epoch } if
|
||||
event_id == self.expire_message_event_id &&
|
||||
expected_epoch as u32 == self.message_epoch => {
|
||||
self.ui.message = String::new();
|
||||
|
@ -390,7 +350,7 @@ impl DemoApp {
|
|||
}
|
||||
|
||||
self.renderer.debug_ui.ui.event = ui_event;
|
||||
self.renderer.debug_ui.ui.mouse_position = get_mouse_position(&self.sdl_event_pump,
|
||||
self.renderer.debug_ui.ui.mouse_position = get_mouse_position(&self.window,
|
||||
self.scale_factor);
|
||||
self.ui.show_text_effects = self.scene_is_monochrome;
|
||||
|
||||
|
@ -406,7 +366,7 @@ impl DemoApp {
|
|||
match (&self.camera, self.ui.three_d_enabled) {
|
||||
(&Camera::TwoD { .. }, true) => self.camera = Camera::new_3d(self.scene_view_box),
|
||||
(&Camera::ThreeD { .. }, false) => {
|
||||
let drawable_size = current_drawable_size(&self.window);
|
||||
let drawable_size = self.window.drawable_size();
|
||||
self.camera = Camera::new_2d(self.scene_view_box, drawable_size);
|
||||
}
|
||||
_ => {}
|
||||
|
@ -425,7 +385,7 @@ impl DemoApp {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
self.window.gl_swap_window();
|
||||
self.window.present();
|
||||
self.frame_counter += 1;
|
||||
}
|
||||
|
||||
|
@ -529,8 +489,8 @@ impl DemoApp {
|
|||
self.scene_view_box = built_svg.scene.view_box;
|
||||
self.scene_is_monochrome = built_svg.scene.is_monochrome();
|
||||
|
||||
update_drawable_size(&self.window, &self.scene_thread_proxy);
|
||||
let drawable_size = current_drawable_size(&self.window);
|
||||
self.scene_thread_proxy.set_drawable_size(self.window.drawable_size());
|
||||
let drawable_size = self.window.drawable_size();
|
||||
|
||||
self.camera = if self.ui.three_d_enabled {
|
||||
Camera::new_3d(built_svg.scene.view_box)
|
||||
|
@ -581,13 +541,12 @@ impl DemoApp {
|
|||
|
||||
fn take_screenshot(&mut self) {
|
||||
let screenshot_path = self.pending_screenshot_path.take().unwrap();
|
||||
let (drawable_width, drawable_height) = self.window.drawable_size();
|
||||
let drawable_size = Point2DI32::new(drawable_width as i32, drawable_height as i32);
|
||||
let drawable_size = self.window.drawable_size();
|
||||
let pixels = self.renderer.device.read_pixels_from_default_framebuffer(drawable_size);
|
||||
image::save_buffer(screenshot_path,
|
||||
&pixels,
|
||||
drawable_width,
|
||||
drawable_height,
|
||||
drawable_size.x() as u32,
|
||||
drawable_size.y() as u32,
|
||||
ColorType::RGBA(8)).unwrap();
|
||||
}
|
||||
|
||||
|
@ -768,18 +727,8 @@ fn build_scene(scene: &Scene, build_options: BuildOptions, jobs: Option<usize>)
|
|||
built_scene
|
||||
}
|
||||
|
||||
fn current_drawable_size(window: &Window) -> Point2DI32 {
|
||||
let (drawable_width, drawable_height) = window.drawable_size();
|
||||
Point2DI32::new(drawable_width as i32, drawable_height as i32)
|
||||
}
|
||||
|
||||
fn update_drawable_size(window: &Window, scene_thread_proxy: &SceneThreadProxy) {
|
||||
scene_thread_proxy.set_drawable_size(current_drawable_size(window));
|
||||
}
|
||||
|
||||
fn center_of_window(window: &Window) -> Point2DF32 {
|
||||
let (drawable_width, drawable_height) = window.drawable_size();
|
||||
Point2DI32::new(drawable_width as i32, drawable_height as i32).to_f32().scale(0.5)
|
||||
fn center_of_window<W>(window: &W) -> Point2DF32 where W: Window {
|
||||
window.drawable_size().to_f32().scale(0.5)
|
||||
}
|
||||
|
||||
enum Camera {
|
||||
|
@ -860,9 +809,8 @@ fn scale_factor_for_view_box(view_box: RectF32) -> f32 {
|
|||
1.0 / f32::min(view_box.size().x(), view_box.size().y())
|
||||
}
|
||||
|
||||
fn get_mouse_position(sdl_event_pump: &EventPump, scale_factor: f32) -> Point2DF32 {
|
||||
let mouse_state = sdl_event_pump.mouse_state();
|
||||
Point2DI32::new(mouse_state.x(), mouse_state.y()).to_f32().scale(scale_factor)
|
||||
fn get_mouse_position<W>(window: &W, scale_factor: f32) -> Point2DF32 where W: Window {
|
||||
window.mouse_position().to_f32().scale(scale_factor)
|
||||
}
|
||||
|
||||
fn get_svg_building_message(built_svg: &BuiltSVG) -> String {
|
||||
|
@ -872,10 +820,11 @@ fn get_svg_building_message(built_svg: &BuiltSVG) -> String {
|
|||
format!("Warning: These features in the SVG are unsupported: {}.", built_svg.result_flags)
|
||||
}
|
||||
|
||||
fn emit_message(ui: &mut DemoUI<GLDevice>,
|
||||
fn emit_message<W>(ui: &mut DemoUI<GLDevice>,
|
||||
message_epoch: &mut u32,
|
||||
expire_message_event_id: u32,
|
||||
message: String) {
|
||||
message: String)
|
||||
where W: Window {
|
||||
if message.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
@ -885,27 +834,6 @@ fn emit_message(ui: &mut DemoUI<GLDevice>,
|
|||
*message_epoch = expected_epoch;
|
||||
thread::spawn(move || {
|
||||
thread::sleep(Duration::from_secs(MESSAGE_TIMEOUT_SECS));
|
||||
push_sdl_user_event(SDL_UserEvent {
|
||||
timestamp: 0,
|
||||
windowID: 0,
|
||||
type_: expire_message_event_id,
|
||||
code: expected_epoch as i32,
|
||||
data1: ptr::null_mut(),
|
||||
data2: ptr::null_mut(),
|
||||
}).unwrap();
|
||||
W::push_user_event(expire_message_event_id, expected_epoch);
|
||||
});
|
||||
}
|
||||
|
||||
// Posts an event from any thread.
|
||||
//
|
||||
// TODO(pcwalton): The fact that this is necessary is really a `rust-sdl2` bug, filed at
|
||||
// https://github.com/Rust-SDL2/rust-sdl2/issues/747.
|
||||
fn push_sdl_user_event(mut event: SDL_UserEvent) -> Result<(), String> {
|
||||
unsafe {
|
||||
if sdl2_sys::SDL_PushEvent(&mut event as *mut SDL_UserEvent as *mut SDL_Event) == 1 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(sdl2::get_error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
// pathfinder/demo/common/src/window.rs
|
||||
//
|
||||
// Copyright © 2019 The Pathfinder Project Developers.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! A minimal cross-platform windowing layer.
|
||||
|
||||
use pathfinder_geometry::basic::point::Point2DI32;
|
||||
|
||||
pub trait Window {
|
||||
fn new(initial_size: Point2DI32) -> Self;
|
||||
fn size(&self) -> Point2DI32;
|
||||
fn drawable_size(&self) -> Point2DI32;
|
||||
fn mouse_position(&self) -> Point2DI32;
|
||||
fn get_event(&mut self) -> Event;
|
||||
fn try_get_event(&mut self) -> Option<Event>;
|
||||
fn present(&self);
|
||||
fn create_user_event_id(&self) -> u32;
|
||||
fn push_user_event(message_type: u32, message_data: u32);
|
||||
}
|
||||
|
||||
pub enum Event {
|
||||
Quit,
|
||||
WindowResized,
|
||||
KeyDown(Keycode),
|
||||
KeyUp(Keycode),
|
||||
MouseDown(Point2DI32),
|
||||
MouseMoved { position: Point2DI32, relative_position: Point2DI32 },
|
||||
MouseDragged { position: Point2DI32, relative_position: Point2DI32 },
|
||||
Zoom(f32),
|
||||
User { message_type: u32, message_data: u32 },
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Keycode {
|
||||
Alphanumeric(u8),
|
||||
Escape,
|
||||
}
|
|
@ -5,6 +5,12 @@ edition = "2018"
|
|||
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
||||
|
||||
[dependencies]
|
||||
gl = "0.6"
|
||||
sdl2 = "0.32"
|
||||
sdl2-sys = "0.32"
|
||||
|
||||
[dependencies.pathfinder_demo]
|
||||
path = "../common"
|
||||
|
||||
[dependencies.pathfinder_geometry]
|
||||
path = "../../geometry"
|
||||
|
|
|
@ -8,10 +8,162 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! A demo app for Pathfinder.
|
||||
//! A demo app for Pathfinder using SDL 2.
|
||||
|
||||
use pathfinder_demo::DemoApp;
|
||||
use pathfinder_demo::window::{Event, Keycode, Window};
|
||||
use pathfinder_geometry::basic::point::Point2DI32;
|
||||
use sdl2::{EventPump, EventSubsystem, Sdl, VideoSubsystem};
|
||||
use sdl2::event::{Event as SDLEvent, WindowEvent};
|
||||
use sdl2::keyboard::Keycode as SDLKeycode;
|
||||
use sdl2::video::{GLContext, GLProfile, Window as SDLWindow};
|
||||
use sdl2_sys::{SDL_Event, SDL_UserEvent};
|
||||
use std::ptr;
|
||||
|
||||
fn main() {
|
||||
DemoApp::new().run();
|
||||
DemoApp::<WindowImpl>::new().run();
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static SDL_CONTEXT: Sdl = sdl2::init().unwrap();
|
||||
static SDL_VIDEO: VideoSubsystem = SDL_CONTEXT.with(|context| context.video().unwrap());
|
||||
static SDL_EVENT: EventSubsystem = SDL_CONTEXT.with(|context| context.event().unwrap());
|
||||
}
|
||||
|
||||
struct WindowImpl {
|
||||
window: SDLWindow,
|
||||
event_pump: EventPump,
|
||||
#[allow(dead_code)]
|
||||
gl_context: GLContext,
|
||||
}
|
||||
|
||||
impl Window for WindowImpl {
|
||||
fn new(default_framebuffer_size: Point2DI32) -> WindowImpl {
|
||||
SDL_VIDEO.with(|sdl_video| {
|
||||
let (window, gl_context, event_pump);
|
||||
|
||||
let gl_attributes = sdl_video.gl_attr();
|
||||
gl_attributes.set_context_profile(GLProfile::Core);
|
||||
gl_attributes.set_context_version(3, 3);
|
||||
gl_attributes.set_depth_size(24);
|
||||
gl_attributes.set_stencil_size(8);
|
||||
|
||||
window = sdl_video.window("Pathfinder Demo",
|
||||
default_framebuffer_size.x() as u32,
|
||||
default_framebuffer_size.y() as u32)
|
||||
.opengl()
|
||||
.resizable()
|
||||
.allow_highdpi()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
gl_context = window.gl_create_context().unwrap();
|
||||
gl::load_with(|name| sdl_video.gl_get_proc_address(name) as *const _);
|
||||
|
||||
event_pump = SDL_CONTEXT.with(|sdl_context| sdl_context.event_pump().unwrap());
|
||||
|
||||
WindowImpl { window, event_pump, gl_context }
|
||||
})
|
||||
}
|
||||
|
||||
fn size(&self) -> Point2DI32 {
|
||||
let (width, height) = self.window.size();
|
||||
Point2DI32::new(width as i32, height as i32)
|
||||
}
|
||||
|
||||
fn drawable_size(&self) -> Point2DI32 {
|
||||
let (width, height) = self.window.drawable_size();
|
||||
Point2DI32::new(width as i32, height as i32)
|
||||
}
|
||||
|
||||
fn mouse_position(&self) -> Point2DI32 {
|
||||
let mouse_state = self.event_pump.mouse_state();
|
||||
Point2DI32::new(mouse_state.x(), mouse_state.y())
|
||||
}
|
||||
|
||||
fn get_event(&mut self) -> Event {
|
||||
loop {
|
||||
let sdl_event = self.event_pump.wait_event();
|
||||
if let Some(event) = self.convert_sdl_event(sdl_event) {
|
||||
return event;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_event(&mut self) -> Option<Event> {
|
||||
loop {
|
||||
let sdl_event = self.event_pump.poll_event()?;
|
||||
if let Some(event) = self.convert_sdl_event(sdl_event) {
|
||||
return Some(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn present(&self) {
|
||||
self.window.gl_swap_window();
|
||||
}
|
||||
|
||||
fn create_user_event_id(&self) -> u32 {
|
||||
SDL_EVENT.with(|sdl_event| unsafe { sdl_event.register_event().unwrap() })
|
||||
}
|
||||
|
||||
fn push_user_event(message_type: u32, message_data: u32) {
|
||||
unsafe {
|
||||
let mut user_event = SDL_UserEvent {
|
||||
timestamp: 0,
|
||||
windowID: 0,
|
||||
type_: message_type,
|
||||
code: message_data as i32,
|
||||
data1: ptr::null_mut(),
|
||||
data2: ptr::null_mut(),
|
||||
};
|
||||
sdl2_sys::SDL_PushEvent(&mut user_event as *mut SDL_UserEvent as *mut SDL_Event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowImpl {
|
||||
fn convert_sdl_event(&self, sdl_event: SDLEvent) -> Option<Event> {
|
||||
match sdl_event {
|
||||
SDLEvent::User { type_, code, .. } => {
|
||||
Some(Event::User { message_type: type_, message_data: code as u32 })
|
||||
}
|
||||
SDLEvent::MouseButtonDown { x, y, .. } => {
|
||||
Some(Event::MouseDown(Point2DI32::new(x, y)))
|
||||
}
|
||||
SDLEvent::MouseMotion { x, y, xrel, yrel, mousestate, .. } => {
|
||||
let position = Point2DI32::new(x, y);
|
||||
let relative_position = Point2DI32::new(xrel, yrel);
|
||||
if mousestate.left() {
|
||||
Some(Event::MouseDragged { position, relative_position })
|
||||
} else {
|
||||
Some(Event::MouseMoved { position, relative_position })
|
||||
}
|
||||
}
|
||||
SDLEvent::Quit { .. } => Some(Event::Quit),
|
||||
SDLEvent::Window { win_event: WindowEvent::SizeChanged(..), .. } => {
|
||||
Some(Event::WindowResized)
|
||||
}
|
||||
SDLEvent::KeyDown { keycode: Some(sdl_keycode), .. } => {
|
||||
self.convert_sdl_keycode(sdl_keycode).map(Event::KeyDown)
|
||||
}
|
||||
SDLEvent::KeyUp { keycode: Some(sdl_keycode), .. } => {
|
||||
self.convert_sdl_keycode(sdl_keycode).map(Event::KeyUp)
|
||||
}
|
||||
SDLEvent::MultiGesture { d_dist, .. } => Some(Event::Zoom(d_dist)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_sdl_keycode(&self, sdl_keycode: SDLKeycode) -> Option<Keycode> {
|
||||
match sdl_keycode {
|
||||
SDLKeycode::Escape => Some(Keycode::Escape),
|
||||
sdl_keycode if sdl_keycode as i32 >= SDLKeycode::A as i32 &&
|
||||
sdl_keycode as i32 <= SDLKeycode::Z as i32 => {
|
||||
let offset = (sdl_keycode as i32 - SDLKeycode::A as i32) as u8;
|
||||
Some(Keycode::Alphanumeric(offset + b'a'))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue