diff --git a/Cargo.lock b/Cargo.lock index 4e828286..87dbc2f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/demo/common/Cargo.toml b/demo/common/Cargo.toml index 264ee582..adac8377 100644 --- a/demo/common/Cargo.toml +++ b/demo/common/Cargo.toml @@ -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" diff --git a/demo/common/src/lib.rs b/demo/common/src/lib.rs index 3cd1ee6a..e0f28c38 100644 --- a/demo/common/src/lib.rs +++ b/demo/common/src/lib.rs @@ -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 where W: Window { + window: W, scale_factor: f32, @@ -111,40 +105,18 @@ pub struct DemoApp { ground_line_vertex_array: GroundLineVertexArray, } -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 DemoApp where W: Window { + pub fn new() -> DemoApp { + 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::(&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) 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(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(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, - message_epoch: &mut u32, - expire_message_event_id: u32, - message: String) { +fn emit_message(ui: &mut DemoUI, + message_epoch: &mut u32, + expire_message_event_id: u32, + message: String) + where W: Window { if message.is_empty() { return; } @@ -885,27 +834,6 @@ fn emit_message(ui: &mut DemoUI, *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()) - } - } -} diff --git a/demo/common/src/window.rs b/demo/common/src/window.rs new file mode 100644 index 00000000..eb056728 --- /dev/null +++ b/demo/common/src/window.rs @@ -0,0 +1,43 @@ +// pathfinder/demo/common/src/window.rs +// +// Copyright © 2019 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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; + 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, +} diff --git a/demo/native/Cargo.toml b/demo/native/Cargo.toml index 5ebd3d33..3425ab65 100644 --- a/demo/native/Cargo.toml +++ b/demo/native/Cargo.toml @@ -5,6 +5,12 @@ edition = "2018" authors = ["Patrick Walton "] [dependencies] +gl = "0.6" +sdl2 = "0.32" +sdl2-sys = "0.32" [dependencies.pathfinder_demo] path = "../common" + +[dependencies.pathfinder_geometry] +path = "../../geometry" diff --git a/demo/native/src/main.rs b/demo/native/src/main.rs index 12c74ab1..32477a9b 100644 --- a/demo/native/src/main.rs +++ b/demo/native/src/main.rs @@ -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::::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 { + 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 { + 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 { + 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, + } + } }