Add screenshot functionality.
This commit is contained in:
parent
aef7dd1353
commit
f6af769486
|
@ -504,6 +504,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"jemallocator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nfd 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pathfinder_geometry 0.3.0",
|
||||
|
|
|
@ -13,6 +13,11 @@ rayon = "1.0"
|
|||
sdl2 = "0.32"
|
||||
usvg = "0.4"
|
||||
|
||||
[dependencies.image]
|
||||
version = "0.21"
|
||||
default-features = false
|
||||
features = ["png_codec"]
|
||||
|
||||
[dependencies.pathfinder_geometry]
|
||||
path = "../../geometry"
|
||||
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
|
||||
use crate::ui::{DemoUI, UIAction, UIEvent};
|
||||
use clap::{App, Arg};
|
||||
use gl::types::GLsizei;
|
||||
use gl::types::{GLsizei, GLvoid};
|
||||
use image::ColorType;
|
||||
use jemallocator;
|
||||
use pathfinder_geometry::basic::point::{Point2DF32, Point2DI32, Point3DF32};
|
||||
use pathfinder_geometry::basic::rect::RectF32;
|
||||
|
@ -89,6 +90,7 @@ pub struct DemoApp {
|
|||
camera: Camera,
|
||||
frame_counter: u32,
|
||||
events: Vec<Event>,
|
||||
pending_screenshot_path: Option<PathBuf>,
|
||||
exit: bool,
|
||||
mouselook_enabled: bool,
|
||||
dirty: bool,
|
||||
|
@ -164,6 +166,7 @@ impl DemoApp {
|
|||
|
||||
camera,
|
||||
frame_counter: 0,
|
||||
pending_screenshot_path: None,
|
||||
events: vec![],
|
||||
exit: false,
|
||||
mouselook_enabled: false,
|
||||
|
@ -342,6 +345,10 @@ impl DemoApp {
|
|||
self.draw_environment(&render_transform);
|
||||
self.render_vector_scene(&built_scene);
|
||||
|
||||
if self.pending_screenshot_path.is_some() {
|
||||
self.take_screenshot();
|
||||
}
|
||||
|
||||
let rendering_time = self.renderer.shift_timer_query();
|
||||
self.renderer.debug_ui.add_sample(tile_time, rendering_time);
|
||||
self.renderer.debug_ui.draw();
|
||||
|
@ -499,6 +506,11 @@ impl DemoApp {
|
|||
self.dirty = true;
|
||||
}
|
||||
|
||||
UIAction::TakeScreenshot(ref path) => {
|
||||
self.pending_screenshot_path = Some((*path).clone());
|
||||
self.dirty = true;
|
||||
}
|
||||
|
||||
UIAction::ZoomIn => {
|
||||
if let Camera::TwoD(ref mut transform) = self.camera {
|
||||
let scale = Point2DF32::splat(1.0 + CAMERA_ZOOM_AMOUNT_2D);
|
||||
|
@ -531,6 +543,17 @@ 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 pixels = self.device.readback_pixels(drawable_width, drawable_height);
|
||||
image::save_buffer(screenshot_path,
|
||||
&pixels,
|
||||
drawable_width,
|
||||
drawable_height,
|
||||
ColorType::RGBA(8)).unwrap();
|
||||
}
|
||||
|
||||
fn background_color(&self) -> ColorU {
|
||||
if self.ui.dark_background_enabled { DARK_BG_COLOR } else { LIGHT_BG_COLOR }
|
||||
}
|
||||
|
@ -817,6 +840,29 @@ impl DemoDevice {
|
|||
gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
fn readback_pixels(&self, width: u32, height: u32) -> Vec<u8> {
|
||||
let mut pixels = vec![0; width as usize * height as usize * 4];
|
||||
unsafe {
|
||||
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
||||
gl::ReadPixels(0, 0,
|
||||
width as GLsizei, height as GLsizei,
|
||||
gl::RGBA,
|
||||
gl::UNSIGNED_BYTE,
|
||||
pixels.as_mut_ptr() as *mut GLvoid);
|
||||
}
|
||||
|
||||
// Flip right-side-up.
|
||||
let stride = width as usize * 4;
|
||||
for y in 0..(height as usize / 2) {
|
||||
let (index_a, index_b) = (y * stride, (height as usize - y - 1) * stride);
|
||||
for offset in 0..stride {
|
||||
pixels.swap(index_a + offset, index_b + offset);
|
||||
}
|
||||
}
|
||||
|
||||
pixels
|
||||
}
|
||||
}
|
||||
|
||||
struct GroundProgram {
|
||||
|
|
|
@ -30,9 +30,12 @@ const SLIDER_KNOB_HEIGHT: i32 = 48;
|
|||
const EFFECTS_PANEL_WIDTH: i32 = 550;
|
||||
const EFFECTS_PANEL_HEIGHT: i32 = BUTTON_HEIGHT * 3 + PADDING * 4;
|
||||
|
||||
const BACKGROUND_SWITCH_X: i32 = PADDING + (BUTTON_WIDTH + PADDING) * 2 + PADDING + SWITCH_SIZE;
|
||||
const OPEN_BUTTON_X: i32 = PADDING + (BUTTON_WIDTH + PADDING) * 1;
|
||||
const SCREENSHOT_BUTTON_X: i32 = PADDING + (BUTTON_WIDTH + PADDING) * 2;
|
||||
const THREE_D_SWITCH_X: i32 = PADDING + (BUTTON_WIDTH + PADDING) * 3;
|
||||
const BACKGROUND_SWITCH_X: i32 = PADDING + (BUTTON_WIDTH + PADDING) * 3 + PADDING + SWITCH_SIZE;
|
||||
|
||||
const ROTATE_PANEL_X: i32 = PADDING + (BUTTON_WIDTH + PADDING) * 2 + (PADDING + SWITCH_SIZE) * 2;
|
||||
const ROTATE_PANEL_X: i32 = PADDING + (BUTTON_WIDTH + PADDING) * 3 + (PADDING + SWITCH_SIZE) * 2;
|
||||
const ROTATE_PANEL_WIDTH: i32 = SLIDER_WIDTH + PADDING * 2;
|
||||
const ROTATE_PANEL_HEIGHT: i32 = PADDING * 2 + SLIDER_HEIGHT;
|
||||
|
||||
|
@ -43,6 +46,7 @@ static ZOOM_IN_PNG_NAME: &'static str = "demo-zoom-in";
|
|||
static ZOOM_OUT_PNG_NAME: &'static str = "demo-zoom-out";
|
||||
static BG_LIGHT_PNG_NAME: &'static str = "demo-bg-light";
|
||||
static BG_DARK_PNG_NAME: &'static str = "demo-bg-dark";
|
||||
static SCREENSHOT_PNG_NAME: &'static str = "demo-screenshot";
|
||||
|
||||
pub struct DemoUI {
|
||||
effects_texture: Texture,
|
||||
|
@ -52,6 +56,7 @@ pub struct DemoUI {
|
|||
zoom_out_texture: Texture,
|
||||
bg_light_texture: Texture,
|
||||
bg_dark_texture: Texture,
|
||||
screenshot_texture: Texture,
|
||||
|
||||
effects_panel_visible: bool,
|
||||
rotate_panel_visible: bool,
|
||||
|
@ -73,6 +78,7 @@ impl DemoUI {
|
|||
let zoom_out_texture = device.create_texture_from_png(ZOOM_OUT_PNG_NAME);
|
||||
let bg_light_texture = device.create_texture_from_png(BG_LIGHT_PNG_NAME);
|
||||
let bg_dark_texture = device.create_texture_from_png(BG_DARK_PNG_NAME);
|
||||
let screenshot_texture = device.create_texture_from_png(SCREENSHOT_PNG_NAME);
|
||||
|
||||
DemoUI {
|
||||
effects_texture,
|
||||
|
@ -82,6 +88,7 @@ impl DemoUI {
|
|||
zoom_out_texture,
|
||||
bg_light_texture,
|
||||
bg_dark_texture,
|
||||
screenshot_texture,
|
||||
three_d_enabled: options.three_d,
|
||||
dark_background_enabled: true,
|
||||
effects_panel_visible: false,
|
||||
|
@ -107,27 +114,36 @@ impl DemoUI {
|
|||
}
|
||||
|
||||
// Draw open button.
|
||||
let open_button_x = PADDING + BUTTON_WIDTH + PADDING;
|
||||
let open_button_y = bottom - BUTTON_HEIGHT;
|
||||
let open_button_position = Point2DI32::new(open_button_x, open_button_y);
|
||||
let lower_button_y = bottom - BUTTON_HEIGHT;
|
||||
let open_button_position = Point2DI32::new(OPEN_BUTTON_X, lower_button_y);
|
||||
if self.draw_button(debug_ui, event, open_button_position, &self.open_texture) {
|
||||
if let Ok(Response::Okay(file)) = nfd::open_file_dialog(Some("svg"), None) {
|
||||
*action = UIAction::OpenFile(PathBuf::from(file));
|
||||
}
|
||||
}
|
||||
|
||||
// Draw screenshot button.
|
||||
let screenshot_button_position = Point2DI32::new(SCREENSHOT_BUTTON_X, lower_button_y);
|
||||
if self.draw_button(debug_ui,
|
||||
event,
|
||||
screenshot_button_position,
|
||||
&self.screenshot_texture) {
|
||||
if let Ok(Response::Okay(file)) = nfd::open_save_dialog(Some("png"), None) {
|
||||
*action = UIAction::TakeScreenshot(PathBuf::from(file));
|
||||
}
|
||||
}
|
||||
|
||||
// Draw 3D switch.
|
||||
let threed_switch_x = PADDING + (BUTTON_WIDTH + PADDING) * 2;
|
||||
let threed_switch_origin = Point2DI32::new(threed_switch_x, open_button_y);
|
||||
let three_d_switch_origin = Point2DI32::new(THREE_D_SWITCH_X, lower_button_y);
|
||||
self.three_d_enabled = self.draw_text_switch(debug_ui,
|
||||
event,
|
||||
threed_switch_origin,
|
||||
three_d_switch_origin,
|
||||
"2D",
|
||||
"3D",
|
||||
self.three_d_enabled);
|
||||
|
||||
// Draw background switch.
|
||||
let background_switch_origin = Point2DI32::new(BACKGROUND_SWITCH_X, open_button_y);
|
||||
let background_switch_origin = Point2DI32::new(BACKGROUND_SWITCH_X, lower_button_y);
|
||||
self.dark_background_enabled = self.draw_image_switch(debug_ui,
|
||||
event,
|
||||
background_switch_origin,
|
||||
|
@ -354,6 +370,7 @@ impl DemoUI {
|
|||
pub enum UIAction {
|
||||
None,
|
||||
OpenFile(PathBuf),
|
||||
TakeScreenshot(PathBuf),
|
||||
ZoomIn,
|
||||
ZoomOut,
|
||||
Rotate(f32),
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 885 B |
Loading…
Reference in New Issue