diff --git a/src/openttd.cpp b/src/openttd.cpp --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -708,14 +708,12 @@ int openttd_main(int argc, char *argv[]) if (resolution.width != 0) _cur_resolution = resolution; - /* - * The width and height must be at least 1 pixel and width times - * height times bytes per pixel must still fit within a 32 bits - * integer, even for 32 bpp video modes. This way all internal - * drawing routines work correctly. - */ - _cur_resolution.width = ClampU(_cur_resolution.width, 1, UINT16_MAX / 2); - _cur_resolution.height = ClampU(_cur_resolution.height, 1, UINT16_MAX / 2); + /* Limit width times height times bytes per pixel to fit a 32 bit + * integer, This way all internal drawing routines work correctly. + * A resolution that has one component as 0 is treated as a marker to + * auto-detect a good window size. */ + _cur_resolution.width = std::min(_cur_resolution.width, UINT16_MAX / 2u); + _cur_resolution.height = std::min(_cur_resolution.height, UINT16_MAX / 2u); /* Assume the cursor starts within the game as not all video drivers * get an event that the cursor is within the window when it is opened. diff --git a/src/table/misc_settings.ini b/src/table/misc_settings.ini --- a/src/table/misc_settings.ini +++ b/src/table/misc_settings.ini @@ -120,7 +120,7 @@ name = ""resolution"" type = SLE_INT length = 2 var = _cur_resolution -def = ""640,480"" +def = ""0,0"" cat = SC_BASIC [SDTG_STR] diff --git a/src/video/allegro_v.cpp b/src/video/allegro_v.cpp --- a/src/video/allegro_v.cpp +++ b/src/video/allegro_v.cpp @@ -417,6 +417,8 @@ const char *VideoDriver_Allegro::Start(c } _allegro_instance_count++; + this->UpdateAutoResolution(); + install_timer(); install_mouse(); install_keyboard(); diff --git a/src/video/cocoa/cocoa_v.h b/src/video/cocoa/cocoa_v.h --- a/src/video/cocoa/cocoa_v.h +++ b/src/video/cocoa/cocoa_v.h @@ -70,6 +70,9 @@ public: /** Main game loop. */ void GameLoop(); // In event.mm. +protected: + Dimension GetScreenSize() const override; + private: friend class WindowQuartzSubdriver; diff --git a/src/video/cocoa/cocoa_v.mm b/src/video/cocoa/cocoa_v.mm --- a/src/video/cocoa/cocoa_v.mm +++ b/src/video/cocoa/cocoa_v.mm @@ -200,6 +200,8 @@ const char *VideoDriver_Cocoa::Start(con /* Don't create a window or enter fullscreen if we're just going to show a dialog. */ if (!CocoaSetupApplication()) return NULL; + this->UpdateAutoResolution(); + this->orig_res = _cur_resolution; int width = _cur_resolution.width; int height = _cur_resolution.height; @@ -303,6 +305,15 @@ void VideoDriver_Cocoa::EditBoxLostFocus } /** + * Get the resolution of the main screen. + */ +Dimension VideoDriver_Cocoa::GetScreenSize() const +{ + NSRect frame = [ [ NSScreen mainScreen ] frame ]; + return { static_cast(NSWidth(frame)), static_cast(NSHeight(frame)) }; +} + +/** * Handle a change of the display area. */ void VideoDriver_Cocoa::GameSizeChanged() diff --git a/src/video/dedicated_v.cpp b/src/video/dedicated_v.cpp --- a/src/video/dedicated_v.cpp +++ b/src/video/dedicated_v.cpp @@ -135,6 +135,8 @@ static FVideoDriver_Dedicated iFVideoDri const char *VideoDriver_Dedicated::Start(const StringList &parm) { + this->UpdateAutoResolution(); + int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); _dedicated_video_mem = (bpp == 0) ? nullptr : MallocT(_cur_resolution.width * _cur_resolution.height * (bpp / 8)); diff --git a/src/video/null_v.cpp b/src/video/null_v.cpp --- a/src/video/null_v.cpp +++ b/src/video/null_v.cpp @@ -24,6 +24,8 @@ const char *VideoDriver_Null::Start(cons _set_error_mode(_OUT_TO_STDERR); #endif + this->UpdateAutoResolution(); + this->ticks = GetDriverParamInt(parm, "ticks", 1000); _screen.width = _screen.pitch = _cur_resolution.width; _screen.height = _cur_resolution.height; diff --git a/src/video/sdl2_v.cpp b/src/video/sdl2_v.cpp --- a/src/video/sdl2_v.cpp +++ b/src/video/sdl2_v.cpp @@ -674,6 +674,8 @@ const char *VideoDriver_SDL::Start(const } if (ret_code < 0) return SDL_GetError(); + this->UpdateAutoResolution(); + GetVideoModes(); if (!CreateMainSurface(_cur_resolution.width, _cur_resolution.height, false)) { return SDL_GetError(); @@ -930,4 +932,12 @@ void VideoDriver_SDL::ReleaseBlitterLock if (_draw_mutex != nullptr) _draw_mutex->unlock(); } +Dimension VideoDriver_SDL::GetScreenSize() const +{ + SDL_DisplayMode mode; + if (SDL_GetCurrentDisplayMode(0, &mode) != 0) return VideoDriver::GetScreenSize(); + + return { static_cast(mode.w), static_cast(mode.h) }; +} + #endif /* WITH_SDL2 */ diff --git a/src/video/sdl2_v.h b/src/video/sdl2_v.h --- a/src/video/sdl2_v.h +++ b/src/video/sdl2_v.h @@ -40,6 +40,10 @@ public: void EditBoxLostFocus() override; const char *GetName() const override { return "sdl"; } + +protected: + Dimension GetScreenSize() const override; + private: int PollEvent(); void LoopOnce(); diff --git a/src/video/sdl_v.cpp b/src/video/sdl_v.cpp --- a/src/video/sdl_v.cpp +++ b/src/video/sdl_v.cpp @@ -614,6 +614,8 @@ const char *VideoDriver_SDL::Start(const } if (ret_code < 0) return SDL_GetError(); + this->UpdateAutoResolution(); + GetVideoModes(); if (!CreateMainSurface(_cur_resolution.width, _cur_resolution.height)) { return SDL_GetError(); diff --git a/src/video/video_driver.hpp b/src/video/video_driver.hpp --- a/src/video/video_driver.hpp +++ b/src/video/video_driver.hpp @@ -12,10 +12,19 @@ #include "../driver.h" #include "../core/geometry_type.hpp" +#include "../core/math_func.hpp" #include +extern std::string _ini_videodriver; +extern std::vector _resolutions; +extern Dimension _cur_resolution; +extern bool _rightclick_emulate; + /** The base of all video drivers. */ class VideoDriver : public Driver { + const uint DEFAULT_WINDOW_WIDTH = 640u; ///< Default window width. + const uint DEFAULT_WINDOW_HEIGHT = 480u; ///< Default window height. + public: /** * Mark a particular area dirty. @@ -102,11 +111,27 @@ public: static VideoDriver *GetInstance() { return static_cast(*DriverFactoryBase::GetActiveDriver(Driver::DT_VIDEO)); } + +protected: + /* + * Get the resolution of the main screen. + */ + virtual Dimension GetScreenSize() const { return { DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT }; } + + /** + * Apply resolution auto-detection and clamp to sensible defaults. + */ + void UpdateAutoResolution() + { + if (_cur_resolution.width == 0 || _cur_resolution.height == 0) { + /* Auto-detect a good resolution. We aim for 75% of the screen size. + * Limit width times height times bytes per pixel to fit a 32 bit + * integer, This way all internal drawing routines work correctly. */ + Dimension res = this->GetScreenSize(); + _cur_resolution.width = ClampU(res.width * 3 / 4, DEFAULT_WINDOW_WIDTH, UINT16_MAX / 2); + _cur_resolution.height = ClampU(res.height * 3 / 4, DEFAULT_WINDOW_HEIGHT, UINT16_MAX / 2); + } + } }; -extern std::string _ini_videodriver; -extern std::vector _resolutions; -extern Dimension _cur_resolution; -extern bool _rightclick_emulate; - #endif /* VIDEO_VIDEO_DRIVER_HPP */ diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -1114,6 +1114,8 @@ static FVideoDriver_Win32 iFVideoDriver_ const char *VideoDriver_Win32::Start(const StringList &parm) { + this->UpdateAutoResolution(); + memset(&_wnd, 0, sizeof(_wnd)); RegisterWndClass(); @@ -1343,3 +1345,8 @@ void VideoDriver_Win32::EditBoxLostFocus SetCompositionPos(_wnd.main_wnd); SetCandidatePos(_wnd.main_wnd); } + +Dimension VideoDriver_Win32::GetScreenSize() const +{ + return { static_cast(GetSystemMetrics(SM_CXSCREEN)), static_cast(GetSystemMetrics(SM_CYSCREEN)) }; +} diff --git a/src/video/win32_v.h b/src/video/win32_v.h --- a/src/video/win32_v.h +++ b/src/video/win32_v.h @@ -40,6 +40,9 @@ public: const char *GetName() const override { return "win32"; } bool MakeWindow(bool full_screen); + +protected: + Dimension GetScreenSize() const override; }; /** The factory for Windows' video driver. */