Add integer scaling option (#150)

* Add integer scaling option

* more

* more

* more
This commit is contained in:
Logan McNaughton
2025-01-14 23:23:26 +01:00
committed by GitHub
parent b3f8688ba5
commit eae81c4623
5 changed files with 75 additions and 50 deletions
+31 -21
View File
@@ -51,6 +51,7 @@ enum vi_registers
};
static bool fullscreen;
static bool integer_scaling;
static SDL_Window *window;
static RDP::CommandProcessor *processor;
static SDL_WSIPlatform *wsi_platform;
@@ -166,13 +167,14 @@ int sdl_event_filter(void *userdata, SDL_Event *event)
return 0;
}
void rdp_init(void *_window, GFX_INFO _gfx_info, bool _fullscreen, bool _upscale)
void rdp_init(void *_window, GFX_INFO _gfx_info, bool _upscale, bool _integer_scaling, bool _fullscreen)
{
window = (SDL_Window *)_window;
SDL_AddEventWatch(sdl_event_filter, nullptr);
gfx_info = _gfx_info;
fullscreen = _fullscreen;
integer_scaling = _integer_scaling;
bool window_vsync = 0;
wsi = new WSI;
wsi_platform = new SDL_WSIPlatform;
@@ -234,34 +236,42 @@ void rdp_close()
static void calculate_viewport(float *x, float *y, float *width, float *height)
{
bool window_widescreen = false;
int32_t display_width = (window_widescreen ? 854 : 640);
int32_t display_height = 480;
const int32_t display_width = 320;
const int32_t display_height = 240;
int w, h;
SDL_GetWindowSize(window, &w, &h);
*width = w;
*height = h;
*x = 0;
*y = 0;
int32_t hw = display_height * *width;
int32_t wh = display_width * *height;
if (integer_scaling)
{
// Integer scaling path
int scale_x = w / display_width;
int scale_y = h / display_height;
int scale = (scale_x < scale_y) ? scale_x : scale_y;
if (scale < 1)
scale = 1;
// add letterboxes or pillarboxes if the window has a different aspect ratio
// than the current display mode
if (hw > wh)
{
int32_t w_max = wh / display_height;
*x += (*width - w_max) / 2;
*width = w_max;
// Calculate scaled dimensions
int scaled_width = display_width * scale;
int scaled_height = display_height * scale;
*width = scaled_width;
*height = scaled_height;
}
else if (hw < wh)
else
{
int32_t h_max = hw / display_width;
*y += (*height - h_max) / 2;
*height = h_max;
// Regular scaling path - maintain aspect ratio
float scale_x = w / (float)display_width;
float scale_y = h / (float)display_height;
float scale = (scale_x < scale_y) ? scale_x : scale_y;
*width = display_width * scale;
*height = display_height * scale;
}
// Center the viewport
*x = (w - *width) / 2.0f;
*y = (h - *height) / 2.0f;
}
static void render_frame(Vulkan::Device &device)
+1 -1
View File
@@ -23,7 +23,7 @@ extern "C"
uint32_t *VI_WIDTH_REG;
} GFX_INFO;
void rdp_init(void *_window, GFX_INFO _gfx_info, bool _fullscreen, bool _upscale);
void rdp_init(void *_window, GFX_INFO _gfx_info, bool _upscale, bool _integer_scaling, bool _fullscreen);
void rdp_close();
void rdp_set_vi_register(uint32_t reg, uint32_t value);
bool rdp_update_screen();
+2
View File
@@ -21,6 +21,7 @@ pub struct Input {
#[derive(serde::Serialize, serde::Deserialize)]
pub struct Video {
pub upscale: bool,
pub integer_scaling: bool,
pub fullscreen: bool,
}
#[derive(serde::Serialize, serde::Deserialize)]
@@ -48,6 +49,7 @@ impl Config {
},
video: Video {
upscale: false,
integer_scaling: false,
fullscreen: false,
},
}
+39 -27
View File
@@ -14,6 +14,7 @@ pub struct GopherEguiApp {
input_profiles: Vec<String>,
controller_enabled: [bool; 4],
upscale: bool,
integer_scaling: bool,
fullscreen: bool,
emulate_vru: bool,
show_vru_dialog: bool,
@@ -22,6 +23,16 @@ pub struct GopherEguiApp {
vru_word_list: Vec<String>,
}
struct SaveConfig {
selected_controller: [i32; 4],
selected_profile: [String; 4],
controller_enabled: [bool; 4],
upscale: bool,
integer_scaling: bool,
fullscreen: bool,
emulate_vru: bool,
}
fn get_input_profiles(game_ui: &ui::Ui) -> Vec<String> {
let mut profiles = vec![];
for key in game_ui.config.input.input_profiles.keys() {
@@ -85,6 +96,7 @@ impl GopherEguiApp {
input_profiles: get_input_profiles(&game_ui),
controller_enabled: game_ui.config.input.controller_enabled,
upscale: game_ui.config.video.upscale,
integer_scaling: game_ui.config.video.integer_scaling,
fullscreen: game_ui.config.video.fullscreen,
emulate_vru: game_ui.config.input.emulate_vru,
show_vru_dialog: false,
@@ -95,17 +107,9 @@ impl GopherEguiApp {
}
}
fn save_config(
game_ui: &mut ui::Ui,
selected_controller: [i32; 4],
selected_profile: [String; 4],
controller_enabled: [bool; 4],
upscale: bool,
fullscreen: bool,
emulate_vru: bool,
) {
fn save_config(game_ui: &mut ui::Ui, save_config_items: SaveConfig) {
let joystick_subsystem = game_ui.joystick_subsystem.as_ref().unwrap();
for (pos, item) in selected_controller.iter().enumerate() {
for (pos, item) in save_config_items.selected_controller.iter().enumerate() {
if *item != -1 {
game_ui.config.input.controller_assignment[pos] = Some(
joystick_subsystem
@@ -118,26 +122,28 @@ fn save_config(
}
}
game_ui.config.input.input_profile_binding = selected_profile;
game_ui.config.input.controller_enabled = controller_enabled;
game_ui.config.input.input_profile_binding = save_config_items.selected_profile;
game_ui.config.input.controller_enabled = save_config_items.controller_enabled;
game_ui.config.video.fullscreen = fullscreen;
game_ui.config.video.upscale = upscale;
game_ui.config.input.emulate_vru = emulate_vru;
game_ui.config.video.upscale = save_config_items.upscale;
game_ui.config.video.integer_scaling = save_config_items.integer_scaling;
game_ui.config.video.fullscreen = save_config_items.fullscreen;
game_ui.config.input.emulate_vru = save_config_items.emulate_vru;
}
impl Drop for GopherEguiApp {
fn drop(&mut self) {
let mut game_ui = ui::Ui::new(self.config_dir.clone());
save_config(
&mut game_ui,
self.selected_controller,
self.selected_profile.clone(),
self.controller_enabled,
self.upscale,
self.fullscreen,
self.emulate_vru,
);
let save_config_items = SaveConfig {
selected_controller: self.selected_controller,
selected_profile: self.selected_profile.clone(),
controller_enabled: self.controller_enabled,
upscale: self.upscale,
integer_scaling: self.integer_scaling,
fullscreen: self.fullscreen,
emulate_vru: self.emulate_vru,
};
save_config(&mut game_ui, save_config_items);
}
}
@@ -186,6 +192,7 @@ impl eframe::App for GopherEguiApp {
let selected_profile = self.selected_profile.clone();
let controller_enabled = self.controller_enabled;
let upscale = self.upscale;
let integer_scaling = self.integer_scaling;
let fullscreen = self.fullscreen;
let emulate_vru = self.emulate_vru;
let config_dir = self.config_dir.clone();
@@ -221,15 +228,18 @@ impl eframe::App for GopherEguiApp {
panic!("could not create running file: {}", result.err().unwrap())
}
let mut device = device::Device::new(config_dir);
save_config(
&mut device.ui,
let save_config_items = SaveConfig {
selected_controller,
selected_profile,
controller_enabled,
upscale,
integer_scaling,
fullscreen,
emulate_vru,
);
};
save_config(&mut device.ui, save_config_items);
if emulate_vru {
device.vru.window_notifier = Some(vru_window_notifier);
device.vru.word_receiver = Some(vru_word_receiver);
@@ -306,7 +316,9 @@ impl eframe::App for GopherEguiApp {
});
ui.add_space(32.0);
ui.checkbox(&mut self.upscale, "High-Res Graphics");
ui.checkbox(&mut self.integer_scaling, "Integer Scaling");
ui.checkbox(&mut self.fullscreen, "Fullscreen (Esc closes game)");
ui.add_space(32.0);
ui.checkbox(
&mut self.emulate_vru,
"Emulate VRU (connects VRU to controller port 4)",
+2 -1
View File
@@ -38,8 +38,9 @@ pub fn init(device: &mut device::Device, fullscreen: bool) {
rdp_init(
device.ui.window.as_ref().unwrap().raw() as *mut std::ffi::c_void,
gfx_info,
fullscreen,
device.ui.config.video.upscale,
device.ui.config.video.integer_scaling,
fullscreen,
)
}
}