Add screenshot, fullscreen, & debug keys

Former-commit-id: 9358575794b71535905c5133eb6764284c35fb34
This commit is contained in:
Imbris 2019-05-18 17:16:35 -04:00
parent 9e9e8be196
commit 7855dfe52f
8 changed files with 137 additions and 4 deletions

1
.gitignore vendored
View File

@ -20,3 +20,4 @@ settings.toml
*.rar
*.log
run.sh
screenshots

View File

@ -538,6 +538,10 @@ impl Hud {
self.show.toggle_help();
true
}
Key::ToggleDebug => {
self.show.debug = !self.show.debug;
true
}
_ => false,
},
WinEvent::KeyDown(key) | WinEvent::KeyUp(key) => match key {

View File

@ -42,6 +42,8 @@ pub enum RenderError {
CombinedError(gfx::CombinedError),
BufferCreationError(gfx::buffer::CreationError),
IncludeError(glsl_include::Error),
MappingError(gfx::mapping::Error),
CopyError(gfx::CopyError<[u16; 3], usize>),
}
/// Used to represent a specific rendering configuration.

View File

@ -306,6 +306,54 @@ impl Renderer {
texture.update(&mut self.encoder, offset, size, data)
}
/// Creates a download buffer, downloads the win_color_view, and converts to a image::DynamicImage.
pub fn create_screenshot(&mut self) -> Result<image::DynamicImage, RenderError> {
let (width, height) = self.get_resolution().into_tuple();
use gfx::{
format::{Formatted, SurfaceTyped},
memory::Typed,
};
type WinSurfaceData = <<WinColorFmt as Formatted>::Surface as SurfaceTyped>::DataType;
let mut download = self
.factory
.create_download_buffer::<WinSurfaceData>(width as usize * height as usize)
.map_err(|err| RenderError::BufferCreationError(err))?;
self.encoder
.copy_texture_to_buffer_raw(
self.win_color_view.raw().get_texture(),
None,
gfx::texture::RawImageInfo {
xoffset: 0,
yoffset: 0,
zoffset: 0,
width,
height,
depth: 0,
format: WinColorFmt::get_format(),
mipmap: 0,
},
download.raw(),
0,
)
.map_err(|err| RenderError::CopyError(err))?;
self.flush();
// Assumes that the format is Rgba8.
let raw_data = self
.factory
.read_mapping(&download)
.map_err(|err| RenderError::MappingError(err))?
.iter()
.rev()
.flatten()
.map(|&e| e)
.collect::<Vec<_>>();
Ok(image::DynamicImage::ImageRgba8(
// Should not fail if the dimensions are correct.
image::ImageBuffer::from_raw(width as u32, height as u32, raw_data).unwrap(),
))
}
/// Queue the rendering of the provided skybox model in the upcoming frame.
pub fn render_skybox(
&mut self,

View File

@ -35,6 +35,9 @@ pub struct ControlSettings {
pub settings: VirtualKeyCode,
pub help: VirtualKeyCode,
pub toggle_interface: VirtualKeyCode,
pub toggle_debug: VirtualKeyCode,
pub fullscreen: VirtualKeyCode,
pub screenshot: VirtualKeyCode,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
@ -71,6 +74,9 @@ impl Default for Settings {
settings: VirtualKeyCode::N,
help: VirtualKeyCode::F1,
toggle_interface: VirtualKeyCode::F2,
toggle_debug: VirtualKeyCode::F3,
fullscreen: VirtualKeyCode::F11,
screenshot: VirtualKeyCode::F4,
},
networking: NetworkingSettings {
username: "Username".to_string(),

View File

@ -55,7 +55,7 @@ impl GraphicCache {
mut cacher: F,
) -> Option<Aabr<u16>>
where
F: FnMut(Aabr<u16>, Vec<[u8; 4]>),
F: FnMut(Aabr<u16>, &[[u8; 4]]),
{
match self
.rect_map
@ -94,6 +94,7 @@ impl GraphicCache {
image::FilterType::Nearest,
)
.to_rgba()
// TODO: might be a better way to do this
.pixels()
.map(|p| p.data)
.collect::<Vec<[u8; 4]>>(),
@ -103,7 +104,7 @@ impl GraphicCache {
};
// Draw to allocated area.
cacher(aabr, data);
cacher(aabr, &data);
// Insert area into map for retrieval.
self.rect_map

View File

@ -347,7 +347,7 @@ impl Ui {
|aabr, data| {
let offset = aabr.min.into_array();
let size = aabr.size().into_array();
renderer.update_texture(cache_tex, offset, size, &data);
renderer.update_texture(cache_tex, offset, size, data);
},
) {
Some(aabr) => Aabr {

View File

@ -11,6 +11,7 @@ pub struct Window {
renderer: Renderer,
window: glutin::GlWindow,
cursor_grabbed: bool,
fullscreen: bool,
needs_refresh_resize: bool,
key_map: HashMap<glutin::VirtualKeyCode, Key>,
supplement_events: Vec<Event>,
@ -56,12 +57,16 @@ impl Window {
key_map.insert(settings.controls.settings, Key::Settings);
key_map.insert(settings.controls.help, Key::Help);
key_map.insert(settings.controls.toggle_interface, Key::ToggleInterface);
key_map.insert(settings.controls.toggle_debug, Key::ToggleDebug);
key_map.insert(settings.controls.fullscreen, Key::Fullscreen);
key_map.insert(settings.controls.screenshot, Key::Screenshot);
let tmp = Ok(Self {
events_loop,
renderer: Renderer::new(device, factory, win_color_view, win_depth_view)?,
window,
cursor_grabbed: false,
fullscreen: false,
needs_refresh_resize: false,
key_map,
supplement_events: vec![],
@ -91,6 +96,8 @@ impl Window {
let renderer = &mut self.renderer;
let window = &mut self.window;
let key_map = &self.key_map;
let mut toggle_fullscreen = false;
let mut take_screenshot = false;
self.events_loop.poll_events(|event| {
// Get events for ui.
@ -112,9 +119,19 @@ impl Window {
glutin::WindowEvent::KeyboardInput { input, .. } => match input.virtual_keycode
{
Some(keycode) => match key_map.get(&keycode) {
Some(Key::Fullscreen) => match input.state {
glutin::ElementState::Pressed => {
toggle_fullscreen = !toggle_fullscreen
}
_ => (),
},
Some(Key::Screenshot) => match input.state {
glutin::ElementState::Pressed => take_screenshot = true,
_ => {}
},
Some(&key) => events.push(match input.state {
glutin::ElementState::Pressed => Event::KeyDown(key),
_ => Event::KeyUp(key),
glutin::ElementState::Released => Event::KeyUp(key),
}),
_ => {}
},
@ -137,6 +154,15 @@ impl Window {
_ => {}
}
});
if take_screenshot {
self.take_screenshot();
}
if toggle_fullscreen {
self.fullscreen(!self.is_fullscreen());
}
events
}
@ -156,6 +182,20 @@ impl Window {
let _ = self.window.grab_cursor(grab);
}
pub fn is_fullscreen(&self) -> bool {
self.fullscreen
}
pub fn fullscreen(&mut self, fullscreen: bool) {
self.fullscreen = fullscreen;
if fullscreen {
self.window
.set_fullscreen(Some(self.window.get_current_monitor()));
} else {
self.window.set_fullscreen(None);
}
}
pub fn needs_refresh_resize(&mut self) {
self.needs_refresh_resize = true;
}
@ -172,6 +212,34 @@ impl Window {
pub fn send_supplement_event(&mut self, event: Event) {
self.supplement_events.push(event)
}
pub fn take_screenshot(&mut self) {
match self.renderer.create_screenshot() {
Ok(img) => {
std::thread::spawn(move || {
use std::{path::PathBuf, time::SystemTime};
// Check if folder exists and create it if it does not
let mut path = std::path::PathBuf::from("./screenshots");
if !path.exists() {
if let Err(err) = std::fs::create_dir(&path) {
log::error!("Coudn't create folder for screenshot: {:?}", err);
}
}
path.push(format!(
"screenshot_{}.png",
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.map(|d| d.as_millis())
.unwrap_or(0)
));
if let Err(err) = img.save(&path) {
log::error!("Coudn't save screenshot: {:?}", err);
}
});
}
Err(err) => log::error!("Coudn't create screenshot due to renderer error: {:?}", err),
}
}
}
/// Represents a key that the game recognises after keyboard mapping.
@ -195,6 +263,9 @@ pub enum Key {
Settings,
ToggleInterface,
Help,
ToggleDebug,
Fullscreen,
Screenshot,
}
/// Represents an incoming event from the window.