10 #include "../stdafx.h"
11 #include "../openttd.h"
12 #include "../error_func.h"
13 #include "../gfx_func.h"
14 #include "../os/windows/win32.h"
15 #include "../blitter/factory.hpp"
16 #include "../core/geometry_func.hpp"
17 #include "../core/math_func.hpp"
18 #include "../core/random_func.hpp"
19 #include "../texteff.hpp"
20 #include "../thread.h"
21 #include "../progress.h"
22 #include "../window_gui.h"
23 #include "../window_func.h"
24 #include "../framerate_type.h"
25 #include "../library_loader.h"
29 #include <versionhelpers.h>
31 #include "../safeguards.h"
34 #ifndef MAPVK_VK_TO_CHAR
35 #define MAPVK_VK_TO_CHAR (2)
39 #define PM_QS_INPUT 0x20000
43 #define WM_DPICHANGED 0x02E0
46 bool _window_maximize;
52 bool VideoDriver_Win32Base::ClaimMousePointer()
54 MyShowCursor(
false,
true);
64 #define AS(x, z) {x, 1, z}
65 #define AM(x, y, z, w) {x, y - x + 1, z}
69 AM(VK_PRIOR, VK_DOWN, WKC_PAGEUP, WKC_DOWN),
71 AM(
'A',
'Z',
'A',
'Z'),
72 AM(
'0',
'9',
'0',
'9'),
74 AS(VK_ESCAPE, WKC_ESC),
75 AS(VK_PAUSE, WKC_PAUSE),
76 AS(VK_BACK, WKC_BACKSPACE),
77 AM(VK_INSERT, VK_DELETE, WKC_INSERT, WKC_DELETE),
79 AS(VK_SPACE, WKC_SPACE),
80 AS(VK_RETURN, WKC_RETURN),
84 AM(VK_F1, VK_F12, WKC_F1, WKC_F12),
87 AM(VK_NUMPAD0, VK_NUMPAD9,
'0',
'9'),
88 AS(VK_DIVIDE, WKC_NUM_DIV),
89 AS(VK_MULTIPLY, WKC_NUM_MUL),
90 AS(VK_SUBTRACT, WKC_NUM_MINUS),
91 AS(VK_ADD, WKC_NUM_PLUS),
92 AS(VK_DECIMAL, WKC_NUM_DECIMAL),
108 static uint MapWindowsKey(uint sym)
112 for (
const auto &map : _vk_mapping) {
113 if (
IsInsideBS(sym, map.vk_from, map.vk_count)) {
114 key = sym - map.vk_from + map.map_to;
119 if (GetAsyncKeyState(VK_SHIFT) < 0) key |= WKC_SHIFT;
120 if (GetAsyncKeyState(VK_CONTROL) < 0) key |= WKC_CTRL;
121 if (GetAsyncKeyState(VK_MENU) < 0) key |= WKC_ALT;
142 _fullscreen = full_screen;
164 if (settings.dmBitsPerPel == 8 && ChangeDisplaySettings(&
settings, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL) {
169 if (ChangeDisplaySettings(&
settings, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL) {
171 GetWindowRect(GetDesktopWindow(), &r);
174 if ((
int)
settings.dmPelsWidth != r.right - r.left || (
int)
settings.dmPelsHeight != r.bottom - r.top) {
179 if (ChangeDisplaySettings(&
settings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
185 ChangeDisplaySettings(
nullptr, 0);
187 this->
width = _bck_resolution.width;
188 this->
height = _bck_resolution.height;
193 DWORD style, showstyle;
196 showstyle = SW_SHOWNORMAL;
202 style = WS_OVERLAPPEDWINDOW;
204 if (_window_maximize) showstyle = SW_SHOWMAXIMIZED;
208 AdjustWindowRect(&r, style, FALSE);
209 w = r.right - r.left;
210 h = r.bottom - r.top;
213 if (!_window_maximize && resize) SetWindowPos(this->
main_wnd, 0, 0, 0, w, h, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE);
221 mi.cbSize =
sizeof(mi);
222 GetMonitorInfo(MonitorFromWindow(0, MONITOR_DEFAULTTOPRIMARY), &mi);
224 x = (mi.rcWork.right - mi.rcWork.left - w) / 2;
225 y = (mi.rcWork.bottom - mi.rcWork.top - h) / 2;
229 this->
main_wnd = CreateWindow(L
"OTTD",
OTTD2FS(caption).c_str(), style, x, y, w, h, 0, 0, GetModuleHandle(
nullptr),
this);
230 if (this->
main_wnd ==
nullptr) UserError(
"CreateWindow failed");
231 ShowWindow(this->
main_wnd, showstyle);
244 static char32_t prev_char = 0;
248 if (prev_char != 0)
Debug(driver, 1,
"Got two UTF-16 lead surrogates, dropping the first one");
249 prev_char = charcode;
254 if (prev_char != 0) {
258 Debug(driver, 1,
"Got an UTF-16 lead surrogate without a trail surrogate, dropping the lead surrogate");
271 return (_imm_props & IME_PROP_AT_CARET) && !(_imm_props & IME_PROP_SPECIAL_UI);
277 HIMC hIMC = ImmGetContext(hwnd);
278 if (hIMC !=
nullptr) {
280 cf.dwStyle = CFS_POINT;
285 cf.ptCurrentPos.x = _focused_window->
left + pt.x;
286 cf.ptCurrentPos.y = _focused_window->
top + pt.y;
288 cf.ptCurrentPos.x = 0;
289 cf.ptCurrentPos.y = 0;
291 ImmSetCompositionWindow(hIMC, &cf);
293 ImmReleaseContext(hwnd, hIMC);
299 HIMC hIMC = ImmGetContext(hwnd);
300 if (hIMC !=
nullptr) {
303 cf.dwStyle = CFS_EXCLUDE;
307 cf.ptCurrentPos.x = _focused_window->
left + pt.x;
308 cf.ptCurrentPos.y = _focused_window->
top + pt.y;
310 cf.rcArea.left = _focused_window->
left;
311 cf.rcArea.top = _focused_window->
top;
312 cf.rcArea.right = _focused_window->
left + _focused_window->
width;
313 cf.rcArea.bottom = _focused_window->
top + _focused_window->
height;
321 cf.ptCurrentPos.x = 0;
322 cf.ptCurrentPos.y = 0;
323 SetRectEmpty(&cf.rcArea);
325 ImmSetCandidateWindow(hIMC, &cf);
327 ImmReleaseContext(hwnd, hIMC);
333 HIMC hIMC = ImmGetContext(hwnd);
335 if (hIMC !=
nullptr) {
336 if (lParam & GCS_RESULTSTR) {
338 LONG len = ImmGetCompositionString(hIMC, GCS_RESULTSTR,
nullptr, 0);
339 std::wstring str(len + 1, L
'\0');
340 len = ImmGetCompositionString(hIMC, GCS_RESULTSTR, str.data(), len);
341 str[len /
sizeof(wchar_t)] = L
'\0';
351 lParam &= ~(GCS_RESULTSTR | GCS_RESULTCLAUSE | GCS_RESULTREADCLAUSE | GCS_RESULTREADSTR);
356 LONG len = ImmGetCompositionString(hIMC, GCS_COMPSTR,
nullptr, 0);
357 std::wstring str(len + 1, L
'\0');
358 len = ImmGetCompositionString(hIMC, GCS_COMPSTR, str.data(), len);
359 str[len /
sizeof(wchar_t)] = L
'\0';
362 static char utf8_buf[1024];
366 LONG caret_bytes = ImmGetCompositionString(hIMC, GCS_CURSORPOS,
nullptr, 0);
367 const char *caret = utf8_buf;
368 for (
const wchar_t *c = str.c_str(); *c !=
'\0' && *caret !=
'\0' && caret_bytes > 0; c++, caret_bytes--) {
382 lParam &= ~(GCS_COMPSTR | GCS_COMPATTR | GCS_COMPCLAUSE | GCS_CURSORPOS | GCS_DELTASTART);
385 ImmReleaseContext(hwnd, hIMC);
387 return lParam != 0 ? DefWindowProc(hwnd, WM_IME_COMPOSITION, wParam, lParam) : 0;
393 HIMC hIMC = ImmGetContext(hwnd);
394 if (hIMC !=
nullptr) ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
395 ImmReleaseContext(hwnd, hIMC);
400 LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
402 static uint32_t keycode = 0;
403 static bool console =
false;
409 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)((LPCREATESTRUCT)lParam)->lpCreateParams);
417 GetUpdateRect(hwnd, &r, FALSE);
418 video_driver->
MakeDirty(r.left, r.top, r.right - r.left, r.bottom - r.top);
420 ValidateRect(hwnd,
nullptr);
424 case WM_PALETTECHANGED:
425 if ((HWND)wParam == hwnd)
return 0;
428 case WM_QUERYNEWPALETTE:
433 HandleExitGameRequest();
474 int x = (int16_t)LOWORD(lParam);
475 int y = (int16_t)HIWORD(lParam);
483 tme.cbSize =
sizeof(tme);
484 tme.dwFlags = TME_LEAVE;
485 tme.hwndTrack = hwnd;
487 TrackMouseEvent(&tme);
494 while (PeekMessage(&m, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE | PM_NOYIELD | PM_QS_INPUT)) {
495 x = (int16_t)LOWORD(m.lParam);
496 y = (int16_t)HIWORD(m.lParam);
502 pt.x = _cursor.
pos.x;
503 pt.y = _cursor.
pos.y;
504 ClientToScreen(hwnd, &pt);
505 SetCursorPos(pt.x, pt.y);
512 case WM_INPUTLANGCHANGE:
516 case WM_IME_SETCONTEXT:
521 case WM_IME_STARTCOMPOSITION:
526 case WM_IME_COMPOSITION:
529 case WM_IME_ENDCOMPOSITION:
540 console =
GB(lParam, 16, 8) == 41;
544 uint scancode =
GB(lParam, 16, 8);
545 uint charcode = wParam;
549 if (console && scancode == 41) {
556 uint cur_keycode = keycode;
564 uint scancode =
GB(lParam, 16, 8);
565 keycode = scancode == 41 ? (uint)WKC_BACKQUOTE : MapWindowsKey(wParam);
567 uint charcode = MapVirtualKey(wParam, MAPVK_VK_TO_CHAR);
578 if (
HasBit(charcode, 31) && !console) {
579 if (scancode == 41) {
588 uint cur_keycode = keycode;
618 if (wParam != SIZE_MINIMIZED) {
621 _window_maximize = (wParam == SIZE_MAXIMIZED || (_window_maximize && _fullscreen));
622 if (_window_maximize || _fullscreen) _bck_resolution =
_cur_resolution;
623 video_driver->ClientSizeChanged(LOWORD(lParam), HIWORD(lParam));
628 RECT *r = (RECT*)lParam;
632 SetRect(&r2, 0, 0, 0, 0);
633 AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
635 w = r->right - r->left - (r2.right - r2.left);
636 h = r->bottom - r->top - (r2.bottom - r2.top);
639 SetRect(&r2, 0, 0, w, h);
641 AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
642 w = r2.right - r2.left;
643 h = r2.bottom - r2.top;
647 r->bottom = r->top + h;
650 case WMSZ_BOTTOMLEFT:
651 r->bottom = r->top + h;
652 r->left = r->right - w;
655 case WMSZ_BOTTOMRIGHT:
656 r->bottom = r->top + h;
657 r->right = r->left + w;
661 r->left = r->right - w;
665 r->right = r->left + w;
669 r->top = r->bottom - h;
673 r->top = r->bottom - h;
674 r->left = r->right - w;
678 r->top = r->bottom - h;
679 r->right = r->left + w;
685 case WM_DPICHANGED: {
689 RECT *prcNewWindow = (RECT *)lParam;
694 prcNewWindow->right - prcNewWindow->left,
695 prcNewWindow->bottom - prcNewWindow->top,
696 SWP_NOZORDER | SWP_NOACTIVATE);
704 #if !defined(WM_MOUSEWHEEL)
705 # define WM_MOUSEWHEEL 0x020A
707 #if !defined(GET_WHEEL_DELTA_WPARAM)
708 # define GET_WHEEL_DELTA_WPARAM(wparam) ((short)HIWORD(wparam))
711 case WM_MOUSEWHEEL: {
712 int delta = GET_WHEEL_DELTA_WPARAM(wParam);
716 }
else if (delta > 0) {
734 if (_exit_game)
break;
736 bool active = (LOWORD(wParam) != WA_INACTIVE);
737 bool minimized = (HIWORD(wParam) != 0);
739 if (active && minimized) {
742 ShowWindow(hwnd, SW_RESTORE);
745 }
else if (!active && !minimized) {
747 ShowWindow(hwnd, SW_MINIMIZE);
748 ChangeDisplaySettings(
nullptr, 0);
755 return DefWindowProc(hwnd, msg, wParam, lParam);
758 static void RegisterWndClass()
760 static bool registered =
false;
762 if (registered)
return;
764 HINSTANCE hinst = GetModuleHandle(
nullptr);
771 LoadIcon(hinst, MAKEINTRESOURCE(100)),
772 LoadCursor(
nullptr, IDC_ARROW),
779 if (!RegisterClass(&wnd)) UserError(
"RegisterClass failed");
782 static const Dimension default_resolutions[] = {
796 static void FindResolutions(uint8_t bpp)
801 for (uint i = 0; EnumDisplaySettings(
nullptr, i, &dm) != 0; i++) {
802 if (dm.dmBitsPerPel != bpp || dm.dmPelsWidth < 640 || dm.dmPelsHeight < 480)
continue;
804 _resolutions.emplace_back(dm.dmPelsWidth, dm.dmPelsHeight);
809 _resolutions.assign(std::begin(default_resolutions), std::end(default_resolutions));
815 void VideoDriver_Win32Base::Initialize()
833 if (this->
fullscreen) ChangeDisplaySettings(
nullptr, 0);
845 this->
MakeDirty(0, 0, _screen.width, _screen.height);
862 (GetAsyncKeyState(VK_LEFT) < 0 ? 1 : 0) +
863 (GetAsyncKeyState(VK_UP) < 0 ? 2 : 0) +
864 (GetAsyncKeyState(VK_RIGHT) < 0 ? 4 : 0) +
865 (GetAsyncKeyState(VK_DOWN) < 0 ? 8 : 0);
877 if (!PeekMessage(&mesg,
nullptr, 0, 0, PM_REMOVE))
return false;
881 DispatchMessage(&mesg);
891 if (_exit_game)
break;
900 void VideoDriver_Win32Base::ClientSizeChanged(
int w,
int h,
bool force)
914 if (_window_maximize) ShowWindow(this->
main_wnd, SW_SHOWNORMAL);
937 static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC, LPRECT, LPARAM data)
939 auto &list = *
reinterpret_cast<std::vector<int>*
>(data);
941 MONITORINFOEX monitorInfo = {};
942 monitorInfo.cbSize =
sizeof(MONITORINFOEX);
943 GetMonitorInfo(hMonitor, &monitorInfo);
945 DEVMODE devMode = {};
946 devMode.dmSize =
sizeof(DEVMODE);
947 devMode.dmDriverExtra = 0;
948 EnumDisplaySettings(monitorInfo.szDevice, ENUM_CURRENT_SETTINGS, &devMode);
950 if (devMode.dmDisplayFrequency != 0) list.push_back(devMode.dmDisplayFrequency);
956 std::vector<int> rates = {};
957 EnumDisplayMonitors(
nullptr,
nullptr, MonitorEnumProc,
reinterpret_cast<LPARAM
>(&rates));
963 return {
static_cast<uint
>(GetSystemMetrics(SM_CXSCREEN)),
static_cast<uint
>(GetSystemMetrics(SM_CYSCREEN)) };
968 typedef UINT (WINAPI *PFNGETDPIFORWINDOW)(HWND hwnd);
969 typedef UINT (WINAPI *PFNGETDPIFORSYSTEM)(VOID);
970 typedef HRESULT (WINAPI *PFNGETDPIFORMONITOR)(HMONITOR hMonitor,
int dpiType, UINT *dpiX, UINT *dpiY);
972 static PFNGETDPIFORWINDOW _GetDpiForWindow =
nullptr;
973 static PFNGETDPIFORSYSTEM _GetDpiForSystem =
nullptr;
974 static PFNGETDPIFORMONITOR _GetDpiForMonitor =
nullptr;
976 static bool init_done =
false;
981 _GetDpiForWindow = _user32.
GetFunction(
"GetDpiForWindow");
982 _GetDpiForSystem = _user32.
GetFunction(
"GetDpiForSystem");
983 _GetDpiForMonitor = _shcore.
GetFunction(
"GetDpiForMonitor");
988 if (cur_dpi == 0 && _GetDpiForWindow !=
nullptr && this->
main_wnd !=
nullptr) {
990 cur_dpi = _GetDpiForWindow(this->
main_wnd);
992 if (cur_dpi == 0 && _GetDpiForMonitor !=
nullptr && this->
main_wnd !=
nullptr) {
995 if (SUCCEEDED(_GetDpiForMonitor(MonitorFromWindow(this->
main_wnd, MONITOR_DEFAULTTOPRIMARY), 0 , &dpiX, &dpiY))) {
999 if (cur_dpi == 0 && _GetDpiForSystem !=
nullptr) {
1001 cur_dpi = _GetDpiForSystem();
1004 return cur_dpi > 0 ? cur_dpi / 96.0f : 1.0f;
1013 assert(_screen.dst_ptr !=
nullptr);
1020 assert(_screen.dst_ptr !=
nullptr);
1021 if (_screen.dst_ptr !=
nullptr) {
1024 _screen.dst_ptr =
nullptr;
1039 this->MakePalette();
1047 return std::nullopt;
1062 w = std::max(w, 64);
1063 h = std::max(h, 64);
1065 if (!force && w == _screen.width && h == _screen.height)
return false;
1067 BITMAPINFO *bi = (BITMAPINFO *)
new char[
sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * 256]();
1068 bi->bmiHeader.biSize =
sizeof(BITMAPINFOHEADER);
1070 bi->bmiHeader.biWidth = this->
width = w;
1071 bi->bmiHeader.biHeight = -(this->
height = h);
1073 bi->bmiHeader.biPlanes = 1;
1074 bi->bmiHeader.biBitCount = bpp;
1075 bi->bmiHeader.biCompression = BI_RGB;
1080 this->
dib_sect = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (VOID **)&this->
buffer_bits,
nullptr, 0);
1083 UserError(
"CreateDIBSection failed");
1088 _screen.pitch = (bpp == 8) ?
Align(w, 4) : w;
1102 void VideoDriver_Win32GDI::MakePalette()
1106 LOGPALETTE *pal = (LOGPALETTE *)
new char[
sizeof(LOGPALETTE) + (256 - 1) *
sizeof(PALETTEENTRY)]();
1108 pal->palVersion = 0x300;
1109 pal->palNumEntries = 256;
1111 for (uint i = 0; i != 256; i++) {
1115 pal->palPalEntry[i].peFlags = 0;
1120 if (this->
gdi_palette ==
nullptr) UserError(
"CreatePalette failed!\n");
1123 void VideoDriver_Win32GDI::UpdatePalette(HDC dc, uint start, uint count)
1127 for (uint i = 0; i != count; i++) {
1131 rgb[i].rgbReserved = 0;
1134 SetDIBColorTable(dc, start, count, rgb);
1139 HDC hDC = GetWindowDC(hWnd);
1140 HPALETTE hOldPalette = SelectPalette(hDC, this->
gdi_palette, FALSE);
1141 UINT nChanged = RealizePalette(hDC);
1143 SelectPalette(hDC, hOldPalette, TRUE);
1144 ReleaseDC(hWnd, hDC);
1145 if (nChanged != 0) this->
MakeDirty(0, 0, _screen.width, _screen.height);
1155 HDC dc2 = CreateCompatibleDC(dc);
1157 HBITMAP old_bmp = (HBITMAP)SelectObject(dc2, this->
dib_sect);
1158 HPALETTE old_palette = SelectPalette(dc, this->
gdi_palette, FALSE);
1182 BitBlt(dc, 0, 0, this->
width, this->
height, dc2, 0, 0, SRCCOPY);
1183 SelectPalette(dc, old_palette, TRUE);
1184 SelectObject(dc2, old_bmp);
1195 int VideoDriver_Win32GDI::RedrawScreenDebug()
1214 #include "../3rdparty/opengl/glext.h"
1215 #include "../3rdparty/opengl/wglext.h"
1218 #ifndef PFD_SUPPORT_COMPOSITION
1219 # define PFD_SUPPORT_COMPOSITION 0x00008000
1222 static PFNWGLCREATECONTEXTATTRIBSARBPROC _wglCreateContextAttribsARB =
nullptr;
1223 static PFNWGLSWAPINTERVALEXTPROC _wglSwapIntervalEXT =
nullptr;
1224 static bool _hasWGLARBCreateContextProfile =
false;
1229 OGLProc ret =
reinterpret_cast<OGLProc
>(wglGetProcAddress(proc));
1230 if (ret ==
nullptr) {
1232 ret =
reinterpret_cast<OGLProc
>(GetProcAddress(GetModuleHandle(L
"opengl32"), proc));
1242 static std::optional<std::string_view> SelectPixelFormat(HDC dc)
1244 PIXELFORMATDESCRIPTOR pfd = {
1245 sizeof(PIXELFORMATDESCRIPTOR),
1247 PFD_DRAW_TO_WINDOW |
1248 PFD_SUPPORT_OPENGL |
1253 0, 0, 0, 0, 0, 0, 0, 0,
1261 pfd.dwFlags |= PFD_SUPPORT_COMPOSITION;
1264 int format = ChoosePixelFormat(dc, &pfd);
1265 if (format == 0)
return "No suitable pixel format found";
1266 if (!SetPixelFormat(dc, format, &pfd))
return "Can't set pixel format";
1268 return std::nullopt;
1272 static void LoadWGLExtensions()
1279 HWND wnd = CreateWindow(L
"STATIC", L
"dummy", WS_OVERLAPPEDWINDOW, 0, 0, 0, 0,
nullptr,
nullptr, GetModuleHandle(
nullptr),
nullptr);
1280 HDC dc = GetDC(wnd);
1283 if (SelectPixelFormat(dc) == std::nullopt) {
1285 HGLRC rc = wglCreateContext(dc);
1286 if (rc !=
nullptr) {
1287 wglMakeCurrent(dc, rc);
1291 #pragma GCC diagnostic push
1292 #pragma GCC diagnostic ignored "-Wcast-function-type"
1296 PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress(
"wglGetExtensionsStringARB");
1297 if (wglGetExtensionsStringARB !=
nullptr) {
1298 const char *wgl_exts = wglGetExtensionsStringARB(dc);
1301 _wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress(
"wglCreateContextAttribsARB");
1305 _wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress(
"wglSwapIntervalEXT");
1310 #pragma GCC diagnostic pop
1312 wglMakeCurrent(
nullptr,
nullptr);
1313 wglDeleteContext(rc);
1321 static FVideoDriver_Win32OpenGL iFVideoDriver_Win32OpenGL;
1323 std::optional<std::string_view> VideoDriver_Win32OpenGL::Start(
const StringList ¶m)
1329 LoadWGLExtensions();
1332 this->MakeWindow(_fullscreen);
1335 auto err = this->AllocateContext();
1342 this->driver_info = GetName();
1343 this->driver_info +=
" (";
1345 this->driver_info +=
")";
1347 this->ClientSizeChanged(this->width, this->height,
true);
1349 if (_screen.dst_ptr ==
nullptr) {
1352 return "Can't get pointer to screen buffer";
1355 this->ReleaseVideoPointer();
1361 return std::nullopt;
1364 void VideoDriver_Win32OpenGL::Stop()
1366 this->DestroyContext();
1370 void VideoDriver_Win32OpenGL::DestroyContext()
1374 wglMakeCurrent(
nullptr,
nullptr);
1375 if (this->gl_rc !=
nullptr) {
1376 wglDeleteContext(this->gl_rc);
1377 this->gl_rc =
nullptr;
1379 if (this->dc !=
nullptr) {
1380 ReleaseDC(this->main_wnd, this->dc);
1385 void VideoDriver_Win32OpenGL::ToggleVsync(
bool vsync)
1387 if (_wglSwapIntervalEXT !=
nullptr) {
1388 _wglSwapIntervalEXT(vsync);
1390 Debug(driver, 0,
"OpenGL: Vsync requested, but not supported by driver");
1394 std::optional<std::string_view> VideoDriver_Win32OpenGL::AllocateContext()
1396 this->dc = GetDC(this->main_wnd);
1398 auto err = SelectPixelFormat(this->dc);
1399 if (err)
return err;
1404 if (_wglCreateContextAttribsARB !=
nullptr) {
1407 WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
1408 WGL_CONTEXT_MINOR_VERSION_ARB, 5,
1409 WGL_CONTEXT_FLAGS_ARB, _debug_driver_level >= 8 ? WGL_CONTEXT_DEBUG_BIT_ARB : 0,
1410 _hasWGLARBCreateContextProfile ? WGL_CONTEXT_PROFILE_MASK_ARB : 0, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
1413 rc = _wglCreateContextAttribsARB(this->dc,
nullptr, attribs);
1415 if (rc ==
nullptr) {
1419 rc = _wglCreateContextAttribsARB(this->dc,
nullptr, attribs);
1423 if (rc ==
nullptr) {
1425 rc = wglCreateContext(this->dc);
1426 if (rc ==
nullptr)
return "Can't create OpenGL context";
1428 if (!wglMakeCurrent(this->dc, rc))
return "Can't active GL context";
1436 bool VideoDriver_Win32OpenGL::ToggleFullscreen(
bool full_screen)
1438 if (_screen.dst_ptr !=
nullptr) this->ReleaseVideoPointer();
1439 this->DestroyContext();
1441 res &= this->AllocateContext() == std::nullopt;
1442 this->ClientSizeChanged(this->width, this->height,
true);
1446 bool VideoDriver_Win32OpenGL::AfterBlitterChange()
1449 this->ClientSizeChanged(this->width, this->height,
true);
1453 void VideoDriver_Win32OpenGL::PopulateSystemSprites()
1458 void VideoDriver_Win32OpenGL::ClearSystemSprites()
1463 bool VideoDriver_Win32OpenGL::AllocateBackingStore(
int w,
int h,
bool force)
1465 if (!force && w == _screen.width && h == _screen.height)
return false;
1467 this->width = w = std::max(w, 64);
1468 this->height = h = std::max(h, 64);
1470 if (this->gl_rc ==
nullptr)
return false;
1472 if (_screen.dst_ptr !=
nullptr) this->ReleaseVideoPointer();
1474 this->dirty_rect = {};
1476 SwapBuffers(this->dc);
1477 _screen.dst_ptr = this->GetVideoPointer();
1482 void *VideoDriver_Win32OpenGL::GetVideoPointer()
1490 void VideoDriver_Win32OpenGL::ReleaseVideoPointer()
1494 this->dirty_rect = {};
1495 _screen.dst_ptr =
nullptr;
1496 this->anim_buffer =
nullptr;
1499 void VideoDriver_Win32OpenGL::Paint()
1518 SwapBuffers(this->dc);