30#include <versionhelpers.h>
31#if defined(_MSC_VER) && defined(NTDDI_WIN10_RS4)
32#include <winrt/Windows.UI.ViewManagement.h>
37#include "../3rdparty/opengl/glext.h"
38#include "../3rdparty/opengl/wglext.h"
45#ifndef MAPVK_VK_TO_CHAR
46#define MAPVK_VK_TO_CHAR (2)
50#define PM_QS_INPUT 0x20000
54#define WM_DPICHANGED 0x02E0
65 MyShowCursor(
false,
true);
74#define AS(x, z) {x, 1, z}
75#define AM(x, y, z, w) {x, y - x + 1, z}
79 AM(VK_PRIOR, VK_DOWN, WKC_PAGEUP, WKC_DOWN),
81 AM(
'A',
'Z',
'A',
'Z'),
82 AM(
'0',
'9',
'0',
'9'),
84 AS(VK_ESCAPE, WKC_ESC),
85 AS(VK_PAUSE, WKC_PAUSE),
86 AS(VK_BACK, WKC_BACKSPACE),
87 AM(VK_INSERT, VK_DELETE, WKC_INSERT, WKC_DELETE),
89 AS(VK_SPACE, WKC_SPACE),
90 AS(VK_RETURN, WKC_RETURN),
94 AM(VK_F1, VK_F12, WKC_F1, WKC_F12),
97 AM(VK_NUMPAD0, VK_NUMPAD9,
'0',
'9'),
98 AS(VK_DIVIDE, WKC_NUM_DIV),
99 AS(VK_MULTIPLY, WKC_NUM_MUL),
100 AS(VK_SUBTRACT, WKC_NUM_MINUS),
101 AS(VK_ADD, WKC_NUM_PLUS),
102 AS(VK_DECIMAL, WKC_NUM_DECIMAL),
118static uint MapWindowsKey(uint sym)
122 for (
const auto &map : _vk_mapping) {
123 if (
IsInsideBS(sym, map.vk_from, map.vk_count)) {
124 key = sym - map.vk_from + map.map_to;
129 if (GetAsyncKeyState(VK_SHIFT) < 0) key |= WKC_SHIFT;
130 if (GetAsyncKeyState(VK_CONTROL) < 0) key |= WKC_CTRL;
131 if (GetAsyncKeyState(VK_MENU) < 0) key |= WKC_ALT;
155 _fullscreen = full_screen;
175 if (
settings.dmBitsPerPel == 8 && ChangeDisplaySettings(&
settings, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL) {
180 if (ChangeDisplaySettings(&
settings, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL) {
182 GetWindowRect(GetDesktopWindow(), &r);
185 if ((
int)
settings.dmPelsWidth != r.right - r.left || (
int)
settings.dmPelsHeight != r.bottom - r.top) {
190 if (ChangeDisplaySettings(&
settings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
196 ChangeDisplaySettings(
nullptr, 0);
198 this->
width = _bck_resolution.width;
199 this->
height = _bck_resolution.height;
204 DWORD style, showstyle;
207 showstyle = SW_SHOWNORMAL;
213 style = WS_OVERLAPPEDWINDOW;
215 if (_window_maximize) showstyle = SW_SHOWMAXIMIZED;
219 AdjustWindowRect(&r, style, FALSE);
220 w = r.right - r.left;
221 h = r.bottom - r.top;
224 if (!_window_maximize && resize) SetWindowPos(this->
main_wnd, 0, 0, 0, w, h, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE);
232 mi.cbSize =
sizeof(mi);
233 GetMonitorInfo(MonitorFromWindow(0, MONITOR_DEFAULTTOPRIMARY), &mi);
235 x = (mi.rcWork.right - mi.rcWork.left - w) / 2;
236 y = (mi.rcWork.bottom - mi.rcWork.top - h) / 2;
240 this->
main_wnd = CreateWindow(L
"OTTD",
OTTD2FS(caption).c_str(), style, x, y, w, h, 0, 0, GetModuleHandle(
nullptr),
this);
241 if (this->
main_wnd ==
nullptr) UserError(
"CreateWindow failed");
242 ShowWindow(this->
main_wnd, showstyle);
260 static char32_t prev_char = 0;
264 if (prev_char != 0)
Debug(driver, 1,
"Got two UTF-16 lead surrogates, dropping the first one");
265 prev_char = charcode;
270 if (prev_char != 0) {
274 Debug(driver, 1,
"Got an UTF-16 lead surrogate without a trail surrogate, dropping the lead surrogate");
290 return (_imm_props & IME_PROP_AT_CARET) && !(_imm_props & IME_PROP_SPECIAL_UI);
299 HIMC hIMC = ImmGetContext(hwnd);
300 if (hIMC !=
nullptr) {
302 cf.dwStyle = CFS_POINT;
310 cf.ptCurrentPos.x = 0;
311 cf.ptCurrentPos.y = 0;
313 ImmSetCompositionWindow(hIMC, &cf);
315 ImmReleaseContext(hwnd, hIMC);
324 HIMC hIMC = ImmGetContext(hwnd);
325 if (hIMC !=
nullptr) {
328 cf.dwStyle = CFS_EXCLUDE;
342 cf.rcArea.right = cf.rcArea.left +
_focused_window->nested_focus->current_x;
343 cf.rcArea.bottom = cf.rcArea.top +
_focused_window->nested_focus->current_y;
346 cf.ptCurrentPos.x = 0;
347 cf.ptCurrentPos.y = 0;
348 SetRectEmpty(&cf.rcArea);
350 ImmSetCandidateWindow(hIMC, &cf);
352 ImmReleaseContext(hwnd, hIMC);
364 HIMC hIMC = ImmGetContext(hwnd);
366 if (hIMC !=
nullptr) {
367 if (lParam & GCS_RESULTSTR) {
369 LONG len = ImmGetCompositionString(hIMC, GCS_RESULTSTR,
nullptr, 0);
370 std::wstring str(len + 1, L
'\0');
371 len = ImmGetCompositionString(hIMC, GCS_RESULTSTR, str.data(), len);
372 str[len /
sizeof(wchar_t)] = L
'\0';
382 lParam &= ~(GCS_RESULTSTR | GCS_RESULTCLAUSE | GCS_RESULTREADCLAUSE | GCS_RESULTREADSTR);
387 LONG len = ImmGetCompositionString(hIMC, GCS_COMPSTR,
nullptr, 0);
388 std::wstring str(len + 1, L
'\0');
389 len = ImmGetCompositionString(hIMC, GCS_COMPSTR, str.data(), len);
390 str[len /
sizeof(wchar_t)] = L
'\0';
393 static char utf8_buf[1024];
397 LONG caret_bytes = ImmGetCompositionString(hIMC, GCS_CURSORPOS,
nullptr, 0);
399 auto caret = view.begin();
400 const auto end = view.end();
401 for (
const wchar_t *c = str.c_str(); *c !=
'\0' && caret != end && caret_bytes > 0; c++, caret_bytes--) {
415 lParam &= ~(GCS_COMPSTR | GCS_COMPATTR | GCS_COMPCLAUSE | GCS_CURSORPOS | GCS_DELTASTART);
418 ImmReleaseContext(hwnd, hIMC);
420 return lParam != 0 ? DefWindowProc(hwnd, WM_IME_COMPOSITION, wParam, lParam) : 0;
429 HIMC hIMC = ImmGetContext(hwnd);
430 if (hIMC !=
nullptr) ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
431 ImmReleaseContext(hwnd, hIMC);
436#if defined(_MSC_VER) && defined(NTDDI_WIN10_RS4)
444extern "C" int32_t __stdcall WINRT_IMPL_RoOriginateLanguageException(int32_t error,
void *message,
void *languageException)
noexcept
446 typedef BOOL(WINAPI *PFNRoOriginateLanguageException)(int32_t,
void *,
void *);
447 static PFNRoOriginateLanguageException RoOriginateLanguageException = _combase.GetFunction(
"RoOriginateLanguageException");
449 if (RoOriginateLanguageException !=
nullptr) {
450 return RoOriginateLanguageException(error, message, languageException);
456extern "C" int32_t __stdcall WINRT_IMPL_RoGetActivationFactory(
void *classId, winrt::guid
const &iid,
void **factory)
noexcept
458 typedef BOOL(WINAPI *PFNRoGetActivationFactory)(
void *, winrt::guid
const &,
void **);
459 static PFNRoGetActivationFactory RoGetActivationFactory = _combase.GetFunction(
"RoGetActivationFactory");
461 if (RoGetActivationFactory !=
nullptr) {
462 return RoGetActivationFactory(classId, iid, factory);
465 return winrt::impl::error_class_not_available;
470static bool IsDarkModeEnabled()
473#if defined(_MSC_VER) && defined(NTDDI_WIN10_RS4)
474 if (IsWindows10OrGreater()) {
484 winrt::Windows::UI::ViewManagement::UISettings
settings;
485 auto foreground =
settings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::Foreground);
488 return ((5 * foreground.G) + (2 * foreground.R) + foreground.B) > (8 * 128);
499static void SetDarkModeForWindow(HWND hWnd,
bool dark_mode)
502#if defined(NTDDI_WIN10)
503 if (!IsWindows10OrGreater())
return;
508 typedef HRESULT(WINAPI *PFNDWMSETWINDOWATTRIBUTE)(HWND, DWORD, LPCVOID, DWORD);
509 static const PFNDWMSETWINDOWATTRIBUTE DwmSetWindowAttribute = _dwmapi.GetFunction(
"DwmSetWindowAttribute");
511 if (DwmSetWindowAttribute !=
nullptr) {
515 BOOL value = dark_mode ? TRUE : FALSE;
516 if (DwmSetWindowAttribute(hWnd, 20 , &value,
sizeof(value)) != S_OK) {
517 DwmSetWindowAttribute(hWnd, 19 , &value,
sizeof(value));
523LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
525 static uint32_t keycode = 0;
526 static bool console =
false;
528 const float SCROLL_BUILTIN_MULTIPLIER = 14.0f / WHEEL_DELTA;
534 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)((LPCREATESTRUCT)lParam)->lpCreateParams);
535 _cursor.in_window =
false;
540 SetDarkModeForWindow(hwnd, IsDarkModeEnabled());
543 case WM_SETTINGCHANGE:
545 SetDarkModeForWindow(hwnd, IsDarkModeEnabled());
550 GetUpdateRect(hwnd, &r, FALSE);
551 video_driver->
MakeDirty(r.left, r.top, r.right - r.left, r.bottom - r.top);
553 ValidateRect(hwnd,
nullptr);
557 case WM_PALETTECHANGED:
558 if ((HWND)wParam == hwnd)
return 0;
561 case WM_QUERYNEWPALETTE:
566 HandleExitGameRequest();
601 _cursor.in_window =
false;
607 int x = (int16_t)LOWORD(lParam);
608 int y = (int16_t)HIWORD(lParam);
613 if (!_cursor.in_window) {
614 _cursor.in_window =
true;
616 tme.cbSize =
sizeof(tme);
617 tme.dwFlags = TME_LEAVE;
618 tme.hwndTrack = hwnd;
620 TrackMouseEvent(&tme);
623 if (_cursor.fix_at) {
627 while (PeekMessage(&m, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE | PM_NOYIELD | PM_QS_INPUT)) {
628 x = (int16_t)LOWORD(m.lParam);
629 y = (int16_t)HIWORD(m.lParam);
633 if (_cursor.UpdateCursorPosition(x, y)) {
635 pt.x = _cursor.pos.x;
636 pt.y = _cursor.pos.y;
637 ClientToScreen(hwnd, &pt);
638 SetCursorPos(pt.x, pt.y);
645 case WM_INPUTLANGCHANGE:
649 case WM_IME_SETCONTEXT:
654 case WM_IME_STARTCOMPOSITION:
659 case WM_IME_COMPOSITION:
662 case WM_IME_ENDCOMPOSITION:
673 console =
GB(lParam, 16, 8) == 41;
677 uint scancode =
GB(lParam, 16, 8);
678 uint charcode = wParam;
682 if (console && scancode == 41) {
689 uint cur_keycode = keycode;
697 uint scancode =
GB(lParam, 16, 8);
698 keycode = scancode == 41 ? (uint)WKC_BACKQUOTE : MapWindowsKey(wParam);
700 uint charcode = MapVirtualKey(wParam, MAPVK_VK_TO_CHAR);
711 if (
HasBit(charcode, 31) && !console) {
712 if (scancode == 41) {
721 uint cur_keycode = keycode;
751 if (wParam != SIZE_MINIMIZED) {
754 _window_maximize = (wParam == SIZE_MAXIMIZED || (_window_maximize && _fullscreen));
755 if (_window_maximize || _fullscreen) _bck_resolution =
_cur_resolution;
761 RECT *r = (RECT*)lParam;
765 SetRect(&r2, 0, 0, 0, 0);
766 AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
768 w = r->right - r->left - (r2.right - r2.left);
769 h = r->bottom - r->top - (r2.bottom - r2.top);
772 SetRect(&r2, 0, 0, w, h);
774 AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
775 w = r2.right - r2.left;
776 h = r2.bottom - r2.top;
780 r->bottom = r->top + h;
783 case WMSZ_BOTTOMLEFT:
784 r->bottom = r->top + h;
785 r->left = r->right - w;
788 case WMSZ_BOTTOMRIGHT:
789 r->bottom = r->top + h;
790 r->right = r->left + w;
794 r->left = r->right - w;
798 r->right = r->left + w;
802 r->top = r->bottom - h;
806 r->top = r->bottom - h;
807 r->left = r->right - w;
811 r->top = r->bottom - h;
812 r->right = r->left + w;
818 case WM_DPICHANGED: {
822 RECT *prcNewWindow = (RECT *)lParam;
827 prcNewWindow->right - prcNewWindow->left,
828 prcNewWindow->bottom - prcNewWindow->top,
829 SWP_NOZORDER | SWP_NOACTIVATE);
837#if !defined(WM_MOUSEWHEEL)
838# define WM_MOUSEWHEEL 0x020A
840#if !defined(WM_MOUSEHWHEEL)
841# define WM_MOUSEHWHEEL 0x020E
843#if !defined(GET_WHEEL_DELTA_WPARAM)
844# define GET_WHEEL_DELTA_WPARAM(wparam) ((short)HIWORD(wparam))
847 case WM_MOUSEWHEEL: {
848 int delta = GET_WHEEL_DELTA_WPARAM(wParam);
852 }
else if (delta > 0) {
856 _cursor.v_wheel -=
static_cast<float>(delta) * SCROLL_BUILTIN_MULTIPLIER *
_settings_client.gui.scrollwheel_multiplier;
857 _cursor.wheel_moved =
true;
862 case WM_MOUSEHWHEEL: {
863 int delta = GET_WHEEL_DELTA_WPARAM(wParam);
865 _cursor.h_wheel +=
static_cast<float>(delta) * SCROLL_BUILTIN_MULTIPLIER *
_settings_client.gui.scrollwheel_multiplier;
866 _cursor.wheel_moved =
true;
882 if (_exit_game)
break;
884 bool active = (LOWORD(wParam) != WA_INACTIVE);
885 bool minimized = (HIWORD(wParam) != 0);
887 if (active && minimized) {
890 ShowWindow(hwnd, SW_RESTORE);
893 }
else if (!active && !minimized) {
895 ShowWindow(hwnd, SW_MINIMIZE);
896 ChangeDisplaySettings(
nullptr, 0);
903 return DefWindowProc(hwnd, msg, wParam, lParam);
906static void RegisterWndClass()
908 static bool registered =
false;
910 if (registered)
return;
912 HINSTANCE hinst = GetModuleHandle(
nullptr);
919 LoadIcon(hinst, MAKEINTRESOURCE(100)),
920 LoadCursor(
nullptr, IDC_ARROW),
927 if (!RegisterClass(&wnd)) UserError(
"RegisterClass failed");
930static const Dimension default_resolutions[] = {
944static void FindResolutions(uint8_t bpp)
949 for (uint i = 0; EnumDisplaySettings(
nullptr, i, &dm) != 0; i++) {
950 if (dm.dmBitsPerPel != bpp || dm.dmPelsWidth < 640 || dm.dmPelsHeight < 480)
continue;
952 _resolutions.emplace_back(dm.dmPelsWidth, dm.dmPelsHeight);
957 _resolutions.assign(std::begin(default_resolutions), std::end(default_resolutions));
963void VideoDriver_Win32Base::Initialize()
981 if (this->
fullscreen) ChangeDisplaySettings(
nullptr, 0);
993 this->
MakeDirty(0, 0, _screen.width, _screen.height);
1010 (GetAsyncKeyState(VK_LEFT) < 0 ? 1 : 0) +
1011 (GetAsyncKeyState(VK_UP) < 0 ? 2 : 0) +
1012 (GetAsyncKeyState(VK_RIGHT) < 0 ? 4 : 0) +
1013 (GetAsyncKeyState(VK_DOWN) < 0 ? 8 : 0);
1025 if (!PeekMessage(&mesg,
nullptr, 0, 0, PM_REMOVE))
return false;
1029 DispatchMessage(&mesg);
1039 if (_exit_game)
break;
1068 if (_window_maximize) ShowWindow(this->
main_wnd, SW_SHOWNORMAL);
1091static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC, LPRECT, LPARAM data)
1093 auto &list = *
reinterpret_cast<std::vector<int>*
>(data);
1095 MONITORINFOEX monitorInfo = {};
1096 monitorInfo.cbSize =
sizeof(MONITORINFOEX);
1097 GetMonitorInfo(hMonitor, &monitorInfo);
1099 DEVMODE devMode = {};
1100 devMode.dmSize =
sizeof(DEVMODE);
1101 devMode.dmDriverExtra = 0;
1102 EnumDisplaySettings(monitorInfo.szDevice, ENUM_CURRENT_SETTINGS, &devMode);
1104 if (devMode.dmDisplayFrequency != 0) list.push_back(devMode.dmDisplayFrequency);
1110 std::vector<int> rates = {};
1111 EnumDisplayMonitors(
nullptr,
nullptr, MonitorEnumProc,
reinterpret_cast<LPARAM
>(&rates));
1117 return {
static_cast<uint
>(GetSystemMetrics(SM_CXSCREEN)),
static_cast<uint
>(GetSystemMetrics(SM_CYSCREEN)) };
1126 assert(_screen.dst_ptr !=
nullptr);
1133 assert(_screen.dst_ptr !=
nullptr);
1134 if (_screen.dst_ptr !=
nullptr) {
1137 _screen.dst_ptr =
nullptr;
1152 this->MakePalette();
1160 return std::nullopt;
1175 w = std::max(w, 64);
1176 h = std::max(h, 64);
1178 if (!force && w == _screen.width && h == _screen.height)
return false;
1180 BITMAPINFO *bi = (BITMAPINFO *)
new char[
sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * 256]();
1181 bi->bmiHeader.biSize =
sizeof(BITMAPINFOHEADER);
1183 bi->bmiHeader.biWidth = this->
width = w;
1184 bi->bmiHeader.biHeight = -(this->
height = h);
1186 bi->bmiHeader.biPlanes = 1;
1187 bi->bmiHeader.biBitCount = bpp;
1188 bi->bmiHeader.biCompression = BI_RGB;
1193 this->
dib_sect = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (VOID **)&this->
buffer_bits,
nullptr, 0);
1196 UserError(
"CreateDIBSection failed");
1201 _screen.pitch = (bpp == 8) ?
Align(w, 4) : w;
1215void VideoDriver_Win32GDI::MakePalette()
1219 LOGPALETTE *pal = (LOGPALETTE *)
new char[
sizeof(LOGPALETTE) + (256 - 1) *
sizeof(PALETTEENTRY)]();
1221 pal->palVersion = 0x300;
1222 pal->palNumEntries = 256;
1224 for (uint i = 0; i != 256; i++) {
1228 pal->palPalEntry[i].peFlags = 0;
1233 if (this->
gdi_palette ==
nullptr) UserError(
"CreatePalette failed!\n");
1236void VideoDriver_Win32GDI::UpdatePalette(HDC dc, uint start, uint count)
1240 for (uint i = 0; i != count; i++) {
1244 rgb[i].rgbReserved = 0;
1247 SetDIBColorTable(dc, start, count, rgb);
1252 HDC hDC = GetWindowDC(hWnd);
1253 HPALETTE hOldPalette = SelectPalette(hDC, this->
gdi_palette, FALSE);
1254 UINT nChanged = RealizePalette(hDC);
1256 SelectPalette(hDC, hOldPalette, TRUE);
1257 ReleaseDC(hWnd, hDC);
1258 if (nChanged != 0) this->
MakeDirty(0, 0, _screen.width, _screen.height);
1268 HDC dc2 = CreateCompatibleDC(dc);
1270 HBITMAP old_bmp = (HBITMAP)SelectObject(dc2, this->
dib_sect);
1271 HPALETTE old_palette = SelectPalette(dc, this->
gdi_palette, FALSE);
1295 BitBlt(dc, 0, 0, this->
width, this->
height, dc2, 0, 0, SRCCOPY);
1296 SelectPalette(dc, old_palette, TRUE);
1297 SelectObject(dc2, old_bmp);
1308 int VideoDriver_Win32GDI::RedrawScreenDebug()
1326#ifndef PFD_SUPPORT_COMPOSITION
1327# define PFD_SUPPORT_COMPOSITION 0x00008000
1330static PFNWGLCREATECONTEXTATTRIBSARBPROC _wglCreateContextAttribsARB =
nullptr;
1331static PFNWGLSWAPINTERVALEXTPROC _wglSwapIntervalEXT =
nullptr;
1332static bool _hasWGLARBCreateContextProfile =
false;
1341 OGLProc ret =
reinterpret_cast<OGLProc
>(wglGetProcAddress(proc));
1342 if (ret ==
nullptr) {
1344 ret =
reinterpret_cast<OGLProc
>(GetProcAddress(GetModuleHandle(L
"opengl32"), proc));
1354static std::optional<std::string_view> SelectPixelFormat(HDC dc)
1356 PIXELFORMATDESCRIPTOR pfd = {
1357 sizeof(PIXELFORMATDESCRIPTOR),
1359 PFD_DRAW_TO_WINDOW |
1360 PFD_SUPPORT_OPENGL |
1365 0, 0, 0, 0, 0, 0, 0, 0,
1373 pfd.dwFlags |= PFD_SUPPORT_COMPOSITION;
1376 int format = ChoosePixelFormat(dc, &pfd);
1377 if (format == 0)
return "No suitable pixel format found";
1378 if (!SetPixelFormat(dc, format, &pfd))
return "Can't set pixel format";
1380 return std::nullopt;
1384static void LoadWGLExtensions()
1391 HWND wnd = CreateWindow(L
"STATIC", L
"dummy", WS_OVERLAPPEDWINDOW, 0, 0, 0, 0,
nullptr,
nullptr, GetModuleHandle(
nullptr),
nullptr);
1392 HDC dc = GetDC(wnd);
1395 if (SelectPixelFormat(dc) == std::nullopt) {
1397 HGLRC rc = wglCreateContext(dc);
1398 if (rc !=
nullptr) {
1399 wglMakeCurrent(dc, rc);
1403#pragma GCC diagnostic push
1404#pragma GCC diagnostic ignored "-Wcast-function-type"
1408 PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress(
"wglGetExtensionsStringARB");
1409 if (wglGetExtensionsStringARB !=
nullptr) {
1410 std::string_view wgl_exts = wglGetExtensionsStringARB(dc);
1413 _wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress(
"wglCreateContextAttribsARB");
1417 _wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress(
"wglSwapIntervalEXT");
1422#pragma GCC diagnostic pop
1424 wglMakeCurrent(
nullptr,
nullptr);
1425 wglDeleteContext(rc);
1433static FVideoDriver_Win32OpenGL iFVideoDriver_Win32OpenGL;
1435std::optional<std::string_view> VideoDriver_Win32OpenGL::Start(
const StringList ¶m)
1441 LoadWGLExtensions();
1444 this->MakeWindow(_fullscreen);
1447 auto err = this->AllocateContext();
1454 this->driver_info = GetName();
1455 this->driver_info +=
" (";
1457 this->driver_info +=
")";
1459 this->ClientSizeChanged(this->width, this->height,
true);
1461 if (_screen.dst_ptr ==
nullptr) {
1464 return "Can't get pointer to screen buffer";
1467 this->ReleaseVideoPointer();
1473 return std::nullopt;
1476void VideoDriver_Win32OpenGL::Stop()
1478 this->DestroyContext();
1482void VideoDriver_Win32OpenGL::DestroyContext()
1486 wglMakeCurrent(
nullptr,
nullptr);
1487 if (this->gl_rc !=
nullptr) {
1488 wglDeleteContext(this->gl_rc);
1489 this->gl_rc =
nullptr;
1491 if (this->dc !=
nullptr) {
1492 ReleaseDC(this->main_wnd, this->dc);
1497void VideoDriver_Win32OpenGL::ToggleVsync(
bool vsync)
1499 if (_wglSwapIntervalEXT !=
nullptr) {
1500 _wglSwapIntervalEXT(vsync);
1502 Debug(driver, 0,
"OpenGL: Vsync requested, but not supported by driver");
1506std::optional<std::string_view> VideoDriver_Win32OpenGL::AllocateContext()
1508 this->dc = GetDC(this->main_wnd);
1510 auto err = SelectPixelFormat(this->dc);
1511 if (err)
return err;
1516 if (_wglCreateContextAttribsARB !=
nullptr) {
1519 WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
1520 WGL_CONTEXT_MINOR_VERSION_ARB, 5,
1521 WGL_CONTEXT_FLAGS_ARB, _debug_driver_level >= 8 ? WGL_CONTEXT_DEBUG_BIT_ARB : 0,
1522 _hasWGLARBCreateContextProfile ? WGL_CONTEXT_PROFILE_MASK_ARB : 0, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
1525 rc = _wglCreateContextAttribsARB(this->dc,
nullptr, attribs);
1527 if (rc ==
nullptr) {
1531 rc = _wglCreateContextAttribsARB(this->dc,
nullptr, attribs);
1535 if (rc ==
nullptr) {
1537 rc = wglCreateContext(this->dc);
1538 if (rc ==
nullptr)
return "Can't create OpenGL context";
1540 if (!wglMakeCurrent(this->dc, rc))
return "Can't activate GL context";
1548bool VideoDriver_Win32OpenGL::ToggleFullscreen(
bool full_screen)
1550 if (_screen.dst_ptr !=
nullptr) this->ReleaseVideoPointer();
1551 this->DestroyContext();
1553 res &= this->AllocateContext() == std::nullopt;
1554 this->ClientSizeChanged(this->width, this->height,
true);
1558bool VideoDriver_Win32OpenGL::AfterBlitterChange()
1561 this->ClientSizeChanged(this->width, this->height,
true);
1565void VideoDriver_Win32OpenGL::PopulateSystemSprites()
1570void VideoDriver_Win32OpenGL::ClearSystemSprites()
1575bool VideoDriver_Win32OpenGL::AllocateBackingStore(
int w,
int h,
bool force)
1577 if (!force && w == _screen.width && h == _screen.height)
return false;
1579 this->width = w = std::max(w, 64);
1580 this->height = h = std::max(h, 64);
1582 if (this->gl_rc ==
nullptr)
return false;
1584 if (_screen.dst_ptr !=
nullptr) this->ReleaseVideoPointer();
1586 this->dirty_rect = {};
1588 SwapBuffers(this->dc);
1589 _screen.dst_ptr = this->GetVideoPointer();
1594void *VideoDriver_Win32OpenGL::GetVideoPointer()
1602void VideoDriver_Win32OpenGL::ReleaseVideoPointer()
1606 this->dirty_rect = {};
1607 _screen.dst_ptr =
nullptr;
1608 this->anim_buffer =
nullptr;
1611void VideoDriver_Win32OpenGL::Paint()
1630 SwapBuffers(this->dc);
#define AS(ap_name, size_x, size_y, min_year, max_year, catchment, noise, maint_cost, ttdpatch_type, class_id, name, preview)
AirportSpec definition for airports with at least one depot.
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
How all blitters should look like.
virtual uint8_t GetScreenDepth()=0
Get the screen depth this blitter works for.
virtual Blitter::PaletteAnimation UsePaletteAnimation()=0
Check if the blitter uses palette animation at all.
virtual void PaletteAnimate(const Palette &palette)=0
Called when the 8bpp palette is changed; you should redraw all pixels on the screen that are equal to...
@ None
No palette animation.
@ Blitter
The blitter takes care of the palette animation.
@ VideoBackend
Palette animation should be done by video backend (8bpp only!).
virtual void PostResize()
Post resize event.
The factory for Windows' video driver.
void Paint()
Render video buffer to the screen.
uint8_t * GetAnimBuffer()
Get a pointer to the memory for the separate animation buffer.
void * GetVideoBuffer()
Get a pointer to the memory for the video driver to draw to.
bool Resize(int w, int h, bool force=false)
Change the size of the drawing window and allocate matching resources.
static std::optional< std::string_view > Create(GetOGLProcAddressProc get_proc, const Dimension &screen_res)
Create and initialize the singleton back-end class.
void UpdatePalette(const Colour *pal, uint first, uint length)
Update the stored palette.
void ReleaseAnimBuffer(const Rect &update_rect)
Update animation buffer texture after the animation buffer was filled.
void ClearCursorCache()
Queue a request for cursor cache clear.
static OpenGLBackend * Get()
Get singleton instance of this class.
void DrawMouseCursor()
Draw mouse cursor on screen.
void ReleaseVideoBuffer(const Rect &update_rect)
Update video buffer texture after the video buffer was filled.
static void Destroy()
Free resources and destroy singleton back-end class.
Constant span of UTF-8 encoded data.
Base class for Windows video drivers.
int height
Height in pixels of our display surface.
bool has_focus
Does our window have system focus?
void EditBoxLostFocus() override
An edit box lost the input focus.
void CheckPaletteAnim() override
Process any pending palette animation.
void Stop() override
Stop this driver.
int height_org
Original monitor resolution height, before we changed it.
HWND main_wnd
Handle to system window.
bool fullscreen
Whether to use (true) fullscreen mode.
int width_org
Original monitor resolution width, before we changed it.
bool MakeWindow(bool full_screen, bool resize=true)
Instantiate a new window.
bool buffer_locked
Video buffer was locked by the main thread.
virtual void * GetVideoPointer()=0
Get a pointer to the video buffer.
void MakeDirty(int left, int top, int width, int height) override
Mark a particular area dirty.
bool PollEvent() override
Process a single system event.
virtual void PaletteChanged(HWND hWnd)=0
Palette of the window has changed.
bool LockVideoBuffer() override
Make sure the video buffer is ready for drawing.
std::vector< int > GetListOfMonitorRefreshRates() override
Get a list of refresh rates of each available monitor.
virtual bool AllocateBackingStore(int w, int h, bool force=false)=0
(Re-)create the backing store.
int width
Width in pixels of our display surface.
void InputLoop() override
Handle input logic, is CTRL pressed, should we fast-forward, etc.
virtual uint8_t GetFullscreenBpp()
Colour depth to use for fullscreen display modes.
Dimension GetScreenSize() const override
Get the resolution of the main screen.
virtual void ReleaseVideoPointer()
Hand video buffer back to the painting backend.
void UnlockVideoBuffer() override
Unlock a previously locked video buffer.
void ClientSizeChanged(int w, int h, bool force=false)
Indicate to the driver the client-size might have changed.
void MainLoop() override
Perform the actual drawing.
void ClaimMousePointer() override
Claim the exclusive rights for the mouse pointer.
Rect dirty_rect
Region of the screen that needs redrawing.
bool ToggleFullscreen(bool fullscreen) override
Change the full screen setting.
bool ChangeResolution(int w, int h) override
Change the resolution of the window.
The GDI video driver for windows.
void * buffer_bits
Internal rendering buffer.
HBITMAP dib_sect
System bitmap object referencing our rendering buffer.
void PaletteChanged(HWND hWnd) override
Palette of the window has changed.
std::optional< std::string_view > Start(const StringList ¶m) override
Start this driver.
void * GetVideoPointer() override
Get a pointer to the video buffer.
HPALETTE gdi_palette
Palette object for 8bpp blitter.
bool AllocateBackingStore(int w, int h, bool force=false) override
(Re-)create the backing store.
void Paint() override
Paint the window.
bool AfterBlitterChange() override
Callback invoked after the blitter was changed.
void Stop() override
Stop this driver.
bool fast_forward_key_pressed
The fast-forward key is being pressed.
void Tick()
Give the video-driver a tick.
void SleepTillNextTick()
Sleep till the next tick is about to happen.
void StartGameThread()
Start the loop for game-tick.
static std::string GetCaption()
Get the caption to use for the game's title bar.
void StopGameThread()
Stop the loop for the game-tick.
static VideoDriver * GetInstance()
Get the currently active instance of the video driver.
void UpdateAutoResolution()
Apply resolution auto-detection and clamp to sensible defaults.
static Palette _local_palette
Current palette to use for drawing.
static OGLProc GetOGLProcAddressCallback(const char *proc)
Platform-specific callback to get an OpenGL function pointer.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
bool GetDriverParamBool(const StringList &parm, std::string_view name)
Get a boolean parameter the list of parameters.
std::vector< Dimension > _resolutions
List of resolutions.
Dimension _cur_resolution
The current resolution.
Error reporting related functions.
Factory to 'query' all available blitters.
fluid_settings_t * settings
FluidSynth settings handle.
Types for recording game performance data.
@ PFE_VIDEO
Speed of painting drawn video buffer.
Rect BoundingRect(const Rect &r1, const Rect &r2)
Compute the bounding rectangle around two rectangles.
bool IsEmptyRect(const Rect &r)
Check if a rectangle is empty.
bool _shift_pressed
Is Shift pressed?
bool _left_button_down
Is left mouse button pressed?
bool _ctrl_pressed
Is Ctrl pressed?
uint8_t _dirkeys
1 = left, 2 = up, 4 = right, 8 = down
bool _left_button_clicked
Is left mouse button clicked?
bool _right_button_clicked
Is right mouse button clicked?
bool _right_button_down
Is right mouse button pressed?
bool AdjustGUIZoom(bool automatic)
Resolve GUI zoom level and adjust GUI to new zoom, if auto-suggestion is requested.
Functions related to the gfx engine.
void HandleCtrlChanged()
State of CONTROL key has changed.
void UpdateWindows()
Update the continuously changing contents of the windows, such as the viewports.
void GameSizeChanged()
Size of the application screen changed.
void HandleMouseEvents()
Handle a mouse event from the video driver.
void HandleKeypress(uint keycode, char32_t key)
Handle keyboard input.
void HandleTextInput(std::string_view str, bool marked=false, std::optional< size_t > caret=std::nullopt, std::optional< size_t > insert_location=std::nullopt, std::optional< size_t > replacement_end=std::nullopt)
Handle text input.
@ S8BPP_HARDWARE
Full 8bpp support by OS and hardware.
@ WKC_BACKSLASH
\ Backslash
@ WKC_SLASH
/ Forward slash
@ WKC_SINGLEQUOTE
' Single quote
@ WKC_R_BRACKET
] Right square bracket
@ WKC_L_BRACKET
[ Left square bracket
@ WKC_SEMICOLON
; Semicolon
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Functions/types related to loading libraries dynamically.
#define Point
Macro that prevents name conflicts between included headers.
constexpr bool IsInsideBS(const T x, const size_t base, const size_t size)
Checks if a value is between a window started at some base point.
constexpr T Align(const T x, uint n)
Return the smallest multiple of n equal or greater than x.
bool HasStringInExtensionList(std::string_view string, std::string_view substring)
Find a substring in a string made of space delimited elements.
OpenGL video driver support.
@ Stop
Go to the depot and stop there.
void GetKeyboardLayout()
Retrieve keyboard layout from language string or (if set) config file.
bool CopyPalette(Palette &local_palette, bool force_copy)
Copy the current palette if the palette was updated.
Functions related to modal progress.
Pseudo random number generator.
A number of safeguards to prevent using unsafe methods.
ClientSettings _settings_client
The current settings for this game.
Definition of base types and functions in a cross-platform compatible way.
char32_t Utf16DecodeSurrogate(uint lead, uint trail)
Convert an UTF-16 surrogate pair to the corresponding Unicode character.
bool Utf16IsLeadSurrogate(uint c)
Is the given character a lead surrogate code point?
bool Utf16IsTrailSurrogate(uint c)
Is the given character a lead surrogate code point?
std::vector< std::string > StringList
Type for a list of strings.
Dimensions (a width and height) of a rectangle in 2D.
Colour palette[256]
Current palette. Entry 0 has to be always fully transparent!
Specification of a rectangle with absolute coordinates of all edges.
Functions related to text effects.
Handling of UTF-8 encoded data.
bool _video_vsync
Whether we should use vsync (only if active video driver supports HW acceleration).
std::string_view convert_from_fs(const std::wstring_view src, std::span< char > dst_buf)
Convert to OpenTTD's encoding from that of the environment in UNICODE.
std::wstring OTTD2FS(std::string_view name)
Convert from OpenTTD's encoding to a wide string.
std::string FS2OTTD(std::wstring_view name)
Convert to OpenTTD's encoding from a wide string.
Declarations of functions for MS windows systems.
static LRESULT HandleCharMsg(uint keycode, char32_t charcode)
Forward key presses to the window system.
static bool DrawIMECompositionString()
Should we draw the composition string ourself, i.e is this a normal IME?
static LRESULT HandleIMEComposition(HWND hwnd, WPARAM wParam, LPARAM lParam)
Handle WM_IME_COMPOSITION messages.
static void SetCandidatePos(HWND hwnd)
Set the position of the candidate window.
static void CancelIMEComposition(HWND hwnd)
Clear the current composition string.
static void SetCompositionPos(HWND hwnd)
Set position of the composition window to the caret position.
Base of the Windows video driver.
Window * _focused_window
Window that currently has focus.
void ReInitAllWindows(bool zoom_changed)
Re-initialize all windows.
bool EditBoxInGlobalFocus()
Check if an edit box is in global focus.
void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope)
Mark window data of all windows of a given class as invalid (in need of re-computing) Note that by de...
Window functions not directly related to making/drawing windows.
Functions, definitions and such used only by the GUI.
@ WC_CONSOLE
Console; Window numbers:
@ WC_GAME_OPTIONS
Game options window; Window numbers: