summaryrefslogtreecommitdiffstats
path: root/platform/windows
diff options
context:
space:
mode:
Diffstat (limited to 'platform/windows')
-rw-r--r--platform/windows/SCsub5
-rw-r--r--platform/windows/crash_handler_windows.h2
-rw-r--r--platform/windows/detect.py33
-rw-r--r--platform/windows/display_server_windows.cpp505
-rw-r--r--platform/windows/display_server_windows.h16
-rw-r--r--platform/windows/doc_classes/EditorExportPlatformWindows.xml9
-rw-r--r--platform/windows/export/export_plugin.cpp47
-rw-r--r--platform/windows/gl_manager_windows_angle.cpp70
-rw-r--r--platform/windows/gl_manager_windows_angle.h61
-rw-r--r--platform/windows/gl_manager_windows_native.cpp (renamed from platform/windows/gl_manager_windows.cpp)131
-rw-r--r--platform/windows/gl_manager_windows_native.h (renamed from platform/windows/gl_manager_windows.h)28
-rw-r--r--platform/windows/joypad_windows.cpp8
-rw-r--r--platform/windows/os_windows.cpp15
-rw-r--r--platform/windows/platform_config.h2
-rw-r--r--platform/windows/platform_gl.h53
-rw-r--r--platform/windows/platform_windows_builders.py16
-rw-r--r--platform/windows/tts_windows.cpp12
-rw-r--r--platform/windows/wgl_detect_version.cpp197
-rw-r--r--platform/windows/wgl_detect_version.h42
-rw-r--r--platform/windows/windows_terminal_logger.cpp4
20 files changed, 1061 insertions, 195 deletions
diff --git a/platform/windows/SCsub b/platform/windows/SCsub
index efbb47d965..1b6908d2bb 100644
--- a/platform/windows/SCsub
+++ b/platform/windows/SCsub
@@ -16,7 +16,9 @@ common_win = [
"tts_windows.cpp",
"windows_terminal_logger.cpp",
"vulkan_context_win.cpp",
- "gl_manager_windows.cpp",
+ "gl_manager_windows_native.cpp",
+ "gl_manager_windows_angle.cpp",
+ "wgl_detect_version.cpp",
]
common_win_wrap = [
@@ -44,6 +46,7 @@ if env["windows_subsystem"] == "gui":
env_wrap.Append(LIBS=["version"])
prog_wrap = env_wrap.add_program("#bin/godot", common_win_wrap + res_wrap_obj, PROGSUFFIX=env["PROGSUFFIX_WRAP"])
+ env_wrap.Depends(prog_wrap, prog)
# Microsoft Visual Studio Project Generation
if env["vsproj"]:
diff --git a/platform/windows/crash_handler_windows.h b/platform/windows/crash_handler_windows.h
index ef5831f10c..3871210977 100644
--- a/platform/windows/crash_handler_windows.h
+++ b/platform/windows/crash_handler_windows.h
@@ -35,7 +35,7 @@
#include <windows.h>
// Crash handler exception only enabled with MSVC
-#if defined(DEBUG_ENABLED) && defined(MSVC)
+#if defined(DEBUG_ENABLED) && defined(_MSC_VER)
#define CRASH_HANDLER_EXCEPTION 1
extern DWORD CrashHandlerException(EXCEPTION_POINTERS *ep);
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index bec1fd2cb6..bdacdbb9ba 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -185,6 +185,8 @@ def get_opts():
BoolVariable("use_static_cpp", "Link MinGW/MSVC C++ runtime libraries statically", True),
BoolVariable("use_asan", "Use address sanitizer (ASAN)", False),
BoolVariable("debug_crt", "Compile with MSVC's debug CRT (/MDd)", False),
+ BoolVariable("incremental_link", "Use MSVC incremental linking. May increase or decrease build times.", False),
+ ("angle_libs", "Path to the ANGLE static libraries", ""),
]
@@ -355,6 +357,10 @@ def configure_msvc(env, vcvars_msvc_config):
else:
env.AppendUnique(CCFLAGS=["/MD"])
+ # MSVC incremental linking is broken and may _increase_ link time (GH-77968).
+ if not env["incremental_link"]:
+ env.Append(LINKFLAGS=["/INCREMENTAL:NO"])
+
if env["arch"] == "x86_32":
env["x86_libtheora_opt_vc"] = True
@@ -379,7 +385,6 @@ def configure_msvc(env, vcvars_msvc_config):
"WINMIDI_ENABLED",
"TYPED_METHOD_BIND",
"WIN32",
- "MSVC",
"WINVER=%s" % env["target_win_version"],
"_WIN32_WINNT=%s" % env["target_win_version"],
]
@@ -414,6 +419,7 @@ def configure_msvc(env, vcvars_msvc_config):
"dwmapi",
"dwrite",
"wbemuuid",
+ "ntdll",
]
if env.debug_features:
@@ -426,7 +432,16 @@ def configure_msvc(env, vcvars_msvc_config):
if env["opengl3"]:
env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"])
- LIBS += ["opengl32"]
+ if env["angle_libs"] != "":
+ env.AppendUnique(CPPDEFINES=["EGL_STATIC"])
+ env.Append(LIBPATH=[env["angle_libs"]])
+ LIBS += [
+ "libANGLE.windows." + env["arch"],
+ "libEGL.windows." + env["arch"],
+ "libGLES.windows." + env["arch"],
+ ]
+ LIBS += ["dxgi", "d3d9", "d3d11"]
+ env.Prepend(CPPPATH=["#thirdparty/angle/include"])
env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS])
@@ -596,6 +611,7 @@ def configure_mingw(env):
"dwmapi",
"dwrite",
"wbemuuid",
+ "ntdll",
]
)
@@ -609,7 +625,18 @@ def configure_mingw(env):
if env["opengl3"]:
env.Append(CPPDEFINES=["GLES3_ENABLED"])
- env.Append(LIBS=["opengl32"])
+ if env["angle_libs"] != "":
+ env.AppendUnique(CPPDEFINES=["EGL_STATIC"])
+ env.Append(LIBPATH=[env["angle_libs"]])
+ env.Append(
+ LIBS=[
+ "EGL.windows." + env["arch"],
+ "GLES.windows." + env["arch"],
+ "ANGLE.windows." + env["arch"],
+ ]
+ )
+ env.Append(LIBS=["dxgi", "d3d9", "d3d11"])
+ env.Prepend(CPPPATH=["#thirdparty/angle/include"])
env.Append(CPPDEFINES=["MINGW_ENABLED", ("MINGW_HAS_SECURE_API", 1)])
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 86b909234a..bb0b64ba10 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -31,8 +31,11 @@
#include "display_server_windows.h"
#include "os_windows.h"
+#include "wgl_detect_version.h"
+#include "core/config/project_settings.h"
#include "core/io/marshalls.h"
+#include "drivers/png/png_driver_common.h"
#include "main/main.h"
#include "scene/resources/atlas_texture.h"
@@ -42,6 +45,8 @@
#include <avrt.h>
#include <dwmapi.h>
+#include <shlwapi.h>
+#include <shobjidl.h>
#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
@@ -87,6 +92,7 @@ bool DisplayServerWindows::has_feature(Feature p_feature) const {
case FEATURE_HIDPI:
case FEATURE_ICON:
case FEATURE_NATIVE_ICON:
+ case FEATURE_NATIVE_DIALOG:
case FEATURE_SWAP_BUFFERS:
case FEATURE_KEEP_SCREEN_ON:
case FEATURE_TEXT_TO_SPEECH:
@@ -179,40 +185,205 @@ void DisplayServerWindows::_register_raw_input_devices(WindowID p_target_window)
}
bool DisplayServerWindows::tts_is_speaking() const {
- ERR_FAIL_COND_V_MSG(!tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
+ ERR_FAIL_NULL_V_MSG(tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
return tts->is_speaking();
}
bool DisplayServerWindows::tts_is_paused() const {
- ERR_FAIL_COND_V_MSG(!tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
+ ERR_FAIL_NULL_V_MSG(tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
return tts->is_paused();
}
TypedArray<Dictionary> DisplayServerWindows::tts_get_voices() const {
- ERR_FAIL_COND_V_MSG(!tts, TypedArray<Dictionary>(), "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
+ ERR_FAIL_NULL_V_MSG(tts, TypedArray<Dictionary>(), "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
return tts->get_voices();
}
void DisplayServerWindows::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) {
- ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
+ ERR_FAIL_NULL_MSG(tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
tts->speak(p_text, p_voice, p_volume, p_pitch, p_rate, p_utterance_id, p_interrupt);
}
void DisplayServerWindows::tts_pause() {
- ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
+ ERR_FAIL_NULL_MSG(tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
tts->pause();
}
void DisplayServerWindows::tts_resume() {
- ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
+ ERR_FAIL_NULL_MSG(tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
tts->resume();
}
void DisplayServerWindows::tts_stop() {
- ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
+ ERR_FAIL_NULL_MSG(tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
tts->stop();
}
+Error DisplayServerWindows::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_INDEX_V(int(p_mode), FILE_DIALOG_MODE_SAVE_MAX, FAILED);
+
+ Vector<Char16String> filter_names;
+ Vector<Char16String> filter_exts;
+ for (const String &E : p_filters) {
+ Vector<String> tokens = E.split(";");
+ if (tokens.size() >= 1) {
+ String flt = tokens[0].strip_edges();
+ int filter_slice_count = flt.get_slice_count(",");
+ Vector<String> exts;
+ for (int j = 0; j < filter_slice_count; j++) {
+ String str = (flt.get_slice(",", j).strip_edges());
+ if (!str.is_empty()) {
+ exts.push_back(str);
+ }
+ }
+ if (!exts.is_empty()) {
+ String str = String(";").join(exts);
+ filter_exts.push_back(str.utf16());
+ if (tokens.size() == 2) {
+ filter_names.push_back(tokens[1].strip_edges().utf16());
+ } else {
+ filter_names.push_back(str.utf16());
+ }
+ }
+ }
+ }
+ if (filter_names.is_empty()) {
+ filter_exts.push_back(String("*.*").utf16());
+ filter_names.push_back(RTR("All Files").utf16());
+ }
+
+ Vector<COMDLG_FILTERSPEC> filters;
+ for (int i = 0; i < filter_names.size(); i++) {
+ filters.push_back({ (LPCWSTR)filter_names[i].ptr(), (LPCWSTR)filter_exts[i].ptr() });
+ }
+
+ WindowID prev_focus = last_focused_window;
+
+ HRESULT hr = S_OK;
+ IFileDialog *pfd = nullptr;
+ if (p_mode == FILE_DIALOG_MODE_SAVE_FILE) {
+ hr = CoCreateInstance(CLSID_FileSaveDialog, nullptr, CLSCTX_INPROC_SERVER, IID_IFileSaveDialog, (void **)&pfd);
+ } else {
+ hr = CoCreateInstance(CLSID_FileOpenDialog, nullptr, CLSCTX_INPROC_SERVER, IID_IFileOpenDialog, (void **)&pfd);
+ }
+ if (SUCCEEDED(hr)) {
+ DWORD flags;
+ pfd->GetOptions(&flags);
+ if (p_mode == FILE_DIALOG_MODE_OPEN_FILES) {
+ flags |= FOS_ALLOWMULTISELECT;
+ }
+ if (p_mode == FILE_DIALOG_MODE_OPEN_DIR) {
+ flags |= FOS_PICKFOLDERS;
+ }
+ if (p_show_hidden) {
+ flags |= FOS_FORCESHOWHIDDEN;
+ }
+ pfd->SetOptions(flags | FOS_FORCEFILESYSTEM);
+ pfd->SetTitle((LPCWSTR)p_title.utf16().ptr());
+
+ String dir = ProjectSettings::get_singleton()->globalize_path(p_current_directory);
+ if (dir == ".") {
+ dir = OS::get_singleton()->get_executable_path().get_base_dir();
+ }
+ dir = dir.replace("/", "\\");
+
+ IShellItem *shellitem = nullptr;
+ hr = SHCreateItemFromParsingName((LPCWSTR)dir.utf16().ptr(), nullptr, IID_IShellItem, (void **)&shellitem);
+ if (SUCCEEDED(hr)) {
+ pfd->SetDefaultFolder(shellitem);
+ pfd->SetFolder(shellitem);
+ }
+
+ pfd->SetFileName((LPCWSTR)p_filename.utf16().ptr());
+ pfd->SetFileTypes(filters.size(), filters.ptr());
+ pfd->SetFileTypeIndex(0);
+
+ WindowID window_id = _get_focused_window_or_popup();
+ if (!windows.has(window_id)) {
+ window_id = MAIN_WINDOW_ID;
+ }
+
+ hr = pfd->Show(windows[window_id].hWnd);
+ UINT index = 0;
+ pfd->GetFileTypeIndex(&index);
+
+ if (SUCCEEDED(hr)) {
+ Vector<String> file_names;
+
+ if (p_mode == FILE_DIALOG_MODE_OPEN_FILES) {
+ IShellItemArray *results;
+ hr = static_cast<IFileOpenDialog *>(pfd)->GetResults(&results);
+ if (SUCCEEDED(hr)) {
+ DWORD count = 0;
+ results->GetCount(&count);
+ for (DWORD i = 0; i < count; i++) {
+ IShellItem *result;
+ results->GetItemAt(i, &result);
+
+ PWSTR file_path = nullptr;
+ hr = result->GetDisplayName(SIGDN_FILESYSPATH, &file_path);
+ if (SUCCEEDED(hr)) {
+ file_names.push_back(String::utf16((const char16_t *)file_path));
+ CoTaskMemFree(file_path);
+ }
+ result->Release();
+ }
+ results->Release();
+ }
+ } else {
+ IShellItem *result;
+ hr = pfd->GetResult(&result);
+ if (SUCCEEDED(hr)) {
+ PWSTR file_path = nullptr;
+ hr = result->GetDisplayName(SIGDN_FILESYSPATH, &file_path);
+ if (SUCCEEDED(hr)) {
+ file_names.push_back(String::utf16((const char16_t *)file_path));
+ CoTaskMemFree(file_path);
+ }
+ result->Release();
+ }
+ }
+ if (!p_callback.is_null()) {
+ Variant v_result = true;
+ Variant v_files = file_names;
+ Variant v_index = index;
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[3] = { &v_result, &v_files, &v_index };
+
+ p_callback.callp(args, 3, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat(RTR("Failed to execute file dialogs callback: %s."), Variant::get_callable_error_text(p_callback, args, 3, ce)));
+ }
+ }
+ } else {
+ if (!p_callback.is_null()) {
+ Variant v_result = false;
+ Variant v_files = Vector<String>();
+ Variant v_index = index;
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[3] = { &v_result, &v_files, &v_index };
+
+ p_callback.callp(args, 3, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat(RTR("Failed to execute file dialogs callback: %s."), Variant::get_callable_error_text(p_callback, args, 3, ce)));
+ }
+ }
+ }
+ pfd->Release();
+ if (prev_focus != INVALID_WINDOW_ID) {
+ callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(prev_focus);
+ }
+
+ return OK;
+ } else {
+ return ERR_CANT_OPEN;
+ }
+}
+
void DisplayServerWindows::mouse_set_mode(MouseMode p_mode) {
_THREAD_SAFE_METHOD_
@@ -280,7 +451,7 @@ void DisplayServerWindows::clipboard_set(const String &p_text) {
Char16String utf16 = text.utf16();
HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (utf16.length() + 1) * sizeof(WCHAR));
- ERR_FAIL_COND_MSG(mem == nullptr, "Unable to allocate memory for clipboard contents.");
+ ERR_FAIL_NULL_MSG(mem, "Unable to allocate memory for clipboard contents.");
LPWSTR lptstrCopy = (LPWSTR)GlobalLock(mem);
memcpy(lptstrCopy, utf16.get_data(), (utf16.length() + 1) * sizeof(WCHAR));
@@ -291,7 +462,7 @@ void DisplayServerWindows::clipboard_set(const String &p_text) {
// Set the CF_TEXT version (not needed?).
CharString utf8 = text.utf8();
mem = GlobalAlloc(GMEM_MOVEABLE, utf8.length() + 1);
- ERR_FAIL_COND_MSG(mem == nullptr, "Unable to allocate memory for clipboard contents.");
+ ERR_FAIL_NULL_MSG(mem, "Unable to allocate memory for clipboard contents.");
LPTSTR ptr = (LPTSTR)GlobalLock(mem);
memcpy(ptr, utf8.get_data(), utf8.length());
@@ -341,6 +512,68 @@ String DisplayServerWindows::clipboard_get() const {
return ret;
}
+Ref<Image> DisplayServerWindows::clipboard_get_image() const {
+ Ref<Image> image;
+ if (!windows.has(last_focused_window)) {
+ return image; // No focused window?
+ }
+ if (!OpenClipboard(windows[last_focused_window].hWnd)) {
+ ERR_FAIL_V_MSG(image, "Unable to open clipboard.");
+ }
+ UINT png_format = RegisterClipboardFormatA("PNG");
+ if (png_format && IsClipboardFormatAvailable(png_format)) {
+ HANDLE png_handle = GetClipboardData(png_format);
+ if (png_handle) {
+ size_t png_size = GlobalSize(png_handle);
+ uint8_t *png_data = (uint8_t *)GlobalLock(png_handle);
+ image.instantiate();
+
+ PNGDriverCommon::png_to_image(png_data, png_size, false, image);
+
+ GlobalUnlock(png_handle);
+ }
+ } else if (IsClipboardFormatAvailable(CF_DIB)) {
+ HGLOBAL mem = GetClipboardData(CF_DIB);
+ if (mem != NULL) {
+ BITMAPINFO *ptr = static_cast<BITMAPINFO *>(GlobalLock(mem));
+
+ if (ptr != NULL) {
+ BITMAPINFOHEADER *info = &ptr->bmiHeader;
+ PackedByteArray pba;
+
+ for (LONG y = info->biHeight - 1; y > -1; y--) {
+ for (LONG x = 0; x < info->biWidth; x++) {
+ tagRGBQUAD *rgbquad = ptr->bmiColors + (info->biWidth * y) + x;
+ pba.append(rgbquad->rgbRed);
+ pba.append(rgbquad->rgbGreen);
+ pba.append(rgbquad->rgbBlue);
+ pba.append(rgbquad->rgbReserved);
+ }
+ }
+ image.instantiate();
+ image->create_from_data(info->biWidth, info->biHeight, false, Image::Format::FORMAT_RGBA8, pba);
+
+ GlobalUnlock(mem);
+ }
+ }
+ }
+
+ CloseClipboard();
+
+ return image;
+}
+
+bool DisplayServerWindows::clipboard_has() const {
+ return (IsClipboardFormatAvailable(CF_TEXT) ||
+ IsClipboardFormatAvailable(CF_UNICODETEXT) ||
+ IsClipboardFormatAvailable(CF_OEMTEXT));
+}
+
+bool DisplayServerWindows::clipboard_has_image() const {
+ UINT png_format = RegisterClipboardFormatA("PNG");
+ return ((png_format && IsClipboardFormatAvailable(png_format)) || IsClipboardFormatAvailable(CF_DIB));
+}
+
typedef struct {
int count;
int screen;
@@ -618,7 +851,7 @@ Color DisplayServerWindows::screen_get_pixel(const Point2i &p_position) const {
COLORREF col = GetPixel(dc, p.x, p.y);
if (col != CLR_INVALID) {
ReleaseDC(NULL, dc);
- return Color(float(col & 0x000000FF) / 256.0, float((col & 0x0000FF00) >> 8) / 256.0, float((col & 0x00FF0000) >> 16) / 256.0, 1.0);
+ return Color(float(col & 0x000000FF) / 255.0f, float((col & 0x0000FF00) >> 8) / 255.0f, float((col & 0x00FF0000) >> 16) / 255.0f, 1.0f);
}
ReleaseDC(NULL, dc);
}
@@ -875,8 +1108,11 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) {
}
#endif
#ifdef GLES3_ENABLED
- if (gl_manager) {
- gl_manager->window_destroy(p_window);
+ if (gl_manager_angle) {
+ gl_manager_angle->window_destroy(p_window);
+ }
+ if (gl_manager_native) {
+ gl_manager_native->window_destroy(p_window);
}
#endif
@@ -894,8 +1130,11 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) {
void DisplayServerWindows::gl_window_make_current(DisplayServer::WindowID p_window_id) {
#if defined(GLES3_ENABLED)
- if (gl_manager) {
- gl_manager->window_make_current(p_window_id);
+ if (gl_manager_angle) {
+ gl_manager_angle->window_make_current(p_window_id);
+ }
+ if (gl_manager_native) {
+ gl_manager_native->window_make_current(p_window_id);
}
#endif
}
@@ -911,14 +1150,18 @@ int64_t DisplayServerWindows::window_get_native_handle(HandleType p_handle_type,
}
#if defined(GLES3_ENABLED)
case WINDOW_VIEW: {
- if (gl_manager) {
- return (int64_t)gl_manager->get_hdc(p_window);
+ if (gl_manager_native) {
+ return (int64_t)gl_manager_native->get_hdc(p_window);
+ } else {
+ return (int64_t)GetDC(windows[p_window].hWnd);
}
- return 0;
}
case OPENGL_CONTEXT: {
- if (gl_manager) {
- return (int64_t)gl_manager->get_hglrc(p_window);
+ if (gl_manager_native) {
+ return (int64_t)gl_manager_native->get_hglrc(p_window);
+ }
+ if (gl_manager_angle) {
+ return (int64_t)gl_manager_angle->get_context(p_window);
}
return 0;
}
@@ -985,6 +1228,51 @@ void DisplayServerWindows::window_set_title(const String &p_title, WindowID p_wi
SetWindowTextW(windows[p_window].hWnd, (LPCWSTR)(p_title.utf16().get_data()));
}
+Size2i DisplayServerWindows::window_get_title_size(const String &p_title, WindowID p_window) const {
+ _THREAD_SAFE_METHOD_
+
+ Size2i size;
+ ERR_FAIL_COND_V(!windows.has(p_window), size);
+
+ const WindowData &wd = windows[p_window];
+ if (wd.fullscreen || wd.minimized || wd.borderless) {
+ return size;
+ }
+
+ HDC hdc = GetDCEx(wd.hWnd, NULL, DCX_WINDOW);
+ if (hdc) {
+ Char16String s = p_title.utf16();
+ SIZE text_size;
+ if (GetTextExtentPoint32W(hdc, (LPCWSTR)(s.get_data()), s.length(), &text_size)) {
+ size.x = text_size.cx;
+ size.y = text_size.cy;
+ }
+
+ ReleaseDC(wd.hWnd, hdc);
+ }
+ RECT rect;
+ if (DwmGetWindowAttribute(wd.hWnd, DWMWA_CAPTION_BUTTON_BOUNDS, &rect, sizeof(RECT)) == S_OK) {
+ if (rect.right - rect.left > 0) {
+ ClientToScreen(wd.hWnd, (POINT *)&rect.left);
+ ClientToScreen(wd.hWnd, (POINT *)&rect.right);
+
+ if (win81p_PhysicalToLogicalPointForPerMonitorDPI) {
+ win81p_PhysicalToLogicalPointForPerMonitorDPI(0, (POINT *)&rect.left);
+ win81p_PhysicalToLogicalPointForPerMonitorDPI(0, (POINT *)&rect.right);
+ }
+
+ size.x += (rect.right - rect.left);
+ size.y = MAX(size.y, rect.bottom - rect.top);
+ }
+ }
+ if (icon.is_valid()) {
+ size.x += 32;
+ } else {
+ size.x += 16;
+ }
+ return size;
+}
+
void DisplayServerWindows::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) {
_THREAD_SAFE_METHOD_
@@ -997,7 +1285,7 @@ void DisplayServerWindows::_update_window_mouse_passthrough(WindowID p_window) {
ERR_FAIL_COND(!windows.has(p_window));
if (windows[p_window].mpass || windows[p_window].mpath.size() == 0) {
- SetWindowRgn(windows[p_window].hWnd, nullptr, TRUE);
+ SetWindowRgn(windows[p_window].hWnd, nullptr, FALSE);
} else {
POINT *points = (POINT *)memalloc(sizeof(POINT) * windows[p_window].mpath.size());
for (int i = 0; i < windows[p_window].mpath.size(); i++) {
@@ -1011,8 +1299,7 @@ void DisplayServerWindows::_update_window_mouse_passthrough(WindowID p_window) {
}
HRGN region = CreatePolygonRgn(points, windows[p_window].mpath.size(), ALTERNATE);
- SetWindowRgn(windows[p_window].hWnd, region, TRUE);
- DeleteObject(region);
+ SetWindowRgn(windows[p_window].hWnd, region, FALSE);
memfree(points);
}
}
@@ -1253,8 +1540,11 @@ void DisplayServerWindows::window_set_size(const Size2i p_size, WindowID p_windo
}
#endif
#if defined(GLES3_ENABLED)
- if (gl_manager) {
- gl_manager->window_resize(p_window, w, h);
+ if (gl_manager_native) {
+ gl_manager_native->window_resize(p_window, w, h);
+ }
+ if (gl_manager_angle) {
+ gl_manager_angle->window_resize(p_window, w, h);
}
#endif
@@ -1317,7 +1607,7 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscre
if (p_fullscreen || p_borderless) {
r_style |= WS_POPUP; // p_borderless was WS_EX_TOOLWINDOW in the past.
- if (p_fullscreen && p_multiwindow_fs) {
+ if ((p_fullscreen && p_multiwindow_fs) || p_maximized) {
r_style |= WS_BORDER; // Allows child windows to be displayed on top of full screen.
}
} else {
@@ -2124,8 +2414,11 @@ void DisplayServerWindows::make_rendering_thread() {
void DisplayServerWindows::swap_buffers() {
#if defined(GLES3_ENABLED)
- if (gl_manager) {
- gl_manager->swap_buffers();
+ if (gl_manager_angle) {
+ gl_manager_angle->swap_buffers();
+ }
+ if (gl_manager_native) {
+ gl_manager_native->swap_buffers();
}
#endif
}
@@ -2196,7 +2489,7 @@ void DisplayServerWindows::set_native_icon(const String &p_filename) {
f->seek(pos);
f->get_buffer((uint8_t *)&data_big.write[0], bytecount_big);
HICON icon_big = CreateIconFromResource((PBYTE)&data_big.write[0], bytecount_big, TRUE, 0x00030000);
- ERR_FAIL_COND_MSG(!icon_big, "Could not create " + itos(big_icon_width) + "x" + itos(big_icon_width) + " @" + itos(big_icon_cc) + " icon, error: " + format_error_message(GetLastError()) + ".");
+ ERR_FAIL_NULL_MSG(icon_big, "Could not create " + itos(big_icon_width) + "x" + itos(big_icon_width) + " @" + itos(big_icon_cc) + " icon, error: " + format_error_message(GetLastError()) + ".");
// Read the small icon.
DWORD bytecount_small = icon_dir->idEntries[small_icon_index].dwBytesInRes;
@@ -2206,7 +2499,7 @@ void DisplayServerWindows::set_native_icon(const String &p_filename) {
f->seek(pos);
f->get_buffer((uint8_t *)&data_small.write[0], bytecount_small);
HICON icon_small = CreateIconFromResource((PBYTE)&data_small.write[0], bytecount_small, TRUE, 0x00030000);
- ERR_FAIL_COND_MSG(!icon_small, "Could not create 16x16 @" + itos(small_icon_cc) + " icon, error: " + format_error_message(GetLastError()) + ".");
+ ERR_FAIL_NULL_MSG(icon_small, "Could not create 16x16 @" + itos(small_icon_cc) + " icon, error: " + format_error_message(GetLastError()) + ".");
// Online tradition says to be sure last error is cleared and set the small icon first.
int err = 0;
@@ -2271,7 +2564,7 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) {
}
HICON hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
- ERR_FAIL_COND(!hicon);
+ ERR_FAIL_NULL(hicon);
icon = img;
@@ -2282,8 +2575,8 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) {
SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_BIG, (LPARAM)hicon);
} else {
icon = Ref<Image>();
- SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_SMALL, NULL);
- SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_BIG, NULL);
+ SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_SMALL, 0);
+ SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_BIG, 0);
}
}
@@ -2296,8 +2589,11 @@ void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsyn
#endif
#if defined(GLES3_ENABLED)
- if (gl_manager) {
- gl_manager->set_use_vsync(p_window, p_vsync_mode != DisplayServer::VSYNC_DISABLED);
+ if (gl_manager_native) {
+ gl_manager_native->set_use_vsync(p_window, p_vsync_mode != DisplayServer::VSYNC_DISABLED);
+ }
+ if (gl_manager_angle) {
+ gl_manager_angle->set_use_vsync(p_vsync_mode != DisplayServer::VSYNC_DISABLED);
}
#endif
}
@@ -2311,8 +2607,11 @@ DisplayServer::VSyncMode DisplayServerWindows::window_get_vsync_mode(WindowID p_
#endif
#if defined(GLES3_ENABLED)
- if (gl_manager) {
- return gl_manager->is_using_vsync(p_window) ? DisplayServer::VSYNC_ENABLED : DisplayServer::VSYNC_DISABLED;
+ if (gl_manager_native) {
+ return gl_manager_native->is_using_vsync(p_window) ? DisplayServer::VSYNC_ENABLED : DisplayServer::VSYNC_DISABLED;
+ }
+ if (gl_manager_angle) {
+ return gl_manager_angle->is_using_vsync() ? DisplayServer::VSYNC_ENABLED : DisplayServer::VSYNC_DISABLED;
}
#endif
@@ -2374,12 +2673,9 @@ void DisplayServerWindows::_drag_event(WindowID p_window, float p_x, float p_y,
}
void DisplayServerWindows::_send_window_event(const WindowData &wd, WindowEvent p_event) {
- if (!wd.event_callback.is_null()) {
+ if (wd.event_callback.is_valid()) {
Variant event = int(p_event);
- Variant *eventp = &event;
- Variant ret;
- Callable::CallError ce;
- wd.event_callback.callp((const Variant **)&eventp, 1, ret, ce);
+ wd.event_callback.call(event);
}
}
@@ -2392,12 +2688,7 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event)
if (in_dispatch_input_event) {
return;
}
-
in_dispatch_input_event = true;
- Variant ev = p_event;
- Variant *evp = &ev;
- Variant ret;
- Callable::CallError ce;
{
List<WindowID>::Element *E = popup_list.back();
@@ -2406,7 +2697,7 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event)
if (windows.has(E->get())) {
Callable callable = windows[E->get()].input_event_callback;
if (callable.is_valid()) {
- callable.callp((const Variant **)&evp, 1, ret, ce);
+ callable.call(p_event);
}
}
in_dispatch_input_event = false;
@@ -2420,7 +2711,7 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event)
if (windows.has(event_from_window->get_window_id())) {
Callable callable = windows[event_from_window->get_window_id()].input_event_callback;
if (callable.is_valid()) {
- callable.callp((const Variant **)&evp, 1, ret, ce);
+ callable.call(p_event);
}
}
} else {
@@ -2428,7 +2719,7 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event)
for (const KeyValue<WindowID, WindowData> &E : windows) {
const Callable callable = E.value.input_event_callback;
if (callable.is_valid()) {
- callable.callp((const Variant **)&evp, 1, ret, ce);
+ callable.call(p_event);
}
}
}
@@ -2546,7 +2837,7 @@ LRESULT DisplayServerWindows::MouseProc(int code, WPARAM wParam, LPARAM lParam)
// Find top popup to close.
while (E) {
// Popup window area.
- Rect2i win_rect = Rect2i(window_get_position(E->get()), window_get_size(E->get()));
+ Rect2i win_rect = Rect2i(window_get_position_with_decorations(E->get()), window_get_size_with_decorations(E->get()));
// Area of the parent window, which responsible for opening sub-menu.
Rect2i safe_rect = window_get_popup_safe_rect(E->get());
if (win_rect.has_point(pos)) {
@@ -2635,6 +2926,30 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
// Process window messages.
switch (uMsg) {
+ case WM_NCPAINT: {
+ if (RenderingServer::get_singleton() && (windows[window_id].borderless || (windows[window_id].fullscreen && windows[window_id].multiwindow_fs))) {
+ Color color = RenderingServer::get_singleton()->get_default_clear_color();
+ HDC hdc = GetWindowDC(hWnd);
+ if (hdc) {
+ HPEN pen = CreatePen(PS_SOLID, 1, RGB(color.r * 255.f, color.g * 255.f, color.b * 255.f));
+ if (pen) {
+ HGDIOBJ prev_pen = SelectObject(hdc, pen);
+ HGDIOBJ prev_brush = SelectObject(hdc, GetStockObject(NULL_BRUSH));
+
+ RECT rc;
+ GetWindowRect(hWnd, &rc);
+ OffsetRect(&rc, -rc.left, -rc.top);
+ Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);
+
+ SelectObject(hdc, prev_pen);
+ SelectObject(hdc, prev_brush);
+ DeleteObject(pen);
+ }
+ ReleaseDC(hWnd, hdc);
+ }
+ return 0;
+ }
+ } break;
case WM_NCHITTEST: {
if (windows[window_id].mpass) {
return HTTRANSPARENT;
@@ -3467,11 +3782,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
if (rect_changed) {
if (!window.rect_changed_callback.is_null()) {
- Variant size = Rect2i(window.last_pos.x, window.last_pos.y, window.width, window.height);
- const Variant *args[] = { &size };
- Variant ret;
- Callable::CallError ce;
- window.rect_changed_callback.callp(args, 1, ret, ce);
+ window.rect_changed_callback.call(Rect2i(window.last_pos.x, window.last_pos.y, window.width, window.height));
}
// Update cursor clip region after window rect has changed.
@@ -3648,6 +3959,10 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
} break;
case WM_DESTROY: {
Input::get_singleton()->flush_buffered_events();
+ if (window_mouseover_id == window_id) {
+ window_mouseover_id = INVALID_WINDOW_ID;
+ _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_EXIT);
+ }
} break;
case WM_SETCURSOR: {
if (LOWORD(lParam) == HTCLIENT) {
@@ -3684,11 +3999,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
if (files.size() && !windows[window_id].drop_files_callback.is_null()) {
- Variant v = files;
- Variant *vp = &v;
- Variant ret;
- Callable::CallError ce;
- windows[window_id].drop_files_callback.callp((const Variant **)&vp, 1, ret, ce);
+ windows[window_id].drop_files_callback.call(files);
}
} break;
default: {
@@ -4026,10 +4337,20 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
#endif
#ifdef GLES3_ENABLED
- if (gl_manager) {
- if (gl_manager->window_create(id, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) != OK) {
- memdelete(gl_manager);
- gl_manager = nullptr;
+ if (gl_manager_native) {
+ if (gl_manager_native->window_create(id, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) != OK) {
+ memdelete(gl_manager_native);
+ gl_manager_native = nullptr;
+ windows.erase(id);
+ ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create an OpenGL window.");
+ }
+ window_set_vsync_mode(p_vsync_mode, id);
+ }
+
+ if (gl_manager_angle) {
+ if (gl_manager_angle->window_create(id, nullptr, wd.hWnd, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) != OK) {
+ memdelete(gl_manager_angle);
+ gl_manager_angle = nullptr;
windows.erase(id);
ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create an OpenGL window.");
}
@@ -4130,6 +4451,7 @@ bool DisplayServerWindows::winink_available = false;
GetPointerTypePtr DisplayServerWindows::win8p_GetPointerType = nullptr;
GetPointerPenInfoPtr DisplayServerWindows::win8p_GetPointerPenInfo = nullptr;
LogicalToPhysicalPointForPerMonitorDPIPtr DisplayServerWindows::win81p_LogicalToPhysicalPointForPerMonitorDPI = nullptr;
+PhysicalToLogicalPointForPerMonitorDPIPtr DisplayServerWindows::win81p_PhysicalToLogicalPointForPerMonitorDPI = nullptr;
typedef enum _SHC_PROCESS_DPI_AWARENESS {
SHC_PROCESS_DPI_UNAWARE = 0,
@@ -4267,6 +4589,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
win8p_GetPointerType = (GetPointerTypePtr)GetProcAddress(user32_lib, "GetPointerType");
win8p_GetPointerPenInfo = (GetPointerPenInfoPtr)GetProcAddress(user32_lib, "GetPointerPenInfo");
win81p_LogicalToPhysicalPointForPerMonitorDPI = (LogicalToPhysicalPointForPerMonitorDPIPtr)GetProcAddress(user32_lib, "LogicalToPhysicalPointForPerMonitorDPI");
+ win81p_PhysicalToLogicalPointForPerMonitorDPI = (PhysicalToLogicalPointForPerMonitorDPIPtr)GetProcAddress(user32_lib, "PhysicalToLogicalPointForPerMonitorDPI");
winink_available = win8p_GetPointerType && win8p_GetPointerPenInfo;
}
@@ -4324,19 +4647,50 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
// Init context and rendering device
#if defined(GLES3_ENABLED)
+ bool fallback = GLOBAL_GET("rendering/gl_compatibility/fallback_to_angle");
+ if (fallback && (rendering_driver == "opengl3")) {
+ Dictionary gl_info = detect_wgl();
+
+ bool force_angle = false;
+
+ Array device_list = GLOBAL_GET("rendering/gl_compatibility/force_angle_on_devices");
+ for (int i = 0; i < device_list.size(); i++) {
+ const Dictionary &device = device_list[i];
+ if (device.has("vendor") && device.has("name") && device["vendor"].operator String().to_upper() == gl_info["vendor"].operator String().to_upper() && (device["name"] == "*" || device["name"].operator String().to_upper() == gl_info["name"].operator String().to_upper())) {
+ force_angle = true;
+ break;
+ }
+ }
+
+ if (force_angle || (gl_info["version"].operator int() < 30003)) {
+ WARN_PRINT("Your video card drivers seem not to support the required OpenGL 3.3 version, switching to ANGLE.");
+ rendering_driver = "opengl3_angle";
+ }
+ }
+
if (rendering_driver == "opengl3") {
- GLManager_Windows::ContextType opengl_api_type = GLManager_Windows::GLES_3_0_COMPATIBLE;
+ gl_manager_native = memnew(GLManagerNative_Windows);
+
+ if (gl_manager_native->initialize() != OK) {
+ memdelete(gl_manager_native);
+ gl_manager_native = nullptr;
+ r_error = ERR_UNAVAILABLE;
+ return;
+ }
- gl_manager = memnew(GLManager_Windows(opengl_api_type));
+ RasterizerGLES3::make_current(true);
+ }
+ if (rendering_driver == "opengl3_angle") {
+ gl_manager_angle = memnew(GLManagerANGLE_Windows);
- if (gl_manager->initialize() != OK) {
- memdelete(gl_manager);
- gl_manager = nullptr;
+ if (gl_manager_angle->initialize() != OK) {
+ memdelete(gl_manager_angle);
+ gl_manager_angle = nullptr;
r_error = ERR_UNAVAILABLE;
return;
}
- RasterizerGLES3::make_current();
+ RasterizerGLES3::make_current(false);
}
#endif
@@ -4410,6 +4764,7 @@ Vector<String> DisplayServerWindows::get_rendering_drivers_func() {
#endif
#ifdef GLES3_ENABLED
drivers.push_back("opengl3");
+ drivers.push_back("opengl3_angle");
#endif
return drivers;
@@ -4495,9 +4850,13 @@ DisplayServerWindows::~DisplayServerWindows() {
SystemParametersInfoA(SPI_SETMOUSETRAILS, restore_mouse_trails, 0, 0);
}
#ifdef GLES3_ENABLED
- if (gl_manager) {
- memdelete(gl_manager);
- gl_manager = nullptr;
+ if (gl_manager_angle) {
+ memdelete(gl_manager_angle);
+ gl_manager_angle = nullptr;
+ }
+ if (gl_manager_native) {
+ memdelete(gl_manager_native);
+ gl_manager_native = nullptr;
}
#endif
if (tts) {
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 9d1088675b..48c8c20280 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -59,8 +59,9 @@
#endif
#if defined(GLES3_ENABLED)
-#include "gl_manager_windows.h"
-#endif
+#include "gl_manager_windows_angle.h"
+#include "gl_manager_windows_native.h"
+#endif // GLES3_ENABLED
#include <io.h>
#include <stdio.h>
@@ -261,6 +262,7 @@ typedef struct tagPOINTER_PEN_INFO {
typedef BOOL(WINAPI *GetPointerTypePtr)(uint32_t p_id, POINTER_INPUT_TYPE *p_type);
typedef BOOL(WINAPI *GetPointerPenInfoPtr)(uint32_t p_id, POINTER_PEN_INFO *p_pen_info);
typedef BOOL(WINAPI *LogicalToPhysicalPointForPerMonitorDPIPtr)(HWND hwnd, LPPOINT lpPoint);
+typedef BOOL(WINAPI *PhysicalToLogicalPointForPerMonitorDPIPtr)(HWND hwnd, LPPOINT lpPoint);
typedef struct {
BYTE bWidth; // Width, in pixels, of the image
@@ -308,6 +310,7 @@ class DisplayServerWindows : public DisplayServer {
// DPI conversion API
static LogicalToPhysicalPointForPerMonitorDPIPtr win81p_LogicalToPhysicalPointForPerMonitorDPI;
+ static PhysicalToLogicalPointForPerMonitorDPIPtr win81p_PhysicalToLogicalPointForPerMonitorDPI;
void _update_tablet_ctx(const String &p_old_driver, const String &p_new_driver);
String tablet_driver;
@@ -335,7 +338,8 @@ class DisplayServerWindows : public DisplayServer {
Point2i center;
#if defined(GLES3_ENABLED)
- GLManager_Windows *gl_manager = nullptr;
+ GLManagerANGLE_Windows *gl_manager_angle = nullptr;
+ GLManagerNative_Windows *gl_manager_native = nullptr;
#endif
#if defined(VULKAN_ENABLED)
@@ -511,6 +515,8 @@ public:
virtual bool is_dark_mode() const override;
virtual Color get_accent_color() const override;
+ virtual Error file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) override;
+
virtual void mouse_set_mode(MouseMode p_mode) override;
virtual MouseMode mouse_get_mode() const override;
@@ -520,6 +526,9 @@ public:
virtual void clipboard_set(const String &p_text) override;
virtual String clipboard_get() const override;
+ virtual Ref<Image> clipboard_get_image() const override;
+ virtual bool clipboard_has() const override;
+ virtual bool clipboard_has_image() const override;
virtual int get_screen_count() const override;
virtual int get_primary_screen() const override;
@@ -562,6 +571,7 @@ public:
virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) override;
+ virtual Size2i window_get_title_size(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) const override;
virtual void window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window = MAIN_WINDOW_ID) override;
virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const override;
diff --git a/platform/windows/doc_classes/EditorExportPlatformWindows.xml b/platform/windows/doc_classes/EditorExportPlatformWindows.xml
index 80928d7418..2a286de100 100644
--- a/platform/windows/doc_classes/EditorExportPlatformWindows.xml
+++ b/platform/windows/doc_classes/EditorExportPlatformWindows.xml
@@ -18,14 +18,17 @@
<member name="application/copyright" type="String" setter="" getter="">
Copyright notice for the bundle visible to the user. Optional. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url].
</member>
+ <member name="application/export_angle" type="int" setter="" getter="">
+ If set to [code]1[/code], ANGLE libraries are exported with the exported application. If set to [code]0[/code], ANGLE libraries are exported only if [member ProjectSettings.rendering/gl_compatibility/driver] is set to [code]"opengl3_angle"[/code].
+ </member>
<member name="application/file_description" type="String" setter="" getter="">
File description to be presented to users. Required. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url].
</member>
<member name="application/file_version" type="String" setter="" getter="">
- Version number of the file. Required. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url].
+ Version number of the file. Falls back to [member ProjectSettings.application/config/version] if left empty. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url].
</member>
<member name="application/icon" type="String" setter="" getter="">
- Application icon file. If left empty, it will fallback to [member ProjectSettings.application/config/windows_native_icon], and then to [member ProjectSettings.application/config/icon].
+ Application icon file. If left empty, it will fallback to [member ProjectSettings.application/config/windows_native_icon], and then to [member ProjectSettings.application/config/icon].
</member>
<member name="application/icon_interpolation" type="int" setter="" getter="">
Interpolation method used to resize application icon.
@@ -37,7 +40,7 @@
Name of the application. Required. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url].
</member>
<member name="application/product_version" type="String" setter="" getter="">
- Application version visible to the user. Required. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url].
+ Application version visible to the user. Falls back to [member ProjectSettings.application/config/version] if left empty. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url].
</member>
<member name="application/trademarks" type="String" setter="" getter="">
Trademarks and registered trademarks that apply to the file. Optional. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url].
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index 0ef07c3275..4185c36d77 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -38,6 +38,7 @@
#include "editor/editor_node.h"
#include "editor/editor_paths.h"
#include "editor/editor_scale.h"
+#include "editor/editor_string_names.h"
#include "editor/export/editor_export.h"
#include "modules/modules_enabled.gen.h" // For svg.
@@ -168,16 +169,45 @@ Error EditorExportPlatformWindows::sign_shared_object(const Ref<EditorExportPres
Error EditorExportPlatformWindows::modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
if (p_preset->get("application/modify_resources")) {
- _rcedit_add_data(p_preset, p_path, true);
+ _rcedit_add_data(p_preset, p_path, false);
String wrapper_path = p_path.get_basename() + ".console.exe";
if (FileAccess::exists(wrapper_path)) {
- _rcedit_add_data(p_preset, wrapper_path, false);
+ _rcedit_add_data(p_preset, wrapper_path, true);
}
}
return OK;
}
Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
+ int export_angle = p_preset->get("application/export_angle");
+ bool include_angle_libs = false;
+ if (export_angle == 0) {
+ include_angle_libs = String(GLOBAL_GET("rendering/gl_compatibility/driver.windows")) == "opengl3_angle";
+ } else if (export_angle == 1) {
+ include_angle_libs = true;
+ }
+
+ if (include_angle_libs) {
+ String custom_debug = p_preset->get("custom_template/debug");
+ String custom_release = p_preset->get("custom_template/release");
+ String arch = p_preset->get("binary_format/architecture");
+
+ String template_path = p_debug ? custom_debug : custom_release;
+
+ template_path = template_path.strip_edges();
+
+ if (template_path.is_empty()) {
+ template_path = find_export_template(get_template_file_name(p_debug ? "debug" : "release", arch));
+ }
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ if (da->file_exists(template_path.get_base_dir().path_join("libEGL." + arch + ".dll"))) {
+ da->copy(template_path.get_base_dir().path_join("libEGL." + arch + ".dll"), p_path.get_base_dir().path_join("libEGL.dll"), get_chmod_flags());
+ }
+ if (da->file_exists(template_path.get_base_dir().path_join("libGLESv2." + arch + ".dll"))) {
+ da->copy(template_path.get_base_dir().path_join("libGLESv2." + arch + ".dll"), p_path.get_base_dir().path_join("libGLESv2.dll"), get_chmod_flags());
+ }
+ }
+
bool export_as_zip = p_path.ends_with("zip");
bool embedded = p_preset->get("binary_format/embed_pck");
@@ -310,7 +340,7 @@ bool EditorExportPlatformWindows::get_export_option_visibility(const EditorExpor
// Hide resources.
bool mod_res = p_preset->get("application/modify_resources");
- if (!mod_res && p_option != "application/modify_resources" && p_option.begins_with("application/")) {
+ if (!mod_res && p_option != "application/modify_resources" && p_option != "application/export_angle" && p_option.begins_with("application/")) {
return false;
}
@@ -342,13 +372,14 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico,*.png,*.webp,*.svg"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/console_wrapper_icon", PROPERTY_HINT_FILE, "*.ico,*.png,*.webp,*.svg"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), "", false, true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), "", false, true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "Leave empty to use project version"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "Leave empty to use project version"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/company_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Company Name"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_description"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/trademarks"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/export_angle", PROPERTY_HINT_ENUM, "Auto,Yes,No"), 0, true));
String run_script = "Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}'\n"
"$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}'\n"
@@ -425,8 +456,8 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
}
}
- String file_verion = p_preset->get("application/file_version");
- String product_version = p_preset->get("application/product_version");
+ String file_verion = p_preset->get_version("application/file_version", true);
+ String product_version = p_preset->get_version("application/product_version", true);
String company_name = p_preset->get("application/company_name");
String product_name = p_preset->get("application/product_name");
String file_description = p_preset->get("application/file_description");
@@ -1020,7 +1051,7 @@ EditorExportPlatformWindows::EditorExportPlatformWindows() {
Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
if (theme.is_valid()) {
- stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons"));
+ stop_icon = theme->get_icon(SNAME("Stop"), EditorStringName(EditorIcons));
} else {
stop_icon.instantiate();
}
diff --git a/platform/windows/gl_manager_windows_angle.cpp b/platform/windows/gl_manager_windows_angle.cpp
new file mode 100644
index 0000000000..3086edc7f2
--- /dev/null
+++ b/platform/windows/gl_manager_windows_angle.cpp
@@ -0,0 +1,70 @@
+/**************************************************************************/
+/* gl_manager_windows_angle.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "gl_manager_windows_angle.h"
+
+#if defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED)
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <EGL/eglext_angle.h>
+
+const char *GLManagerANGLE_Windows::_get_platform_extension_name() const {
+ return "EGL_ANGLE_platform_angle";
+}
+
+EGLenum GLManagerANGLE_Windows::_get_platform_extension_enum() const {
+ return EGL_PLATFORM_ANGLE_ANGLE;
+}
+
+Vector<EGLAttrib> GLManagerANGLE_Windows::_get_platform_display_attributes() const {
+ Vector<EGLAttrib> ret;
+ ret.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
+ ret.push_back(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE);
+ ret.push_back(EGL_NONE);
+
+ return ret;
+}
+
+EGLenum GLManagerANGLE_Windows::_get_platform_api_enum() const {
+ return EGL_OPENGL_ES_API;
+}
+
+Vector<EGLint> GLManagerANGLE_Windows::_get_platform_context_attribs() const {
+ Vector<EGLint> ret;
+ ret.push_back(EGL_CONTEXT_CLIENT_VERSION);
+ ret.push_back(3);
+ ret.push_back(EGL_NONE);
+
+ return ret;
+}
+
+#endif // WINDOWS_ENABLED && GLES3_ENABLED
diff --git a/platform/windows/gl_manager_windows_angle.h b/platform/windows/gl_manager_windows_angle.h
new file mode 100644
index 0000000000..d8dc651cfd
--- /dev/null
+++ b/platform/windows/gl_manager_windows_angle.h
@@ -0,0 +1,61 @@
+/**************************************************************************/
+/* gl_manager_windows_angle.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef GL_MANAGER_WINDOWS_ANGLE_H
+#define GL_MANAGER_WINDOWS_ANGLE_H
+
+#if defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED)
+
+#include "core/error/error_list.h"
+#include "core/os/os.h"
+#include "core/templates/local_vector.h"
+#include "drivers/egl/egl_manager.h"
+#include "servers/display_server.h"
+
+#include <windows.h>
+
+class GLManagerANGLE_Windows : public EGLManager {
+private:
+ virtual const char *_get_platform_extension_name() const override;
+ virtual EGLenum _get_platform_extension_enum() const override;
+ virtual EGLenum _get_platform_api_enum() const override;
+ virtual Vector<EGLAttrib> _get_platform_display_attributes() const override;
+ virtual Vector<EGLint> _get_platform_context_attribs() const override;
+
+public:
+ void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) {}
+
+ GLManagerANGLE_Windows(){};
+ ~GLManagerANGLE_Windows(){};
+};
+
+#endif // WINDOWS_ENABLED && GLES3_ENABLED
+
+#endif // GL_MANAGER_WINDOWS_ANGLE_H
diff --git a/platform/windows/gl_manager_windows.cpp b/platform/windows/gl_manager_windows_native.cpp
index 0334bdd973..b350786d11 100644
--- a/platform/windows/gl_manager_windows.cpp
+++ b/platform/windows/gl_manager_windows_native.cpp
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* gl_manager_windows.cpp */
+/* gl_manager_windows_native.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#include "gl_manager_windows.h"
+#include "gl_manager_windows_native.h"
#if defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED)
@@ -52,10 +52,14 @@
#if defined(__GNUC__)
// Workaround GCC warning from -Wcast-function-type.
-#define wglGetProcAddress (void *)wglGetProcAddress
+#define GetProcAddress (void *)GetProcAddress
#endif
+typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXT)(HDC);
+typedef BOOL(APIENTRY *PFNWGLDELETECONTEXT)(HGLRC);
+typedef BOOL(APIENTRY *PFNWGLMAKECURRENT)(HDC, HGLRC);
typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int *);
+typedef void *(APIENTRY *PFNWGLGETPROCADDRESS)(LPCSTR);
static String format_error_message(DWORD id) {
LPWSTR messageBuffer = nullptr;
@@ -84,6 +88,7 @@ typedef int(__cdecl *NvAPI_DRS_CreateApplication_t)(NvDRSSessionHandle, NvDRSPro
typedef int(__cdecl *NvAPI_DRS_SaveSettings_t)(NvDRSSessionHandle);
typedef int(__cdecl *NvAPI_DRS_SetSetting_t)(NvDRSSessionHandle, NvDRSProfileHandle, NVDRS_SETTING *);
typedef int(__cdecl *NvAPI_DRS_FindProfileByName_t)(NvDRSSessionHandle, NvAPI_UnicodeString, NvDRSProfileHandle *);
+typedef int(__cdecl *NvAPI_DRS_FindApplicationByName_t)(NvDRSSessionHandle, NvAPI_UnicodeString, NvDRSProfileHandle *, NVDRS_APPLICATION *);
NvAPI_GetErrorMessage_t NvAPI_GetErrorMessage__;
static bool nvapi_err_check(const char *msg, int status) {
@@ -101,7 +106,7 @@ static bool nvapi_err_check(const char *msg, int status) {
// On windows we have to disable threaded optimization when using NVIDIA graphics cards
// to avoid stuttering, see https://github.com/microsoft/vscode-cpptools/issues/6592
// also see https://github.com/Ryujinx/Ryujinx/blob/master/Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs
-void GLManager_Windows::_nvapi_disable_threaded_optimization() {
+void GLManagerNative_Windows::_nvapi_disable_threaded_optimization() {
HMODULE nvapi = 0;
#ifdef _WIN64
nvapi = LoadLibraryA("nvapi64.dll");
@@ -115,7 +120,7 @@ void GLManager_Windows::_nvapi_disable_threaded_optimization() {
void *(__cdecl * NvAPI_QueryInterface)(unsigned int interface_id) = 0;
- NvAPI_QueryInterface = (void *(__cdecl *)(unsigned int))GetProcAddress(nvapi, "nvapi_QueryInterface");
+ NvAPI_QueryInterface = (void *(__cdecl *)(unsigned int))(void *)GetProcAddress(nvapi, "nvapi_QueryInterface");
if (NvAPI_QueryInterface == NULL) {
print_verbose("Error getting NVAPI NvAPI_QueryInterface");
@@ -134,6 +139,7 @@ void GLManager_Windows::_nvapi_disable_threaded_optimization() {
NvAPI_DRS_SaveSettings_t NvAPI_DRS_SaveSettings = (NvAPI_DRS_SaveSettings_t)NvAPI_QueryInterface(0xFCBC7E14);
NvAPI_DRS_SetSetting_t NvAPI_DRS_SetSetting = (NvAPI_DRS_SetSetting_t)NvAPI_QueryInterface(0x577DD202);
NvAPI_DRS_FindProfileByName_t NvAPI_DRS_FindProfileByName = (NvAPI_DRS_FindProfileByName_t)NvAPI_QueryInterface(0x7E4A9A0B);
+ NvAPI_DRS_FindApplicationByName_t NvAPI_DRS_FindApplicationByName = (NvAPI_DRS_FindApplicationByName_t)NvAPI_QueryInterface(0xEEE566B2);
if (!nvapi_err_check("NVAPI: Init failed", NvAPI_Initialize())) {
return;
@@ -168,9 +174,9 @@ void GLManager_Windows::_nvapi_disable_threaded_optimization() {
NvDRSProfileHandle profile_handle = 0;
- int status = NvAPI_DRS_FindProfileByName(session_handle, (NvU16 *)(app_profile_name_u16.ptrw()), &profile_handle);
+ int profile_status = NvAPI_DRS_FindProfileByName(session_handle, (NvU16 *)(app_profile_name_u16.ptrw()), &profile_handle);
- if (status != 0) {
+ if (profile_status != 0) {
print_verbose("NVAPI: Profile not found, creating....");
NVDRS_PROFILE profile_info;
@@ -183,9 +189,17 @@ void GLManager_Windows::_nvapi_disable_threaded_optimization() {
NvAPI_Unload();
return;
}
+ }
+
+ NvDRSProfileHandle app_profile_handle = 0;
+ NVDRS_APPLICATION_V4 app;
+ app.version = NVDRS_APPLICATION_VER_V4;
+
+ int app_status = NvAPI_DRS_FindApplicationByName(session_handle, (NvU16 *)(app_executable_name_u16.ptrw()), &app_profile_handle, &app);
+
+ if (app_status != 0) {
+ print_verbose("NVAPI: Application not found, adding to profile...");
- NVDRS_APPLICATION_V4 app;
- app.version = NVDRS_APPLICATION_VER_V4;
app.isPredefined = 0;
app.isMetro = 1;
app.isCommandLine = 1;
@@ -234,7 +248,7 @@ void GLManager_Windows::_nvapi_disable_threaded_optimization() {
NvAPI_DRS_DestroySession(session_handle);
}
-int GLManager_Windows::_find_or_create_display(GLWindow &win) {
+int GLManagerNative_Windows::_find_or_create_display(GLWindow &win) {
// find display NYI, only 1 supported so far
if (_displays.size()) {
return 0;
@@ -296,19 +310,36 @@ static Error _configure_pixel_format(HDC hDC) {
return OK;
}
-Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
+PFNWGLCREATECONTEXT gd_wglCreateContext;
+PFNWGLMAKECURRENT gd_wglMakeCurrent;
+PFNWGLDELETECONTEXT gd_wglDeleteContext;
+PFNWGLGETPROCADDRESS gd_wglGetProcAddress;
+
+Error GLManagerNative_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
Error err = _configure_pixel_format(win.hDC);
if (err != OK) {
return err;
}
- gl_display.hRC = wglCreateContext(win.hDC);
+ HMODULE module = LoadLibraryW(L"opengl32.dll");
+ if (!module) {
+ return ERR_CANT_CREATE;
+ }
+ gd_wglCreateContext = (PFNWGLCREATECONTEXT)GetProcAddress(module, "wglCreateContext");
+ gd_wglMakeCurrent = (PFNWGLMAKECURRENT)GetProcAddress(module, "wglMakeCurrent");
+ gd_wglDeleteContext = (PFNWGLDELETECONTEXT)GetProcAddress(module, "wglDeleteContext");
+ gd_wglGetProcAddress = (PFNWGLGETPROCADDRESS)GetProcAddress(module, "wglGetProcAddress");
+ if (!gd_wglCreateContext || !gd_wglMakeCurrent || !gd_wglDeleteContext || !gd_wglGetProcAddress) {
+ return ERR_CANT_CREATE;
+ }
+
+ gl_display.hRC = gd_wglCreateContext(win.hDC);
if (!gl_display.hRC) // Are We Able To Get A Rendering Context?
{
return ERR_CANT_CREATE; // Return FALSE
}
- if (!wglMakeCurrent(win.hDC, gl_display.hRC)) {
+ if (!gd_wglMakeCurrent(win.hDC, gl_display.hRC)) {
ERR_PRINT("Could not attach OpenGL context to newly created window: " + format_error_message(GetLastError()));
}
@@ -322,45 +353,45 @@ Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
}; //zero indicates the end of the array
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = nullptr; //pointer to the method
- wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
+ wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)gd_wglGetProcAddress("wglCreateContextAttribsARB");
if (wglCreateContextAttribsARB == nullptr) //OpenGL 3.0 is not supported
{
- wglDeleteContext(gl_display.hRC);
+ gd_wglDeleteContext(gl_display.hRC);
gl_display.hRC = 0;
return ERR_CANT_CREATE;
}
HGLRC new_hRC = wglCreateContextAttribsARB(win.hDC, 0, attribs);
if (!new_hRC) {
- wglDeleteContext(gl_display.hRC);
+ gd_wglDeleteContext(gl_display.hRC);
gl_display.hRC = 0;
return ERR_CANT_CREATE;
}
- if (!wglMakeCurrent(win.hDC, nullptr)) {
+ if (!gd_wglMakeCurrent(win.hDC, nullptr)) {
ERR_PRINT("Could not detach OpenGL context from newly created window: " + format_error_message(GetLastError()));
}
- wglDeleteContext(gl_display.hRC);
+ gd_wglDeleteContext(gl_display.hRC);
gl_display.hRC = new_hRC;
- if (!wglMakeCurrent(win.hDC, gl_display.hRC)) // Try To Activate The Rendering Context
+ if (!gd_wglMakeCurrent(win.hDC, gl_display.hRC)) // Try to activate the rendering context.
{
ERR_PRINT("Could not attach OpenGL context to newly created window with replaced OpenGL context: " + format_error_message(GetLastError()));
- wglDeleteContext(gl_display.hRC);
+ gd_wglDeleteContext(gl_display.hRC);
gl_display.hRC = 0;
return ERR_CANT_CREATE;
}
if (!wglSwapIntervalEXT) {
- wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
+ wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)gd_wglGetProcAddress("wglSwapIntervalEXT");
}
return OK;
}
-Error GLManager_Windows::window_create(DisplayServer::WindowID p_window_id, HWND p_hwnd, HINSTANCE p_hinstance, int p_width, int p_height) {
+Error GLManagerNative_Windows::window_create(DisplayServer::WindowID p_window_id, HWND p_hwnd, HINSTANCE p_hinstance, int p_width, int p_height) {
HDC hDC = GetDC(p_hwnd);
if (!hDC) {
return ERR_CANT_CREATE;
@@ -373,8 +404,6 @@ Error GLManager_Windows::window_create(DisplayServer::WindowID p_window_id, HWND
}
GLWindow win;
- win.width = p_width;
- win.height = p_height;
win.hwnd = p_hwnd;
win.hDC = hDC;
@@ -394,24 +423,11 @@ Error GLManager_Windows::window_create(DisplayServer::WindowID p_window_id, HWND
return OK;
}
-void GLManager_Windows::_internal_set_current_window(GLWindow *p_win) {
+void GLManagerNative_Windows::_internal_set_current_window(GLWindow *p_win) {
_current_window = p_win;
}
-void GLManager_Windows::window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) {
- get_window(p_window_id).width = p_width;
- get_window(p_window_id).height = p_height;
-}
-
-int GLManager_Windows::window_get_width(DisplayServer::WindowID p_window_id) {
- return get_window(p_window_id).width;
-}
-
-int GLManager_Windows::window_get_height(DisplayServer::WindowID p_window_id) {
- return get_window(p_window_id).height;
-}
-
-void GLManager_Windows::window_destroy(DisplayServer::WindowID p_window_id) {
+void GLManagerNative_Windows::window_destroy(DisplayServer::WindowID p_window_id) {
GLWindow &win = get_window(p_window_id);
if (_current_window == &win) {
_current_window = nullptr;
@@ -419,17 +435,17 @@ void GLManager_Windows::window_destroy(DisplayServer::WindowID p_window_id) {
_windows.erase(p_window_id);
}
-void GLManager_Windows::release_current() {
+void GLManagerNative_Windows::release_current() {
if (!_current_window) {
return;
}
- if (!wglMakeCurrent(_current_window->hDC, nullptr)) {
+ if (!gd_wglMakeCurrent(_current_window->hDC, nullptr)) {
ERR_PRINT("Could not detach OpenGL context from window marked current: " + format_error_message(GetLastError()));
}
}
-void GLManager_Windows::window_make_current(DisplayServer::WindowID p_window_id) {
+void GLManagerNative_Windows::window_make_current(DisplayServer::WindowID p_window_id) {
if (p_window_id == -1) {
return;
}
@@ -443,33 +459,33 @@ void GLManager_Windows::window_make_current(DisplayServer::WindowID p_window_id)
}
const GLDisplay &disp = get_display(win.gldisplay_id);
- if (!wglMakeCurrent(win.hDC, disp.hRC)) {
+ if (!gd_wglMakeCurrent(win.hDC, disp.hRC)) {
ERR_PRINT("Could not switch OpenGL context to other window: " + format_error_message(GetLastError()));
}
_internal_set_current_window(&win);
}
-void GLManager_Windows::make_current() {
+void GLManagerNative_Windows::make_current() {
if (!_current_window) {
return;
}
const GLDisplay &disp = get_current_display();
- if (!wglMakeCurrent(_current_window->hDC, disp.hRC)) {
+ if (!gd_wglMakeCurrent(_current_window->hDC, disp.hRC)) {
ERR_PRINT("Could not switch OpenGL context to window marked current: " + format_error_message(GetLastError()));
}
}
-void GLManager_Windows::swap_buffers() {
+void GLManagerNative_Windows::swap_buffers() {
SwapBuffers(_current_window->hDC);
}
-Error GLManager_Windows::initialize() {
+Error GLManagerNative_Windows::initialize() {
_nvapi_disable_threaded_optimization();
return OK;
}
-void GLManager_Windows::set_use_vsync(DisplayServer::WindowID p_window_id, bool p_use) {
+void GLManagerNative_Windows::set_use_vsync(DisplayServer::WindowID p_window_id, bool p_use) {
GLWindow &win = get_window(p_window_id);
GLWindow *current = _current_window;
@@ -479,7 +495,12 @@ void GLManager_Windows::set_use_vsync(DisplayServer::WindowID p_window_id, bool
if (wglSwapIntervalEXT) {
win.use_vsync = p_use;
- wglSwapIntervalEXT(p_use ? 1 : 0);
+
+ if (!wglSwapIntervalEXT(p_use ? 1 : 0)) {
+ WARN_PRINT("Could not set V-Sync mode.");
+ }
+ } else {
+ WARN_PRINT("Could not set V-Sync mode. V-Sync is not supported.");
}
if (current != _current_window) {
@@ -488,29 +509,27 @@ void GLManager_Windows::set_use_vsync(DisplayServer::WindowID p_window_id, bool
}
}
-bool GLManager_Windows::is_using_vsync(DisplayServer::WindowID p_window_id) const {
+bool GLManagerNative_Windows::is_using_vsync(DisplayServer::WindowID p_window_id) const {
return get_window(p_window_id).use_vsync;
}
-HDC GLManager_Windows::get_hdc(DisplayServer::WindowID p_window_id) {
+HDC GLManagerNative_Windows::get_hdc(DisplayServer::WindowID p_window_id) {
return get_window(p_window_id).hDC;
}
-HGLRC GLManager_Windows::get_hglrc(DisplayServer::WindowID p_window_id) {
+HGLRC GLManagerNative_Windows::get_hglrc(DisplayServer::WindowID p_window_id) {
const GLWindow &win = get_window(p_window_id);
const GLDisplay &disp = get_display(win.gldisplay_id);
return disp.hRC;
}
-GLManager_Windows::GLManager_Windows(ContextType p_context_type) {
- context_type = p_context_type;
-
+GLManagerNative_Windows::GLManagerNative_Windows() {
direct_render = false;
glx_minor = glx_major = 0;
_current_window = nullptr;
}
-GLManager_Windows::~GLManager_Windows() {
+GLManagerNative_Windows::~GLManagerNative_Windows() {
release_current();
}
diff --git a/platform/windows/gl_manager_windows.h b/platform/windows/gl_manager_windows_native.h
index 482b00a1ba..829c53b3d2 100644
--- a/platform/windows/gl_manager_windows.h
+++ b/platform/windows/gl_manager_windows_native.h
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* gl_manager_windows.h */
+/* gl_manager_windows_native.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifndef GL_MANAGER_WINDOWS_H
-#define GL_MANAGER_WINDOWS_H
+#ifndef GL_MANAGER_WINDOWS_NATIVE_H
+#define GL_MANAGER_WINDOWS_NATIVE_H
#if defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED)
@@ -43,17 +43,10 @@
typedef bool(APIENTRY *PFNWGLSWAPINTERVALEXTPROC)(int interval);
typedef int(APIENTRY *PFNWGLGETSWAPINTERVALEXTPROC)(void);
-class GLManager_Windows {
-public:
- enum ContextType {
- GLES_3_0_COMPATIBLE,
- };
-
+class GLManagerNative_Windows {
private:
// any data specific to the window
struct GLWindow {
- int width = 0;
- int height = 0;
bool use_vsync = false;
// windows specific
@@ -86,7 +79,6 @@ private:
bool direct_render;
int glx_minor, glx_major;
- ContextType context_type;
private:
void _nvapi_disable_threaded_optimization();
@@ -96,11 +88,7 @@ private:
public:
Error window_create(DisplayServer::WindowID p_window_id, HWND p_hwnd, HINSTANCE p_hinstance, int p_width, int p_height);
void window_destroy(DisplayServer::WindowID p_window_id);
- void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height);
-
- // get directly from the cached GLWindow
- int window_get_width(DisplayServer::WindowID p_window_id = 0);
- int window_get_height(DisplayServer::WindowID p_window_id = 0);
+ void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) {}
void release_current();
void make_current();
@@ -116,10 +104,10 @@ public:
HDC get_hdc(DisplayServer::WindowID p_window_id);
HGLRC get_hglrc(DisplayServer::WindowID p_window_id);
- GLManager_Windows(ContextType p_context_type);
- ~GLManager_Windows();
+ GLManagerNative_Windows();
+ ~GLManagerNative_Windows();
};
#endif // WINDOWS_ENABLED && GLES3_ENABLED
-#endif // GL_MANAGER_WINDOWS_H
+#endif // GL_MANAGER_WINDOWS_NATIVE_H
diff --git a/platform/windows/joypad_windows.cpp b/platform/windows/joypad_windows.cpp
index 487cb56ba0..60edb00dd2 100644
--- a/platform/windows/joypad_windows.cpp
+++ b/platform/windows/joypad_windows.cpp
@@ -109,6 +109,7 @@ bool JoypadWindows::is_xinput_device(const GUID *p_guid) {
static GUID IID_XOneSWirelessGamepad = { MAKELONG(0x045E, 0x02EA), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
static GUID IID_XOneSBluetoothGamepad = { MAKELONG(0x045E, 0x02E0), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
static GUID IID_XOneEliteWirelessGamepad = { MAKELONG(0x045E, 0x02E3), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
+ static GUID IID_XOneElite2WirelessGamepad = { MAKELONG(0x045E, 0x0B22), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
if (memcmp(p_guid, &IID_ValveStreamingGamepad, sizeof(*p_guid)) == 0 ||
memcmp(p_guid, &IID_X360WiredGamepad, sizeof(*p_guid)) == 0 ||
@@ -120,7 +121,8 @@ bool JoypadWindows::is_xinput_device(const GUID *p_guid) {
memcmp(p_guid, &IID_XOneNewWirelessGamepad, sizeof(*p_guid)) == 0 ||
memcmp(p_guid, &IID_XOneSWirelessGamepad, sizeof(*p_guid)) == 0 ||
memcmp(p_guid, &IID_XOneSBluetoothGamepad, sizeof(*p_guid)) == 0 ||
- memcmp(p_guid, &IID_XOneEliteWirelessGamepad, sizeof(*p_guid)) == 0)
+ memcmp(p_guid, &IID_XOneEliteWirelessGamepad, sizeof(*p_guid)) == 0 ||
+ memcmp(p_guid, &IID_XOneElite2WirelessGamepad, sizeof(*p_guid)) == 0)
return true;
PRAWINPUTDEVICELIST dev_list = nullptr;
@@ -318,7 +320,9 @@ void JoypadWindows::probe_joypads() {
x_joypads[i].ff_end_timestamp = 0;
x_joypads[i].vibrating = false;
attached_joypads[id] = true;
- input->joy_connection_changed(id, true, "XInput Gamepad", "__XINPUT_DEVICE__");
+ Dictionary joypad_info;
+ joypad_info["xinput_index"] = (int)i;
+ input->joy_connection_changed(id, true, "XInput Gamepad", "__XINPUT_DEVICE__", joypad_info);
}
} else if (x_joypads[i].attached) {
x_joypads[i].attached = false;
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index df93631ef0..1d3b80e21e 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -395,7 +395,7 @@ Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_han
}
}
#else
- ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, format_error_message(GetLastError())));
+ ERR_FAIL_NULL_V_MSG(p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, format_error_message(GetLastError())));
#endif
if (cookie) {
@@ -1356,18 +1356,13 @@ Error OS_Windows::shell_open(String p_uri) {
}
Error OS_Windows::shell_show_in_file_manager(String p_path, bool p_open_folder) {
- p_path = p_path.trim_suffix("file://");
-
bool open_folder = false;
if (DirAccess::dir_exists_absolute(p_path) && p_open_folder) {
open_folder = true;
}
- if (p_path.begins_with("\"")) {
- p_path = String("\"") + p_path;
- }
- if (p_path.ends_with("\"")) {
- p_path = p_path + String("\"");
+ if (!p_path.is_quoted()) {
+ p_path = p_path.quote();
}
p_path = p_path.replace("/", "\\");
@@ -1683,7 +1678,7 @@ Error OS_Windows::move_to_trash(const String &p_path) {
String OS_Windows::get_system_ca_certificates() {
HCERTSTORE cert_store = CertOpenSystemStoreA(0, "ROOT");
- ERR_FAIL_COND_V_MSG(!cert_store, "", "Failed to read the root certificate store.");
+ ERR_FAIL_NULL_V_MSG(cert_store, "", "Failed to read the root certificate store.");
FILETIME curr_time;
GetSystemTimeAsFileTime(&curr_time);
@@ -1714,7 +1709,7 @@ String OS_Windows::get_system_ca_certificates() {
OS_Windows::OS_Windows(HINSTANCE _hInstance) {
hInstance = _hInstance;
- CoInitializeEx(nullptr, COINIT_MULTITHREADED);
+ CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
#ifdef WASAPI_ENABLED
AudioDriverManager::add_driver(&driver_wasapi);
diff --git a/platform/windows/platform_config.h b/platform/windows/platform_config.h
index ae4e51e3fb..964e341ce4 100644
--- a/platform/windows/platform_config.h
+++ b/platform/windows/platform_config.h
@@ -29,5 +29,3 @@
/**************************************************************************/
#include <malloc.h>
-
-#define OPENGL_INCLUDE_H "thirdparty/glad/glad/gl.h"
diff --git a/platform/windows/platform_gl.h b/platform/windows/platform_gl.h
new file mode 100644
index 0000000000..e4af8b0ccd
--- /dev/null
+++ b/platform/windows/platform_gl.h
@@ -0,0 +1,53 @@
+/**************************************************************************/
+/* platform_gl.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef PLATFORM_GL_H
+#define PLATFORM_GL_H
+
+#ifndef GL_API_ENABLED
+#define GL_API_ENABLED // Allow using desktop GL.
+#endif
+
+#ifndef GLES_API_ENABLED
+#define GLES_API_ENABLED // Allow using GLES (ANGLE).
+#endif
+
+#ifdef EGL_STATIC
+#define KHRONOS_STATIC 1
+#include "thirdparty/angle/include/EGL/egl.h"
+#include "thirdparty/angle/include/EGL/eglext.h"
+#undef KHRONOS_STATIC
+#else
+#include "thirdparty/glad/glad/egl.h"
+#endif
+
+#include "thirdparty/glad/glad/gl.h"
+
+#endif // PLATFORM_GL_H
diff --git a/platform/windows/platform_windows_builders.py b/platform/windows/platform_windows_builders.py
index b522a75a9c..51652fa814 100644
--- a/platform/windows/platform_windows_builders.py
+++ b/platform/windows/platform_windows_builders.py
@@ -5,14 +5,24 @@ All such functions are invoked in a subprocess on Windows to prevent build flaki
"""
import os
from detect import get_mingw_bin_prefix
+from detect import try_cmd
from platform_methods import subprocess_main
def make_debug_mingw(target, source, env):
mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"])
- os.system(mingw_bin_prefix + "objcopy --only-keep-debug {0} {0}.debugsymbols".format(target[0]))
- os.system(mingw_bin_prefix + "strip --strip-debug --strip-unneeded {0}".format(target[0]))
- os.system(mingw_bin_prefix + "objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(target[0]))
+ if try_cmd("objcopy --version", env["mingw_prefix"], env["arch"]):
+ os.system(mingw_bin_prefix + "objcopy --only-keep-debug {0} {0}.debugsymbols".format(target[0]))
+ else:
+ os.system("objcopy --only-keep-debug {0} {0}.debugsymbols".format(target[0]))
+ if try_cmd("strip --version", env["mingw_prefix"], env["arch"]):
+ os.system(mingw_bin_prefix + "strip --strip-debug --strip-unneeded {0}".format(target[0]))
+ else:
+ os.system("strip --strip-debug --strip-unneeded {0}".format(target[0]))
+ if try_cmd("objcopy --version", env["mingw_prefix"], env["arch"]):
+ os.system(mingw_bin_prefix + "objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(target[0]))
+ else:
+ os.system("objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(target[0]))
if __name__ == "__main__":
diff --git a/platform/windows/tts_windows.cpp b/platform/windows/tts_windows.cpp
index 907096d890..11d63d85ee 100644
--- a/platform/windows/tts_windows.cpp
+++ b/platform/windows/tts_windows.cpp
@@ -114,7 +114,7 @@ void TTS_Windows::_update_tts() {
}
bool TTS_Windows::is_speaking() const {
- ERR_FAIL_COND_V(!synth, false);
+ ERR_FAIL_NULL_V(synth, false);
SPVOICESTATUS status;
synth->GetStatus(&status, nullptr);
@@ -122,7 +122,7 @@ bool TTS_Windows::is_speaking() const {
}
bool TTS_Windows::is_paused() const {
- ERR_FAIL_COND_V(!synth, false);
+ ERR_FAIL_NULL_V(synth, false);
return paused;
}
@@ -185,7 +185,7 @@ Array TTS_Windows::get_voices() const {
}
void TTS_Windows::speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) {
- ERR_FAIL_COND(!synth);
+ ERR_FAIL_NULL(synth);
if (p_interrupt) {
stop();
}
@@ -212,7 +212,7 @@ void TTS_Windows::speak(const String &p_text, const String &p_voice, int p_volum
}
void TTS_Windows::pause() {
- ERR_FAIL_COND(!synth);
+ ERR_FAIL_NULL(synth);
if (!paused) {
if (synth->Pause() == S_OK) {
paused = true;
@@ -221,13 +221,13 @@ void TTS_Windows::pause() {
}
void TTS_Windows::resume() {
- ERR_FAIL_COND(!synth);
+ ERR_FAIL_NULL(synth);
synth->Resume();
paused = false;
}
void TTS_Windows::stop() {
- ERR_FAIL_COND(!synth);
+ ERR_FAIL_NULL(synth);
SPVOICESTATUS status;
synth->GetStatus(&status, nullptr);
diff --git a/platform/windows/wgl_detect_version.cpp b/platform/windows/wgl_detect_version.cpp
new file mode 100644
index 0000000000..49da4b58c7
--- /dev/null
+++ b/platform/windows/wgl_detect_version.cpp
@@ -0,0 +1,197 @@
+/**************************************************************************/
+/* wgl_detect_version.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#if defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED)
+
+#include "wgl_detect_version.h"
+#include "os_windows.h"
+
+#include "core/string/print_string.h"
+#include "core/string/ustring.h"
+#include "core/variant/dictionary.h"
+
+#include <windows.h>
+
+#include <dwmapi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
+#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
+#define WGL_CONTEXT_FLAGS_ARB 0x2094
+#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
+#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
+#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
+#define WGL_VENDOR 0x1F00
+#define WGL_RENDERER 0x1F01
+#define WGL_VERSION 0x1F02
+
+#if defined(__GNUC__)
+// Workaround GCC warning from -Wcast-function-type.
+#define GetProcAddress (void *)GetProcAddress
+#endif
+
+typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXT)(HDC);
+typedef BOOL(APIENTRY *PFNWGLDELETECONTEXT)(HGLRC);
+typedef BOOL(APIENTRY *PFNWGLMAKECURRENT)(HDC, HGLRC);
+typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int *);
+typedef void *(APIENTRY *PFNWGLGETPROCADDRESS)(LPCSTR);
+typedef const char *(APIENTRY *PFNWGLGETSTRINGPROC)(unsigned int);
+
+Dictionary detect_wgl() {
+ Dictionary gl_info;
+ gl_info["version"] = 0;
+ gl_info["vendor"] = String();
+ gl_info["name"] = String();
+
+ PFNWGLCREATECONTEXT gd_wglCreateContext;
+ PFNWGLMAKECURRENT gd_wglMakeCurrent;
+ PFNWGLDELETECONTEXT gd_wglDeleteContext;
+ PFNWGLGETPROCADDRESS gd_wglGetProcAddress;
+
+ HMODULE module = LoadLibraryW(L"opengl32.dll");
+ if (!module) {
+ return gl_info;
+ }
+ gd_wglCreateContext = (PFNWGLCREATECONTEXT)GetProcAddress(module, "wglCreateContext");
+ gd_wglMakeCurrent = (PFNWGLMAKECURRENT)GetProcAddress(module, "wglMakeCurrent");
+ gd_wglDeleteContext = (PFNWGLDELETECONTEXT)GetProcAddress(module, "wglDeleteContext");
+ gd_wglGetProcAddress = (PFNWGLGETPROCADDRESS)GetProcAddress(module, "wglGetProcAddress");
+ if (!gd_wglCreateContext || !gd_wglMakeCurrent || !gd_wglDeleteContext || !gd_wglGetProcAddress) {
+ return gl_info;
+ }
+
+ LPCWSTR class_name = L"EngineWGLDetect";
+ HINSTANCE hInstance = static_cast<OS_Windows *>(OS::get_singleton())->get_hinstance();
+ WNDCLASSW wc = {};
+
+ wc.lpfnWndProc = DefWindowProcW;
+ wc.hInstance = hInstance;
+ wc.lpszClassName = class_name;
+
+ RegisterClassW(&wc);
+
+ HWND hWnd = CreateWindowExW(WS_EX_APPWINDOW, class_name, L"", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr);
+ if (hWnd) {
+ HDC hDC = GetDC(hWnd);
+ if (hDC) {
+ static PIXELFORMATDESCRIPTOR pfd = {
+ sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
+ 1,
+ PFD_DRAW_TO_WINDOW | // Format Must Support Window
+ PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
+ PFD_DOUBLEBUFFER,
+ (BYTE)PFD_TYPE_RGBA,
+ (BYTE)(OS::get_singleton()->is_layered_allowed() ? 32 : 24),
+ (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, // Color Bits Ignored
+ (BYTE)(OS::get_singleton()->is_layered_allowed() ? 8 : 0), // Alpha Buffer
+ (BYTE)0, // Shift Bit Ignored
+ (BYTE)0, // No Accumulation Buffer
+ (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, // Accumulation Bits Ignored
+ (BYTE)24, // 24Bit Z-Buffer (Depth Buffer)
+ (BYTE)0, // No Stencil Buffer
+ (BYTE)0, // No Auxiliary Buffer
+ (BYTE)PFD_MAIN_PLANE, // Main Drawing Layer
+ (BYTE)0, // Reserved
+ 0, 0, 0 // Layer Masks Ignored
+ };
+
+ int pixel_format = ChoosePixelFormat(hDC, &pfd);
+ SetPixelFormat(hDC, pixel_format, &pfd);
+
+ HGLRC hRC = gd_wglCreateContext(hDC);
+ if (hRC) {
+ if (gd_wglMakeCurrent(hDC, hRC)) {
+ int attribs[] = {
+ WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
+ WGL_CONTEXT_MINOR_VERSION_ARB, 3,
+ WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
+ WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
+ 0
+ };
+
+ PFNWGLCREATECONTEXTATTRIBSARBPROC gd_wglCreateContextAttribsARB = nullptr;
+ gd_wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)gd_wglGetProcAddress("wglCreateContextAttribsARB");
+ if (gd_wglCreateContextAttribsARB) {
+ HGLRC new_hRC = gd_wglCreateContextAttribsARB(hDC, 0, attribs);
+ if (new_hRC) {
+ if (gd_wglMakeCurrent(hDC, new_hRC)) {
+ PFNWGLGETSTRINGPROC gd_wglGetString = (PFNWGLGETSTRINGPROC)GetProcAddress(module, "glGetString");
+ if (gd_wglGetString) {
+ const char *prefixes[] = {
+ "OpenGL ES-CM ",
+ "OpenGL ES-CL ",
+ "OpenGL ES ",
+ "OpenGL SC ",
+ nullptr
+ };
+ const char *version = (const char *)gd_wglGetString(WGL_VERSION);
+ if (version) {
+ const String device_vendor = String::utf8((const char *)gd_wglGetString(WGL_VENDOR)).strip_edges().trim_suffix(" Corporation");
+ const String device_name = String::utf8((const char *)gd_wglGetString(WGL_RENDERER)).strip_edges().trim_suffix("/PCIe/SSE2");
+ for (int i = 0; prefixes[i]; i++) {
+ size_t length = strlen(prefixes[i]);
+ if (strncmp(version, prefixes[i], length) == 0) {
+ version += length;
+ break;
+ }
+ }
+ int major = 0;
+ int minor = 0;
+#ifdef _MSC_VER
+ sscanf_s(version, "%d.%d", &major, &minor);
+#else
+ sscanf(version, "%d.%d", &major, &minor);
+#endif
+ print_verbose(vformat("Native OpenGL API detected: %d.%d: %s - %s", major, minor, device_vendor, device_name));
+ gl_info["vendor"] = device_vendor;
+ gl_info["name"] = device_name;
+ gl_info["version"] = major * 10000 + minor;
+ }
+ }
+ }
+ gd_wglMakeCurrent(nullptr, nullptr);
+ gd_wglDeleteContext(new_hRC);
+ }
+ }
+ }
+ gd_wglMakeCurrent(nullptr, nullptr);
+ gd_wglDeleteContext(hRC);
+ }
+ ReleaseDC(hWnd, hDC);
+ }
+ DestroyWindow(hWnd);
+ }
+ UnregisterClassW(class_name, hInstance);
+
+ return gl_info;
+}
+
+#endif // WINDOWS_ENABLED && GLES3_ENABLED
diff --git a/platform/windows/wgl_detect_version.h b/platform/windows/wgl_detect_version.h
new file mode 100644
index 0000000000..c110b1219e
--- /dev/null
+++ b/platform/windows/wgl_detect_version.h
@@ -0,0 +1,42 @@
+/**************************************************************************/
+/* wgl_detect_version.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef WGL_DETECT_VERSION_H
+#define WGL_DETECT_VERSION_H
+
+#if defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED)
+
+class Dictionary;
+
+Dictionary detect_wgl();
+
+#endif // WINDOWS_ENABLED && GLES3_ENABLED
+
+#endif // WGL_DETECT_VERSION_H
diff --git a/platform/windows/windows_terminal_logger.cpp b/platform/windows/windows_terminal_logger.cpp
index bb223628a8..6881a75596 100644
--- a/platform/windows/windows_terminal_logger.cpp
+++ b/platform/windows/windows_terminal_logger.cpp
@@ -81,12 +81,9 @@ void WindowsTerminalLogger::log_error(const char *p_function, const char *p_file
return;
}
-#ifndef UWP_ENABLED
HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE);
if (!hCon || hCon == INVALID_HANDLE_VALUE) {
-#endif
StdLogger::log_error(p_function, p_file, p_line, p_code, p_rationale, p_type);
-#ifndef UWP_ENABLED
} else {
CONSOLE_SCREEN_BUFFER_INFO sbi; //original
GetConsoleScreenBufferInfo(hCon, &sbi);
@@ -159,7 +156,6 @@ void WindowsTerminalLogger::log_error(const char *p_function, const char *p_file
SetConsoleTextAttribute(hCon, sbi.wAttributes);
}
-#endif
}
WindowsTerminalLogger::~WindowsTerminalLogger() {}