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, 0, z}
65 #define AM(x, y, z, w) {x, y - x, 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)
113 for (map = _vk_mapping; map !=
endof(_vk_mapping); ++map) {
114 if ((uint)(sym - map->vk_from) <= map->vk_count) {
115 key = sym - map->vk_from + map->map_to;
120 if (GetAsyncKeyState(VK_SHIFT) < 0) key |= WKC_SHIFT;
121 if (GetAsyncKeyState(VK_CONTROL) < 0) key |= WKC_CTRL;
122 if (GetAsyncKeyState(VK_MENU) < 0) key |= WKC_ALT;
143 _fullscreen = full_screen;
165 if (settings.dmBitsPerPel == 8 && ChangeDisplaySettings(&
settings, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL) {
170 if (ChangeDisplaySettings(&
settings, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL) {
172 GetWindowRect(GetDesktopWindow(), &r);
175 if ((
int)
settings.dmPelsWidth != r.right - r.left || (
int)
settings.dmPelsHeight != r.bottom - r.top) {
180 if (ChangeDisplaySettings(&
settings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
186 ChangeDisplaySettings(
nullptr, 0);
188 this->
width = _bck_resolution.width;
189 this->
height = _bck_resolution.height;
194 DWORD style, showstyle;
197 showstyle = SW_SHOWNORMAL;
203 style = WS_OVERLAPPEDWINDOW;
205 if (_window_maximize) showstyle = SW_SHOWMAXIMIZED;
209 AdjustWindowRect(&r, style, FALSE);
210 w = r.right - r.left;
211 h = r.bottom - r.top;
214 if (!_window_maximize && resize) SetWindowPos(this->
main_wnd, 0, 0, 0, w, h, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE);
222 mi.cbSize =
sizeof(mi);
223 GetMonitorInfo(MonitorFromWindow(0, MONITOR_DEFAULTTOPRIMARY), &mi);
225 x = (mi.rcWork.right - mi.rcWork.left - w) / 2;
226 y = (mi.rcWork.bottom - mi.rcWork.top - h) / 2;
230 this->
main_wnd = CreateWindow(L
"OTTD",
OTTD2FS(caption).c_str(), style, x, y, w, h, 0, 0, GetModuleHandle(
nullptr),
this);
231 if (this->
main_wnd ==
nullptr) UserError(
"CreateWindow failed");
232 ShowWindow(this->
main_wnd, showstyle);
245 static char32_t prev_char = 0;
249 if (prev_char != 0)
Debug(driver, 1,
"Got two UTF-16 lead surrogates, dropping the first one");
250 prev_char = charcode;
255 if (prev_char != 0) {
259 Debug(driver, 1,
"Got an UTF-16 lead surrogate without a trail surrogate, dropping the lead surrogate");
272 return (_imm_props & IME_PROP_AT_CARET) && !(_imm_props & IME_PROP_SPECIAL_UI);
278 HIMC hIMC = ImmGetContext(hwnd);
279 if (hIMC !=
nullptr) {
281 cf.dwStyle = CFS_POINT;
286 cf.ptCurrentPos.x = _focused_window->
left + pt.x;
287 cf.ptCurrentPos.y = _focused_window->
top + pt.y;
289 cf.ptCurrentPos.x = 0;
290 cf.ptCurrentPos.y = 0;
292 ImmSetCompositionWindow(hIMC, &cf);
294 ImmReleaseContext(hwnd, hIMC);
300 HIMC hIMC = ImmGetContext(hwnd);
301 if (hIMC !=
nullptr) {
304 cf.dwStyle = CFS_EXCLUDE;
308 cf.ptCurrentPos.x = _focused_window->
left + pt.x;
309 cf.ptCurrentPos.y = _focused_window->
top + pt.y;
311 cf.rcArea.left = _focused_window->
left;
312 cf.rcArea.top = _focused_window->
top;
313 cf.rcArea.right = _focused_window->
left + _focused_window->
width;
314 cf.rcArea.bottom = _focused_window->
top + _focused_window->
height;
322 cf.ptCurrentPos.x = 0;
323 cf.ptCurrentPos.y = 0;
324 SetRectEmpty(&cf.rcArea);
326 ImmSetCandidateWindow(hIMC, &cf);
328 ImmReleaseContext(hwnd, hIMC);
334 HIMC hIMC = ImmGetContext(hwnd);
336 if (hIMC !=
nullptr) {
337 if (lParam & GCS_RESULTSTR) {
339 LONG len = ImmGetCompositionString(hIMC, GCS_RESULTSTR,
nullptr, 0);
340 std::wstring str(len + 1, L
'\0');
341 len = ImmGetCompositionString(hIMC, GCS_RESULTSTR, str.data(), len);
342 str[len /
sizeof(wchar_t)] = L
'\0';
352 lParam &= ~(GCS_RESULTSTR | GCS_RESULTCLAUSE | GCS_RESULTREADCLAUSE | GCS_RESULTREADSTR);
357 LONG len = ImmGetCompositionString(hIMC, GCS_COMPSTR,
nullptr, 0);
358 std::wstring str(len + 1, L
'\0');
359 len = ImmGetCompositionString(hIMC, GCS_COMPSTR, str.data(), len);
360 str[len /
sizeof(wchar_t)] = L
'\0';
363 static char utf8_buf[1024];
367 LONG caret_bytes = ImmGetCompositionString(hIMC, GCS_CURSORPOS,
nullptr, 0);
368 const char *caret = utf8_buf;
369 for (
const wchar_t *c = str.c_str(); *c !=
'\0' && *caret !=
'\0' && caret_bytes > 0; c++, caret_bytes--) {
383 lParam &= ~(GCS_COMPSTR | GCS_COMPATTR | GCS_COMPCLAUSE | GCS_CURSORPOS | GCS_DELTASTART);
386 ImmReleaseContext(hwnd, hIMC);
388 return lParam != 0 ? DefWindowProc(hwnd, WM_IME_COMPOSITION, wParam, lParam) : 0;
394 HIMC hIMC = ImmGetContext(hwnd);
395 if (hIMC !=
nullptr) ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
396 ImmReleaseContext(hwnd, hIMC);
401 LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
403 static uint32_t keycode = 0;
404 static bool console =
false;
410 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)((LPCREATESTRUCT)lParam)->lpCreateParams);
418 GetUpdateRect(hwnd, &r, FALSE);
419 video_driver->
MakeDirty(r.left, r.top, r.right - r.left, r.bottom - r.top);
421 ValidateRect(hwnd,
nullptr);
425 case WM_PALETTECHANGED:
426 if ((HWND)wParam == hwnd)
return 0;
429 case WM_QUERYNEWPALETTE:
434 HandleExitGameRequest();
475 int x = (int16_t)LOWORD(lParam);
476 int y = (int16_t)HIWORD(lParam);
484 tme.cbSize =
sizeof(tme);
485 tme.dwFlags = TME_LEAVE;
486 tme.hwndTrack = hwnd;
488 TrackMouseEvent(&tme);
495 while (PeekMessage(&m, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE | PM_NOYIELD | PM_QS_INPUT)) {
496 x = (int16_t)LOWORD(m.lParam);
497 y = (int16_t)HIWORD(m.lParam);
503 pt.x = _cursor.
pos.x;
504 pt.y = _cursor.
pos.y;
505 ClientToScreen(hwnd, &pt);
506 SetCursorPos(pt.x, pt.y);
513 case WM_INPUTLANGCHANGE:
517 case WM_IME_SETCONTEXT:
522 case WM_IME_STARTCOMPOSITION:
527 case WM_IME_COMPOSITION:
530 case WM_IME_ENDCOMPOSITION:
541 console =
GB(lParam, 16, 8) == 41;
545 uint scancode =
GB(lParam, 16, 8);
546 uint charcode = wParam;
550 if (console && scancode == 41) {
557 uint cur_keycode = keycode;
565 uint scancode =
GB(lParam, 16, 8);
566 keycode = scancode == 41 ? (uint)WKC_BACKQUOTE : MapWindowsKey(wParam);
568 uint charcode = MapVirtualKey(wParam, MAPVK_VK_TO_CHAR);
579 if (
HasBit(charcode, 31) && !console) {
580 if (scancode == 41) {
589 uint cur_keycode = keycode;
619 if (wParam != SIZE_MINIMIZED) {
622 _window_maximize = (wParam == SIZE_MAXIMIZED || (_window_maximize && _fullscreen));
623 if (_window_maximize || _fullscreen) _bck_resolution =
_cur_resolution;
624 video_driver->ClientSizeChanged(LOWORD(lParam), HIWORD(lParam));
629 RECT *r = (RECT*)lParam;
633 SetRect(&r2, 0, 0, 0, 0);
634 AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
636 w = r->right - r->left - (r2.right - r2.left);
637 h = r->bottom - r->top - (r2.bottom - r2.top);
640 SetRect(&r2, 0, 0, w, h);
642 AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
643 w = r2.right - r2.left;
644 h = r2.bottom - r2.top;
648 r->bottom = r->top + h;
651 case WMSZ_BOTTOMLEFT:
652 r->bottom = r->top + h;
653 r->left = r->right - w;
656 case WMSZ_BOTTOMRIGHT:
657 r->bottom = r->top + h;
658 r->right = r->left + w;
662 r->left = r->right - w;
666 r->right = r->left + w;
670 r->top = r->bottom - h;
674 r->top = r->bottom - h;
675 r->left = r->right - w;
679 r->top = r->bottom - h;
680 r->right = r->left + w;
686 case WM_DPICHANGED: {
690 RECT *prcNewWindow = (RECT *)lParam;
695 prcNewWindow->right - prcNewWindow->left,
696 prcNewWindow->bottom - prcNewWindow->top,
697 SWP_NOZORDER | SWP_NOACTIVATE);
705 #if !defined(WM_MOUSEWHEEL)
706 # define WM_MOUSEWHEEL 0x020A
708 #if !defined(GET_WHEEL_DELTA_WPARAM)
709 # define GET_WHEEL_DELTA_WPARAM(wparam) ((short)HIWORD(wparam))
712 case WM_MOUSEWHEEL: {
713 int delta = GET_WHEEL_DELTA_WPARAM(wParam);
717 }
else if (delta > 0) {
735 if (_exit_game)
break;
737 bool active = (LOWORD(wParam) != WA_INACTIVE);
738 bool minimized = (HIWORD(wParam) != 0);
740 if (active && minimized) {
743 ShowWindow(hwnd, SW_RESTORE);
746 }
else if (!active && !minimized) {
748 ShowWindow(hwnd, SW_MINIMIZE);
749 ChangeDisplaySettings(
nullptr, 0);
756 return DefWindowProc(hwnd, msg, wParam, lParam);
759 static void RegisterWndClass()
761 static bool registered =
false;
763 if (registered)
return;
765 HINSTANCE hinst = GetModuleHandle(
nullptr);
772 LoadIcon(hinst, MAKEINTRESOURCE(100)),
773 LoadCursor(
nullptr, IDC_ARROW),
780 if (!RegisterClass(&wnd)) UserError(
"RegisterClass failed");
783 static const Dimension default_resolutions[] = {
797 static void FindResolutions(uint8_t bpp)
802 for (uint i = 0; EnumDisplaySettings(
nullptr, i, &dm) != 0; i++) {
803 if (dm.dmBitsPerPel != bpp || dm.dmPelsWidth < 640 || dm.dmPelsHeight < 480)
continue;
805 _resolutions.emplace_back(dm.dmPelsWidth, dm.dmPelsHeight);
810 _resolutions.assign(std::begin(default_resolutions), std::end(default_resolutions));
816 void VideoDriver_Win32Base::Initialize()
834 if (this->
fullscreen) ChangeDisplaySettings(
nullptr, 0);
846 this->
MakeDirty(0, 0, _screen.width, _screen.height);
863 (GetAsyncKeyState(VK_LEFT) < 0 ? 1 : 0) +
864 (GetAsyncKeyState(VK_UP) < 0 ? 2 : 0) +
865 (GetAsyncKeyState(VK_RIGHT) < 0 ? 4 : 0) +
866 (GetAsyncKeyState(VK_DOWN) < 0 ? 8 : 0);
878 if (!PeekMessage(&mesg,
nullptr, 0, 0, PM_REMOVE))
return false;
882 DispatchMessage(&mesg);
892 if (_exit_game)
break;
901 void VideoDriver_Win32Base::ClientSizeChanged(
int w,
int h,
bool force)
915 if (_window_maximize) ShowWindow(this->
main_wnd, SW_SHOWNORMAL);
938 static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC, LPRECT, LPARAM data)
940 auto &list = *
reinterpret_cast<std::vector<int>*
>(data);
942 MONITORINFOEX monitorInfo = {};
943 monitorInfo.cbSize =
sizeof(MONITORINFOEX);
944 GetMonitorInfo(hMonitor, &monitorInfo);
946 DEVMODE devMode = {};
947 devMode.dmSize =
sizeof(DEVMODE);
948 devMode.dmDriverExtra = 0;
949 EnumDisplaySettings(monitorInfo.szDevice, ENUM_CURRENT_SETTINGS, &devMode);
951 if (devMode.dmDisplayFrequency != 0) list.push_back(devMode.dmDisplayFrequency);
957 std::vector<int> rates = {};
958 EnumDisplayMonitors(
nullptr,
nullptr, MonitorEnumProc,
reinterpret_cast<LPARAM
>(&rates));
964 return {
static_cast<uint
>(GetSystemMetrics(SM_CXSCREEN)),
static_cast<uint
>(GetSystemMetrics(SM_CYSCREEN)) };
969 typedef UINT (WINAPI *PFNGETDPIFORWINDOW)(HWND hwnd);
970 typedef UINT (WINAPI *PFNGETDPIFORSYSTEM)(VOID);
971 typedef HRESULT (WINAPI *PFNGETDPIFORMONITOR)(HMONITOR hMonitor,
int dpiType, UINT *dpiX, UINT *dpiY);
973 static PFNGETDPIFORWINDOW _GetDpiForWindow =
nullptr;
974 static PFNGETDPIFORSYSTEM _GetDpiForSystem =
nullptr;
975 static PFNGETDPIFORMONITOR _GetDpiForMonitor =
nullptr;
977 static bool init_done =
false;
982 _GetDpiForWindow = _user32.
GetFunction(
"GetDpiForWindow");
983 _GetDpiForSystem = _user32.
GetFunction(
"GetDpiForSystem");
984 _GetDpiForMonitor = _shcore.
GetFunction(
"GetDpiForMonitor");
989 if (cur_dpi == 0 && _GetDpiForWindow !=
nullptr && this->
main_wnd !=
nullptr) {
991 cur_dpi = _GetDpiForWindow(this->
main_wnd);
993 if (cur_dpi == 0 && _GetDpiForMonitor !=
nullptr && this->
main_wnd !=
nullptr) {
996 if (SUCCEEDED(_GetDpiForMonitor(MonitorFromWindow(this->
main_wnd, MONITOR_DEFAULTTOPRIMARY), 0 , &dpiX, &dpiY))) {
1000 if (cur_dpi == 0 && _GetDpiForSystem !=
nullptr) {
1002 cur_dpi = _GetDpiForSystem();
1005 return cur_dpi > 0 ? cur_dpi / 96.0f : 1.0f;
1014 assert(_screen.dst_ptr !=
nullptr);
1021 assert(_screen.dst_ptr !=
nullptr);
1022 if (_screen.dst_ptr !=
nullptr) {
1025 _screen.dst_ptr =
nullptr;
1040 this->MakePalette();
1063 w = std::max(w, 64);
1064 h = std::max(h, 64);
1066 if (!force && w == _screen.width && h == _screen.height)
return false;
1068 BITMAPINFO *bi = (BITMAPINFO *)
new char[
sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * 256]();
1069 bi->bmiHeader.biSize =
sizeof(BITMAPINFOHEADER);
1071 bi->bmiHeader.biWidth = this->
width = w;
1072 bi->bmiHeader.biHeight = -(this->
height = h);
1074 bi->bmiHeader.biPlanes = 1;
1075 bi->bmiHeader.biBitCount = bpp;
1076 bi->bmiHeader.biCompression = BI_RGB;
1081 this->
dib_sect = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (VOID **)&this->
buffer_bits,
nullptr, 0);
1084 UserError(
"CreateDIBSection failed");
1089 _screen.pitch = (bpp == 8) ?
Align(w, 4) : w;
1103 void VideoDriver_Win32GDI::MakePalette()
1107 LOGPALETTE *pal = (LOGPALETTE *)
new char[
sizeof(LOGPALETTE) + (256 - 1) *
sizeof(PALETTEENTRY)]();
1109 pal->palVersion = 0x300;
1110 pal->palNumEntries = 256;
1112 for (uint i = 0; i != 256; i++) {
1116 pal->palPalEntry[i].peFlags = 0;
1121 if (this->
gdi_palette ==
nullptr) UserError(
"CreatePalette failed!\n");
1124 void VideoDriver_Win32GDI::UpdatePalette(HDC dc, uint start, uint count)
1128 for (uint i = 0; i != count; i++) {
1132 rgb[i].rgbReserved = 0;
1135 SetDIBColorTable(dc, start, count, rgb);
1140 HDC hDC = GetWindowDC(hWnd);
1141 HPALETTE hOldPalette = SelectPalette(hDC, this->
gdi_palette, FALSE);
1142 UINT nChanged = RealizePalette(hDC);
1144 SelectPalette(hDC, hOldPalette, TRUE);
1145 ReleaseDC(hWnd, hDC);
1146 if (nChanged != 0) this->
MakeDirty(0, 0, _screen.width, _screen.height);
1156 HDC dc2 = CreateCompatibleDC(dc);
1158 HBITMAP old_bmp = (HBITMAP)SelectObject(dc2, this->
dib_sect);
1159 HPALETTE old_palette = SelectPalette(dc, this->
gdi_palette, FALSE);
1183 BitBlt(dc, 0, 0, this->
width, this->
height, dc2, 0, 0, SRCCOPY);
1184 SelectPalette(dc, old_palette, TRUE);
1185 SelectObject(dc2, old_bmp);
1196 int VideoDriver_Win32GDI::RedrawScreenDebug()
1215 #include "../3rdparty/opengl/glext.h"
1216 #include "../3rdparty/opengl/wglext.h"
1219 #ifndef PFD_SUPPORT_COMPOSITION
1220 # define PFD_SUPPORT_COMPOSITION 0x00008000
1223 static PFNWGLCREATECONTEXTATTRIBSARBPROC _wglCreateContextAttribsARB =
nullptr;
1224 static PFNWGLSWAPINTERVALEXTPROC _wglSwapIntervalEXT =
nullptr;
1225 static bool _hasWGLARBCreateContextProfile =
false;
1230 OGLProc ret =
reinterpret_cast<OGLProc
>(wglGetProcAddress(proc));
1231 if (ret ==
nullptr) {
1233 ret =
reinterpret_cast<OGLProc
>(GetProcAddress(GetModuleHandle(L
"opengl32"), proc));
1243 static const char *SelectPixelFormat(HDC dc)
1245 PIXELFORMATDESCRIPTOR pfd = {
1246 sizeof(PIXELFORMATDESCRIPTOR),
1248 PFD_DRAW_TO_WINDOW |
1249 PFD_SUPPORT_OPENGL |
1254 0, 0, 0, 0, 0, 0, 0, 0,
1262 pfd.dwFlags |= PFD_SUPPORT_COMPOSITION;
1265 int format = ChoosePixelFormat(dc, &pfd);
1266 if (format == 0)
return "No suitable pixel format found";
1267 if (!SetPixelFormat(dc, format, &pfd))
return "Can't set pixel format";
1273 static void LoadWGLExtensions()
1280 HWND wnd = CreateWindow(_T(
"STATIC"), _T(
"dummy"), WS_OVERLAPPEDWINDOW, 0, 0, 0, 0,
nullptr,
nullptr, GetModuleHandle(
nullptr),
nullptr);
1281 HDC dc = GetDC(wnd);
1284 if (SelectPixelFormat(dc) ==
nullptr) {
1286 HGLRC rc = wglCreateContext(dc);
1287 if (rc !=
nullptr) {
1288 wglMakeCurrent(dc, rc);
1292 #pragma GCC diagnostic push
1293 #pragma GCC diagnostic ignored "-Wcast-function-type"
1297 PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress(
"wglGetExtensionsStringARB");
1298 if (wglGetExtensionsStringARB !=
nullptr) {
1299 const char *wgl_exts = wglGetExtensionsStringARB(dc);
1302 _wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress(
"wglCreateContextAttribsARB");
1306 _wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress(
"wglSwapIntervalEXT");
1311 #pragma GCC diagnostic pop
1313 wglMakeCurrent(
nullptr,
nullptr);
1314 wglDeleteContext(rc);
1322 static FVideoDriver_Win32OpenGL iFVideoDriver_Win32OpenGL;
1324 const char *VideoDriver_Win32OpenGL::Start(
const StringList ¶m)
1330 LoadWGLExtensions();
1333 this->MakeWindow(_fullscreen);
1336 const char *err = this->AllocateContext();
1337 if (err !=
nullptr) {
1343 this->driver_info = GetName();
1344 this->driver_info +=
" (";
1346 this->driver_info +=
")";
1348 this->ClientSizeChanged(this->width, this->height,
true);
1350 if (_screen.dst_ptr ==
nullptr) {
1353 return "Can't get pointer to screen buffer";
1356 this->ReleaseVideoPointer();
1365 void VideoDriver_Win32OpenGL::Stop()
1367 this->DestroyContext();
1371 void VideoDriver_Win32OpenGL::DestroyContext()
1375 wglMakeCurrent(
nullptr,
nullptr);
1376 if (this->gl_rc !=
nullptr) {
1377 wglDeleteContext(this->gl_rc);
1378 this->gl_rc =
nullptr;
1380 if (this->dc !=
nullptr) {
1381 ReleaseDC(this->main_wnd, this->dc);
1386 void VideoDriver_Win32OpenGL::ToggleVsync(
bool vsync)
1388 if (_wglSwapIntervalEXT !=
nullptr) {
1389 _wglSwapIntervalEXT(vsync);
1391 Debug(driver, 0,
"OpenGL: Vsync requested, but not supported by driver");
1395 const char *VideoDriver_Win32OpenGL::AllocateContext()
1397 this->dc = GetDC(this->main_wnd);
1399 const char *err = SelectPixelFormat(this->dc);
1400 if (err !=
nullptr)
return err;
1405 if (_wglCreateContextAttribsARB !=
nullptr) {
1408 WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
1409 WGL_CONTEXT_MINOR_VERSION_ARB, 5,
1410 WGL_CONTEXT_FLAGS_ARB, _debug_driver_level >= 8 ? WGL_CONTEXT_DEBUG_BIT_ARB : 0,
1411 _hasWGLARBCreateContextProfile ? WGL_CONTEXT_PROFILE_MASK_ARB : 0, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
1414 rc = _wglCreateContextAttribsARB(this->dc,
nullptr, attribs);
1416 if (rc ==
nullptr) {
1420 rc = _wglCreateContextAttribsARB(this->dc,
nullptr, attribs);
1424 if (rc ==
nullptr) {
1426 rc = wglCreateContext(this->dc);
1427 if (rc ==
nullptr)
return "Can't create OpenGL context";
1429 if (!wglMakeCurrent(this->dc, rc))
return "Can't active GL context";
1437 bool VideoDriver_Win32OpenGL::ToggleFullscreen(
bool full_screen)
1439 if (_screen.dst_ptr !=
nullptr) this->ReleaseVideoPointer();
1440 this->DestroyContext();
1442 res &= this->AllocateContext() ==
nullptr;
1443 this->ClientSizeChanged(this->width, this->height,
true);
1447 bool VideoDriver_Win32OpenGL::AfterBlitterChange()
1450 this->ClientSizeChanged(this->width, this->height,
true);
1454 void VideoDriver_Win32OpenGL::PopulateSystemSprites()
1459 void VideoDriver_Win32OpenGL::ClearSystemSprites()
1464 bool VideoDriver_Win32OpenGL::AllocateBackingStore(
int w,
int h,
bool force)
1466 if (!force && w == _screen.width && h == _screen.height)
return false;
1468 this->width = w = std::max(w, 64);
1469 this->height = h = std::max(h, 64);
1471 if (this->gl_rc ==
nullptr)
return false;
1473 if (_screen.dst_ptr !=
nullptr) this->ReleaseVideoPointer();
1475 this->dirty_rect = {};
1477 SwapBuffers(this->dc);
1478 _screen.dst_ptr = this->GetVideoPointer();
1483 void *VideoDriver_Win32OpenGL::GetVideoPointer()
1491 void VideoDriver_Win32OpenGL::ReleaseVideoPointer()
1495 this->dirty_rect = {};
1496 _screen.dst_ptr =
nullptr;
1497 this->anim_buffer =
nullptr;
1500 void VideoDriver_Win32OpenGL::Paint()
1519 SwapBuffers(this->dc);