Factor the SDL code out in preparation for other ports

This commit is contained in:
Patrick Walton 2019-03-07 16:14:26 -08:00
parent 25558c2177
commit a74c0abbec
6 changed files with 279 additions and 170 deletions

47
Cargo.lock generated
View File

@ -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"

View File

@ -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"

View File

@ -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>,
message_epoch: &mut u32,
expire_message_event_id: u32,
message: String) {
fn emit_message<W>(ui: &mut DemoUI<GLDevice>,
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<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())
}
}
}

43
demo/common/src/window.rs Normal file
View File

@ -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,
}

View File

@ -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"

View File

@ -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,
}
}
}