update Standard system resource with variable screen size support
This commit is contained in:
parent
7143430769
commit
f2f1d83edf
|
@ -1,10 +1,9 @@
|
|||
use byte_slice_cast::AsByteSlice;
|
||||
|
||||
use crate::audio::queue::AudioQueue;
|
||||
use crate::audio::{Audio, TARGET_AUDIO_CHANNELS, TARGET_AUDIO_FREQUENCY};
|
||||
use crate::graphics::bitmap::rgb::RgbaBitmap;
|
||||
use crate::graphics::font::BitmaskFont;
|
||||
use crate::system::event::{SystemEvent, SystemEventHandler};
|
||||
use crate::system::event::{SystemEvent, SystemEventHandler, WindowEvent};
|
||||
use crate::system::framebuffer::{calculate_logical_screen_size, SdlFramebuffer};
|
||||
use crate::system::input_devices::keyboard::Keyboard;
|
||||
use crate::system::input_devices::mouse::cursor::CustomMouseCursor;
|
||||
use crate::system::input_devices::mouse::Mouse;
|
||||
|
@ -18,22 +17,48 @@ const DEFAULT_SCALE_FACTOR: u32 = 3;
|
|||
pub struct StandardConfig {
|
||||
screen_width: u32,
|
||||
screen_height: u32,
|
||||
fixed_screen_size: bool,
|
||||
initial_scale_factor: u32,
|
||||
integer_scaling: bool,
|
||||
}
|
||||
|
||||
impl Default for StandardConfig {
|
||||
/// Returns a new [`StandardConfig`] with a default configuration.
|
||||
fn default() -> Self {
|
||||
StandardConfig::fixed_screen_size(DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT, false)
|
||||
}
|
||||
}
|
||||
|
||||
impl StandardConfig {
|
||||
/// Returns a new [`DosLikeConfig`] with a default configuration.
|
||||
pub fn new() -> Self {
|
||||
/// Creates a configuration that will use a fixed screen size at a set scaling factor. Any window resizing
|
||||
/// will simply scale up or down the final image on screen, but the application will always use the same
|
||||
/// logical screen resolution, `screen_width` and `screen_height`, at runtime.
|
||||
pub fn fixed_screen_size(screen_width: u32, screen_height: u32, integer_scaling: bool) -> Self {
|
||||
StandardConfig {
|
||||
screen_width: DEFAULT_SCREEN_WIDTH,
|
||||
screen_height: DEFAULT_SCREEN_HEIGHT,
|
||||
screen_width,
|
||||
screen_height,
|
||||
initial_scale_factor: DEFAULT_SCALE_FACTOR,
|
||||
integer_scaling: false,
|
||||
integer_scaling,
|
||||
fixed_screen_size: true,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add customization ability for setting different screen dimensions instead of it being hardcoded
|
||||
/// Creates a configuration that allows the screen size to be automatically updated at runtime to match the
|
||||
/// current window size, including any arbitrary user window resizing. The final image on screen will always be
|
||||
/// scaled up by the factor given. The logical screen size at runtime (as seen by the application code) is
|
||||
/// always based on:
|
||||
///
|
||||
/// `logical_screen_width = ceil(window_width / scale_factor)`
|
||||
/// `logical_screen_height = ceil(window_height / scale_factor)`
|
||||
pub fn variable_screen_size(initial_width: u32, initial_height: u32) -> Self {
|
||||
StandardConfig {
|
||||
screen_width: initial_width,
|
||||
screen_height: initial_height,
|
||||
initial_scale_factor: DEFAULT_SCALE_FACTOR,
|
||||
integer_scaling: false,
|
||||
fixed_screen_size: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets an integer scaling factor for the [`System`] being built to up-scale the virtual
|
||||
/// framebuffer to when displaying it on screen.
|
||||
|
@ -41,13 +66,6 @@ impl StandardConfig {
|
|||
self.initial_scale_factor = scale_factor;
|
||||
self
|
||||
}
|
||||
|
||||
/// Enables or disables restricting the final rendered output to always be integer scaled,
|
||||
/// even if that result will not fully fill the area of the window.
|
||||
pub fn integer_scaling(mut self, enable: bool) -> Self {
|
||||
self.integer_scaling = enable;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl SystemResourcesConfig for StandardConfig {
|
||||
|
@ -59,8 +77,6 @@ impl SystemResourcesConfig for StandardConfig {
|
|||
audio_subsystem: &sdl2::AudioSubsystem,
|
||||
mut window: sdl2::video::Window,
|
||||
) -> Result<Self::SystemResourcesType, SystemResourcesError> {
|
||||
let texture_pixel_size = 4; // 32-bit ARGB format
|
||||
|
||||
let window_width = self.screen_width * self.initial_scale_factor;
|
||||
let window_height = self.screen_height * self.initial_scale_factor;
|
||||
if let Err(error) = window.set_size(window_width, window_height) {
|
||||
|
@ -74,9 +90,6 @@ impl SystemResourcesConfig for StandardConfig {
|
|||
Ok(canvas) => canvas,
|
||||
Err(error) => return Err(SystemResourcesError::SDLError(error.to_string())),
|
||||
};
|
||||
if let Err(error) = sdl_canvas.set_logical_size(self.screen_width, self.screen_height) {
|
||||
return Err(SystemResourcesError::SDLError(error.to_string()));
|
||||
};
|
||||
|
||||
// TODO: newer versions of rust-sdl2 support this directly off the WindowCanvas struct
|
||||
unsafe {
|
||||
|
@ -90,23 +103,14 @@ impl SystemResourcesConfig for StandardConfig {
|
|||
);
|
||||
}
|
||||
|
||||
// create an SDL texture which we will be uploading to every frame to display the
|
||||
// application's framebuffer
|
||||
// create the SDL framebuffer at the initial logical screen size
|
||||
|
||||
let sdl_texture = match sdl_canvas.create_texture_streaming(
|
||||
Some(sdl2::pixels::PixelFormatEnum::ARGB8888),
|
||||
self.screen_width,
|
||||
self.screen_height,
|
||||
) {
|
||||
Ok(texture) => texture,
|
||||
Err(error) => return Err(SystemResourcesError::SDLError(error.to_string())),
|
||||
};
|
||||
let sdl_texture_pitch = (sdl_texture.query().width * texture_pixel_size) as usize;
|
||||
let framebuffer = SdlFramebuffer::new(&mut sdl_canvas, self.screen_width, self.screen_height, false)?;
|
||||
|
||||
// create the Bitmap object that will be exposed to the application acting as the system
|
||||
// backbuffer
|
||||
|
||||
let framebuffer = match RgbaBitmap::new(self.screen_width, self.screen_height) {
|
||||
let screen_bitmap = match RgbaBitmap::new(self.screen_width, self.screen_height) {
|
||||
Ok(bmp) => bmp,
|
||||
Err(error) => return Err(SystemResourcesError::SDLError(error.to_string())),
|
||||
};
|
||||
|
@ -137,11 +141,12 @@ impl SystemResourcesConfig for StandardConfig {
|
|||
|
||||
Ok(Standard {
|
||||
sdl_canvas,
|
||||
sdl_texture,
|
||||
sdl_texture_pitch,
|
||||
framebuffer,
|
||||
scale_factor: self.initial_scale_factor,
|
||||
fixed_screen_size: self.fixed_screen_size,
|
||||
audio,
|
||||
audio_queue,
|
||||
video: framebuffer,
|
||||
video: screen_bitmap,
|
||||
font,
|
||||
keyboard,
|
||||
mouse,
|
||||
|
@ -152,8 +157,9 @@ impl SystemResourcesConfig for StandardConfig {
|
|||
|
||||
pub struct Standard {
|
||||
sdl_canvas: sdl2::render::WindowCanvas,
|
||||
sdl_texture: sdl2::render::Texture,
|
||||
sdl_texture_pitch: usize,
|
||||
framebuffer: SdlFramebuffer,
|
||||
scale_factor: u32,
|
||||
fixed_screen_size: bool,
|
||||
|
||||
/// An [`Audio`] instance that allows interacting with the system's audio output device.
|
||||
pub audio: Audio,
|
||||
|
@ -210,19 +216,8 @@ impl SystemResources for Standard {
|
|||
|
||||
fn display(&mut self) -> Result<(), SystemResourcesError> {
|
||||
self.cursor.render(&mut self.video);
|
||||
|
||||
let texture_pixels = self.video.pixels().as_byte_slice();
|
||||
if let Err(error) = self.sdl_texture.update(None, texture_pixels, self.sdl_texture_pitch) {
|
||||
return Err(SystemResourcesError::SDLError(error.to_string()));
|
||||
}
|
||||
self.sdl_canvas.clear();
|
||||
if let Err(error) = self.sdl_canvas.copy(&self.sdl_texture, None, None) {
|
||||
return Err(SystemResourcesError::SDLError(error));
|
||||
}
|
||||
self.sdl_canvas.present();
|
||||
|
||||
self.framebuffer.display(&mut self.sdl_canvas, &self.video)?;
|
||||
self.cursor.hide(&mut self.video);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -233,6 +228,13 @@ impl SystemResources for Standard {
|
|||
}
|
||||
|
||||
fn handle_event(&mut self, event: &SystemEvent) -> Result<bool, SystemResourcesError> {
|
||||
if let SystemEvent::Window(WindowEvent::SizeChanged(width, height)) = event {
|
||||
if !self.fixed_screen_size {
|
||||
self.resize_screen(*width as u32, *height as u32)?;
|
||||
}
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
if self.keyboard.handle_event(event) {
|
||||
return Ok(true);
|
||||
}
|
||||
|
@ -252,3 +254,21 @@ impl SystemResources for Standard {
|
|||
self.video.height()
|
||||
}
|
||||
}
|
||||
|
||||
impl Standard {
|
||||
fn resize_screen(&mut self, new_width: u32, new_height: u32) -> Result<(), SystemResourcesError> {
|
||||
let (logical_width, logical_height) = calculate_logical_screen_size(new_width, new_height, self.scale_factor);
|
||||
|
||||
let framebuffer = SdlFramebuffer::new(&mut self.sdl_canvas, logical_width, logical_height, false)?;
|
||||
|
||||
let screen_bitmap = match RgbaBitmap::new(logical_width, logical_height) {
|
||||
Ok(bmp) => bmp,
|
||||
Err(error) => return Err(SystemResourcesError::SDLError(error.to_string())),
|
||||
};
|
||||
|
||||
self.framebuffer = framebuffer;
|
||||
self.video = screen_bitmap;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue