diff --git a/dataobj/environment.cc b/dataobj/environment.cc index fd77a7325..df360a8ab 100644 --- a/dataobj/environment.cc +++ b/dataobj/environment.cc @@ -18,6 +18,7 @@ void rdwr_win_settings(loadsave_t *file); // simwin sint16 env_t::menupos = MENU_TOP; sint16 env_t::fullscreen = WINDOWED; +sint16 env_t::display_scale_percent = 100; bool env_t::reselect_closes_tool = true; sint8 env_t::pak_tile_height_step = 16; @@ -571,6 +572,10 @@ void env_t::rdwr(loadsave_t *file) file->rdwr_short( fullscreen ); } + if( file->is_version_atleast(123, 1) ) { + file->rdwr_short(display_scale_percent); + } + // server settings are not saved, since they are server specific // and could be different on different servers on the same computers } diff --git a/dataobj/environment.h b/dataobj/environment.h index f19cc8709..38ce059d5 100644 --- a/dataobj/environment.h +++ b/dataobj/environment.h @@ -39,6 +39,9 @@ public: static sint16 fullscreen; + /// Controls size of the virtual display + static sint16 display_scale_percent; + static bool reselect_closes_tool; /// points to the current user directory for loading and saving diff --git a/gui/display_settings.cc b/gui/display_settings.cc index bfe2623b9..088e24bf6 100644 --- a/gui/display_settings.cc +++ b/gui/display_settings.cc @@ -95,6 +95,12 @@ gui_settings_t::gui_settings_t() add_table(2,4); set_alignment(ALIGN_LEFT); + // screen scale number input + new_component("Screen scale: "); + screen_scale_numinp.init(dr_get_screen_scale(), 25, 400, 25, false); + screen_scale_numinp.add_listener(this); + add_component(&screen_scale_numinp); + // position of menu new_component("Toolbar position:"); switch (env_t::menupos) { @@ -181,6 +187,17 @@ void gui_settings_t::draw(scr_coord offset) } +bool gui_settings_t::action_triggered(gui_action_creator_t *comp, value_t) +{ + if (comp == &screen_scale_numinp) { + const sint16 new_value = screen_scale_numinp.get_value(); + dr_set_screen_scale(new_value); + } + + return true; +} + + map_settings_t::map_settings_t() { set_table_layout( 1, 0 ); diff --git a/gui/display_settings.h b/gui/display_settings.h index ee7a9d592..4ec318143 100644 --- a/gui/display_settings.h +++ b/gui/display_settings.h @@ -16,12 +16,15 @@ #include "components/gui_combobox.h" #include "components/gui_tab_panel.h" + /** * Menu with display settings */ -class gui_settings_t : public gui_aligned_container_t +class gui_settings_t : public gui_aligned_container_t, public action_listener_t { private: + gui_numberinput_t screen_scale_numinp; + gui_label_buf_t frame_time_value_label, idle_time_value_label, @@ -32,9 +35,12 @@ public: button_t toolbar_pos, reselect_closes_tool, fullscreen, borderless; gui_settings_t(); + void draw( scr_coord offset ) OVERRIDE; + bool action_triggered( gui_action_creator_t *comp, value_t v) OVERRIDE; }; + class map_settings_t : public gui_aligned_container_t, public action_listener_t { private: diff --git a/simmain.cc b/simmain.cc index f40dcd4a6..c30c871f0 100644 --- a/simmain.cc +++ b/simmain.cc @@ -393,7 +393,9 @@ void print_help() " -server [PORT] starts program as server (for network game)\n" " without port specified uses 13353\n" " -announce Enable server announcements\n" - " -autodpi Scale for high DPI screens\n" + " -autodpi Automatic screen scaling for high DPI screens\n" + " -screen_scale N Manual screen scaling to N percent (0=off)\n" + " Ignored when -autodpi is specified\n" " -server_dns FQDN/IP FQDN or IP address of server for announcements\n" " -server_name NAME Name of server for announcements\n" " -server_admin_pw PW password for server administration\n" @@ -803,7 +805,12 @@ int simu_main(int argc, char** argv) } if( args.has_arg("-autodpi") ) { - dr_auto_scale( true ); + dr_set_screen_scale( -1 ); + } + else if (const char *scaling = args.gimme_arg("-screen_scale", 1)) { + if (scaling[0] >= '0' && scaling[0] <= '9') { + dr_set_screen_scale(atoi(scaling)); + } } int parameter[2]; diff --git a/simutrans/history.txt b/simutrans/history.txt index d0e00dae8..d26817b46 100644 --- a/simutrans/history.txt +++ b/simutrans/history.txt @@ -1,7 +1,8 @@ FIX: up/down arrows in schedule broken FIX: Simulation speeds up uncontrollably in some cases if New World dialogue is open - CHG: lang files are laoded if their name is *XX.tab or XX*.tab The first is preferred to avoid confusion by name like ja-taken.tab + CHG: lang files are loaded if their name is *XX.tab or XX*.tab. The first is preferred to avoid confusion by name like ja-taken.tab ADD: selected convoi in minimap now magenta. Also network display properly updated when activating or closing windows + ADD: Option to adjust screen scaling manually (either via display settings or '-screen_scale' command line option) Release of 123.0 (r10137 on 30-Dec-2021): diff --git a/sys/simsys.h b/sys/simsys.h index 0baad2eee..2a47fb4b0 100644 --- a/sys/simsys.h +++ b/sys/simsys.h @@ -71,8 +71,18 @@ extern sys_event_t sys_event; extern char const PATH_SEPARATOR[]; -// scale according to dpi setting -bool dr_auto_scale(bool); + +/// @param scale_percent +/// Possible values: +/// -1: auto (scale according to screen DPI setting) +/// 0: off (default 1:1 scale) +/// other: specific scaling, in percent +/// < -1: invalid +bool dr_set_screen_scale(sint16 scale_percent); + +/// @returns Relative size of the virtual display, in percent +sint16 dr_get_screen_scale(); + bool dr_os_init(int const* parameter); diff --git a/sys/simsys_posix.cc b/sys/simsys_posix.cc index 5959765b4..72b7c812f 100644 --- a/sys/simsys_posix.cc +++ b/sys/simsys_posix.cc @@ -29,12 +29,19 @@ static bool sigterm_received = false; #error "Posix only compiles with color depth=0" #endif -// no autoscaling as we have no display ... -bool dr_auto_scale(bool) +bool dr_set_screen_scale(sint16) { + // no autoscaling as we have no display ... return false; } + +sint16 dr_get_screen_scale() +{ + return 100; +} + + bool dr_os_init(const int*) { // prepare for next event diff --git a/sys/simsys_s.cc b/sys/simsys_s.cc index ea74b1e26..879596c3c 100644 --- a/sys/simsys_s.cc +++ b/sys/simsys_s.cc @@ -146,7 +146,7 @@ sint32 y_scale = SCALE_NEUTRAL_Y; #define SCREEN_RESCALE_Y(y) (((y) * SCALE_NEUTRAL_Y) / y_scale) // no autoscaling yet -bool dr_auto_scale(bool) +bool dr_set_screen_scale(sint16 /*scale_percent*/) { #ifdef __ANDROID__ // SDL 1.2 does not support scaling, but the libSDL Android rendering layer @@ -179,6 +179,13 @@ bool dr_auto_scale(bool) #endif } + +sint16 dr_get_screen_scale() +{ + return 100; +} + + /* * Hier sind die Basisfunktionen zur Initialisierung der * Schnittstelle untergebracht diff --git a/sys/simsys_s2.cc b/sys/simsys_s2.cc index 6a3c26510..b4fa9b608 100644 --- a/sys/simsys_s2.cc +++ b/sys/simsys_s2.cc @@ -152,11 +152,13 @@ sint32 y_scale = SCALE_NEUTRAL_Y; bool has_soft_keyboard = false; -// no autoscaling yet -bool dr_auto_scale(bool on_off ) +bool dr_set_screen_scale(sint16 scale_percent) { + const sint32 old_x_scale = x_scale; + const sint32 old_y_scale = y_scale; + + if( scale_percent == -1 ) { #if SDL_VERSION_ATLEAST(2,0,4) - if( on_off ) { float hdpi, vdpi; SDL_Init( SDL_INIT_VIDEO ); SDL_DisplayMode mode; @@ -178,22 +180,48 @@ bool dr_auto_scale(bool on_off ) y_scale = (y_scale * current_y) / MIN_SCALE_HEIGHT; DBG_MESSAGE("new scaling", "x=%i, y=%i", x_scale, y_scale); } - - return x_scale==SCALE_NEUTRAL_X && y_scale==SCALE_NEUTRAL_Y; - } - else #else #pragma message "SDL version must be at least 2.0.4 to support autoscaling." -#endif - { // 1.5 scale up by default - x_scale = (3*SCALE_NEUTRAL_X)/2; - y_scale = (3*SCALE_NEUTRAL_Y)/2; - (void)on_off; - return false; + x_scale = (150*SCALE_NEUTRAL_X)/100; + y_scale = (150*SCALE_NEUTRAL_Y)/100; +#endif + } + else if (scale_percent == 0) { + x_scale = SCALE_NEUTRAL_X; + y_scale = SCALE_NEUTRAL_Y; } + else { + x_scale = (scale_percent*SCALE_NEUTRAL_X)/100; + y_scale = (scale_percent*SCALE_NEUTRAL_Y)/100; + } + + if (x_scale != old_x_scale || y_scale != old_y_scale) { + // force window resize + int w, h; + SDL_GetWindowSize(window, &w, &h); + + SDL_Event ev; + ev.type = SDL_WINDOWEVENT; + ev.window.event = SDL_WINDOWEVENT_SIZE_CHANGED; + ev.window.data1 = w; + ev.window.data2 = h; + + if (SDL_PushEvent(&ev) != 1) { + return false; + } + } + + return true; +} + + +sint16 dr_get_screen_scale() +{ + return (x_scale*100)/SCALE_NEUTRAL_X; } + static int SDLCALL my_event_filter(void* /*userdata*/, SDL_Event* event) { DBG_MESSAGE("my_event_filter", "%i", event->type); @@ -369,6 +397,10 @@ bool internal_create_surfaces(int tex_width, int tex_height) DBG_DEBUG( "internal_create_surfaces(SDL2)", "Using: Renderer: %s, Max_w: %d, Max_h: %d, Flags: %d, Formats: %d, %s", ri.name, ri.max_texture_width, ri.max_texture_height, ri.flags, ri.num_texture_formats, SDL_GetPixelFormatName(pixel_format) ); + // Non-integer scaling -> enable bilinear filtering (must be done before texture creation) + const bool integer_scaling = (x_scale & (SCALE_NEUTRAL_X - 1)) == 0 && (y_scale & (SCALE_NEUTRAL_Y - 1)) == 0; + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, integer_scaling ? "0" : "1" ); // 0=none, 1=bilinear, 2=anisotropic (DirectX only) + screen_tx = SDL_CreateTexture( renderer, pixel_format, SDL_TEXTUREACCESS_STREAMING, tex_width, tex_height ); if( screen_tx == NULL ) { dbg->error( "internal_create_surfaces(SDL2)", "Couldn't create texture: %s", SDL_GetError() ); @@ -402,8 +434,8 @@ int dr_os_open(int screen_width, int screen_height, sint16 fs) { // scale up resolution res = dr_query_screen_resolution(); - const int tex_w = min( res.w, SCREEN_TO_TEX_X(screen_width) ); - const int tex_h = min( res.h, SCREEN_TO_TEX_Y(screen_height) ); + const int tex_w = clamp( res.w, 1, SCREEN_TO_TEX_X(screen_width) ); + const int tex_h = clamp( res.h, 1, SCREEN_TO_TEX_Y(screen_height) ); DBG_MESSAGE("dr_os_open()", "Screen requested %i,%i, available max %i,%i", tex_w, tex_h, res.w, res.h); @@ -411,7 +443,7 @@ int dr_os_open(int screen_width, int screen_height, sint16 fs) // some cards need those alignments // especially 64bit want a border of 8bytes - const int tex_pitch = max((tex_w + 15) & 0x7FF0, 16); + const int tex_pitch = (tex_w + 15) & 0x7FF0; // SDL2 only works with borderless fullscreen (SDL_WINDOW_FULLSCREEN_DESKTOP) Uint32 flags = fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_RESIZABLE; @@ -423,11 +455,6 @@ int dr_os_open(int screen_width, int screen_height, sint16 fs) return 0; } - // Non-integer scaling -> enable bilinear filtering (must be done before texture creation) - if ((x_scale & (SCALE_NEUTRAL_X - 1)) != 0 || (y_scale & (SCALE_NEUTRAL_Y - 1)) != 0) { - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"); // 0=none, 1=bilinear, 2=anisotropic (DirectX only) - } - if( !internal_create_surfaces( tex_pitch, tex_h ) ) { return 0; } @@ -648,8 +675,8 @@ static void internal_GetEvents() case SDL_WINDOWEVENT: if( event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED ) { - sys_event.new_window_size_w = SCREEN_TO_TEX_X(event.window.data1); - sys_event.new_window_size_h = SCREEN_TO_TEX_Y(event.window.data2); + sys_event.new_window_size_w = max(1, SCREEN_TO_TEX_X(event.window.data1)); + sys_event.new_window_size_h = max(1, SCREEN_TO_TEX_Y(event.window.data2)); sys_event.type = SIM_SYSTEM; sys_event.code = SYSTEM_RESIZE; } diff --git a/sys/simsys_w.cc b/sys/simsys_w.cc index b9972a265..36e5d8f1c 100644 --- a/sys/simsys_w.cc +++ b/sys/simsys_w.cc @@ -86,9 +86,9 @@ static long y_scale = 32; // scale automatically -bool dr_auto_scale(bool on_off) +bool dr_set_screen_scale(sint16 percent) { - if( on_off ) { + if( percent == -1 ) { HDC hdc = GetDC(NULL); if (hdc) { x_scale = (GetDeviceCaps(hdc, LOGPIXELSX)*32)/96; @@ -97,11 +97,30 @@ bool dr_auto_scale(bool on_off) } return true; } - else { - x_scale = 32; - y_scale = 32; + else if (percent == 0) { + percent = 100; + } + else if (percent < 0) { + dbg->error("dr_set_screen_scale(Win32)", "Invalid screen scaling %d (Must be >= -1)", percent); + return false; + } + + x_scale = (percent * 32) / 100; + y_scale = (percent * 32) / 100; + + // force window size update + const LRESULT res = SendMessage(hwnd, WM_SIZE, SIZE_RESTORED, MAKELPARAM(WindowSize.right-WindowSize.left, WindowSize.bottom-WindowSize.top)); + if (res != 0) { return false; } + + return true; +} + + +sint16 dr_get_screen_scale() +{ + return (x_scale * 100) / 32; }