@@ -705,20 +705,18 @@ int openttd_main(int argc, char *argv[])
#endif
LoadFromConfig(true);
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.
* Saying the cursor is there makes no visible difference as it would
* just be out of the bounds of the window. */
_cursor.in_window = true;
@@ -117,13 +117,13 @@ cat = SC_BASIC
; workaround for implicit lengthof() in SDTG_LIST
[SDTG_LIST]
name = ""resolution""
type = SLE_INT
length = 2
var = _cur_resolution
def = ""640,480""
def = ""0,0""
cat = SC_BASIC
[SDTG_STR]
name = ""screenshot_format""
type = SLE_STRB
var = _screenshot_format_name
@@ -414,12 +414,14 @@ const char *VideoDriver_Allegro::Start(c
if (_allegro_instance_count == 0 && install_allegro(SYSTEM_AUTODETECT, &errno, nullptr)) {
DEBUG(driver, 0, "allegro: install_allegro failed '%s'", allegro_error);
return "Failed to set up Allegro";
}
_allegro_instance_count++;
this->UpdateAutoResolution();
install_timer();
install_mouse();
install_keyboard();
#if defined _DEBUG
/* Allegro replaces SEGV/ABRT signals meaning that the debugger will never
@@ -67,12 +67,15 @@ public:
/* --- The following methods should be private, but can't be due to Obj-C limitations. --- */
/** Main game loop. */
void GameLoop(); // In event.mm.
protected:
Dimension GetScreenSize() const override;
private:
friend class WindowQuartzSubdriver;
void GameSizeChanged();
};
@@ -197,12 +197,14 @@ const char *VideoDriver_Cocoa::Start(con
if (_cocoa_video_started) return "Already started";
_cocoa_video_started = true;
/* Don't create a window or enter fullscreen if we're just going to show a dialog. */
if (!CocoaSetupApplication()) return NULL;
this->orig_res = _cur_resolution;
int width = _cur_resolution.width;
int height = _cur_resolution.height;
int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
if (bpp != 8 && bpp != 32) {
@@ -300,12 +302,21 @@ void VideoDriver_Cocoa::EditBoxLostFocus
if (_cocoa_subdriver != NULL) [ [ _cocoa_subdriver->cocoaview inputContext ] discardMarkedText ];
/* Clear any marked string from the current edit box. */
HandleTextInput(NULL, true);
/**
* Get the resolution of the main screen.
Dimension VideoDriver_Cocoa::GetScreenSize() const
{
NSRect frame = [ [ NSScreen mainScreen ] frame ];
return { static_cast<uint>(NSWidth(frame)), static_cast<uint>(NSHeight(frame)) };
* Handle a change of the display area.
void VideoDriver_Cocoa::GameSizeChanged()
if (_cocoa_subdriver == nullptr) return;
@@ -132,12 +132,14 @@ extern bool SafeLoad(const std::string &
static FVideoDriver_Dedicated iFVideoDriver_Dedicated;
const char *VideoDriver_Dedicated::Start(const StringList &parm)
_dedicated_video_mem = (bpp == 0) ? nullptr : MallocT<byte>(_cur_resolution.width * _cur_resolution.height * (bpp / 8));
_screen.width = _screen.pitch = _cur_resolution.width;
_screen.height = _cur_resolution.height;
_screen.dst_ptr = _dedicated_video_mem;
@@ -21,12 +21,14 @@ const char *VideoDriver_Null::Start(cons
#ifdef _MSC_VER
/* Disable the MSVC assertion message box. */
_set_error_mode(_OUT_TO_STDERR);
this->ticks = GetDriverParamInt(parm, "ticks", 1000);
_screen.dst_ptr = nullptr;
ScreenSizeChanged();
@@ -671,12 +671,14 @@ const char *VideoDriver_SDL::Start(const
int ret_code = 0;
if (SDL_WasInit(SDL_INIT_VIDEO) == 0) {
ret_code = SDL_InitSubSystem(SDL_INIT_VIDEO);
if (ret_code < 0) return SDL_GetError();
GetVideoModes();
if (!CreateMainSurface(_cur_resolution.width, _cur_resolution.height, false)) {
return SDL_GetError();
const char *dname = SDL_GetCurrentVideoDriver();
@@ -927,7 +929,15 @@ void VideoDriver_SDL::AcquireBlitterLock
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<uint>(mode.w), static_cast<uint>(mode.h) };
#endif /* WITH_SDL2 */
@@ -37,12 +37,16 @@ public:
void EditBoxGainedFocus() override;
void EditBoxLostFocus() override;
const char *GetName() const override { return "sdl"; }
int PollEvent();
void LoopOnce();
void MainLoopCleanup();
bool CreateMainSurface(uint w, uint h, bool resize);
@@ -611,12 +611,14 @@ const char *VideoDriver_SDL::Start(const
ret_code = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE);
} else if (SDL_WasInit(SDL_INIT_VIDEO) == 0) {
if (!CreateMainSurface(_cur_resolution.width, _cur_resolution.height)) {
SDL_VideoDriverName(buf, sizeof buf);
@@ -9,16 +9,25 @@
#ifndef VIDEO_VIDEO_DRIVER_HPP
#define VIDEO_VIDEO_DRIVER_HPP
#include "../driver.h"
#include "../core/geometry_type.hpp"
#include "../core/math_func.hpp"
#include <vector>
extern std::string _ini_videodriver;
extern std::vector<Dimension> _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.
* @param left The left most line of the dirty area.
* @param top The top most line of the dirty area.
* @param width The width of the dirty area.
@@ -99,14 +108,30 @@ public:
* Get the currently active instance of the video driver.
static VideoDriver *GetInstance() {
return static_cast<VideoDriver*>(*DriverFactoryBase::GetActiveDriver(Driver::DT_VIDEO));
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);
#endif /* VIDEO_VIDEO_DRIVER_HPP */
@@ -1111,12 +1111,14 @@ static void FindResolutions()
static FVideoDriver_Win32 iFVideoDriver_Win32;
const char *VideoDriver_Win32::Start(const StringList &parm)
memset(&_wnd, 0, sizeof(_wnd));
RegisterWndClass();
MakePalette();
@@ -1340,6 +1342,11 @@ void VideoDriver_Win32::EditBoxLostFocus
if (_draw_mutex != nullptr) lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
CancelIMEComposition(_wnd.main_wnd);
SetCompositionPos(_wnd.main_wnd);
SetCandidatePos(_wnd.main_wnd);
Dimension VideoDriver_Win32::GetScreenSize() const
return { static_cast<uint>(GetSystemMetrics(SM_CXSCREEN)), static_cast<uint>(GetSystemMetrics(SM_CYSCREEN)) };
@@ -37,12 +37,15 @@ public:
const char *GetName() const override { return "win32"; }
bool MakeWindow(bool full_screen);
/** The factory for Windows' video driver. */
class FVideoDriver_Win32 : public DriverFactoryBase {
FVideoDriver_Win32() : DriverFactoryBase(Driver::DT_VIDEO, 10, "win32", "Win32 GDI Video Driver") {}
Status change: