#include "pch.h" #include "platform_windows/windows_bootstrap_helpers.h" #include "app.h" #include "legacy_gl_runtime_dispatch.h" #include "legacy_preference_storage.h" #include "log.h" #include #include #if __has_include() #include #define USE_RENDERDOC #endif LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp); namespace pp::platform::windows { void set_async_render_context(HDC hdc, HGLRC hrc); } namespace pp::platform::windows { #ifdef USE_RENDERDOC RENDERDOC_API_1_4_0* rdoc_api = NULL; bool win32_renderdoc_init() { // At init, on windows if (HMODULE mod = GetModuleHandleA("renderdoc.dll")) { pRENDERDOC_GetAPI RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)GetProcAddress(mod, "RENDERDOC_GetAPI"); return RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_1_2, (void**)&rdoc_api); } return false; } void win32_renderdoc_frame_start() { if (rdoc_api) rdoc_api->StartFrameCapture(NULL, NULL); } void win32_renderdoc_frame_end() { if (rdoc_api) rdoc_api->EndFrameCapture(NULL, NULL); } #else void win32_renderdoc_frame_start() { } void win32_renderdoc_frame_end() { } #endif HRESULT(*GetDpiForMonitor_fn)(HMONITOR hmonitor, MONITOR_DPI_TYPE dpiType, UINT* dpiX, UINT* dpiY); HRESULT(*SetProcessDpiAwareness_fn)(PROCESS_DPI_AWARENESS value); void init_shcore_API() { HMODULE dll = LoadLibrary(L"Shcore.dll"); if (!dll) { LOG("cannot load Shcore.dll"); return; } LOG("loaded Shcore.dll"); GetDpiForMonitor_fn = (decltype(GetDpiForMonitor_fn))GetProcAddress(dll, "GetDpiForMonitor"); SetProcessDpiAwareness_fn = (decltype(SetProcessDpiAwareness_fn))GetProcAddress(dll, "SetProcessDpiAwareness"); } // Returns the last Win32 error, in string format. Returns an empty string if there is no error. std::string GetLastErrorAsString() { DWORD errorMessageID = ::GetLastError(); if (errorMessageID == 0) return std::string(); LPSTR messageBuffer = nullptr; size_t size = FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); std::string message(messageBuffer, size); LocalFree(messageBuffer); return message; } void ensure_runtime_data_directory() { FILE* fp_check = fopen("data\\layout.xml", "rb"); if (!fp_check) { LOG("data files not found"); static char path[MAX_PATH]; GetModuleFileNameA(NULL, path, MAX_PATH); LOG("current dir %s", path); PathRemoveFileSpecA(path); SetCurrentDirectoryA(path); LOG("change dir to %s", path); return; } fclose(fp_check); LOG("data files ok"); } MainWindowStartupState initialize_main_window_startup_state() { auto startup = MainWindowStartupState {}; const auto hInst = GetModuleHandle(NULL); const auto className = L"EngineMain"; startup.window_class.hInstance = hInst; startup.window_class.lpfnWndProc = (WNDPROC)WndProc; startup.window_class.lpszClassName = className; startup.window_class.hbrBackground = (HBRUSH)COLOR_WINDOW; startup.window_class.hCursor = LoadCursor(NULL, IDC_ARROW); RegisterClass(&startup.window_class); auto monitor = MonitorFromWindow(0, MONITOR_DEFAULTTOPRIMARY); auto x = unsigned{ 96 }; auto y = unsigned{ 96 }; if (GetDpiForMonitor_fn) GetDpiForMonitor_fn(monitor, MDT_EFFECTIVE_DPI, &x, &y); App::I->display_density = (float)x / 96.f; const auto window_preferences = pp::panopainter::read_legacy_window_preferences(SW_NORMAL); if (window_preferences.has_ui_scale) App::I->zoom = window_preferences.ui_scale; else App::I->zoom = (float)x / 96.f; startup.show_command = window_preferences.show_command; startup.client_rect = { 0, 0, static_cast(App::I->width * App::I->zoom), static_cast(App::I->height * App::I->zoom), }; if (window_preferences.has_window_rect) { auto wnd_rect = window_preferences.window_rect; App::I->width = wnd_rect.z - wnd_rect.x; App::I->height = wnd_rect.w - wnd_rect.y; startup.client_rect = { wnd_rect.x, wnd_rect.y, wnd_rect.z, wnd_rect.w }; startup.client_pos = { wnd_rect.x, wnd_rect.y }; } else { AdjustWindowRect(&startup.client_rect, startup.window_style, false); } return startup; } void create_main_window(const MainWindowStartupState& startup, HWND& hWnd, HINSTANCE hInst, const wchar_t* window_title) { const int window_width = startup.client_rect.right - startup.client_rect.left; const int window_height = startup.client_rect.bottom - startup.client_rect.top; hWnd = CreateWindow( startup.window_class.lpszClassName, window_title, startup.window_style, startup.client_pos.x, startup.client_pos.y, window_width, window_height, 0, 0, hInst, 0); } void initialize_pixel_format_descriptor(PIXELFORMATDESCRIPTOR& pixel_format) { pixel_format.nSize = sizeof(pixel_format); pixel_format.nVersion = 1; pixel_format.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pixel_format.iPixelType = PFD_TYPE_RGBA; pixel_format.cColorBits = 32; pixel_format.cDepthBits = 24; pixel_format.iLayerType = PFD_MAIN_PLANE; } bool load_glad_entry_points(HDC device_context) { if (!gladLoadGL()) { LOG("gladLoadGL() failed"); return false; } if (!gladLoadWGL(device_context)) { LOG("gladLoadWGL() failed"); return false; } return true; } pp::renderer::gl::OpenGlRuntimeInfo log_runtime_info() { auto runtime_info = pp::renderer::gl::OpenGlRuntimeInfo {}; const auto runtime_info_result = pp::renderer::gl::query_opengl_runtime_info( pp::legacy::gl_runtime::runtime_info_dispatch()); if (runtime_info_result.ok()) { runtime_info = runtime_info_result.value(); LOG("GL version: %s", runtime_info.version); LOG("GL vendor: %s", runtime_info.vendor); LOG("GL renderer: %s", runtime_info.renderer); } else { LOG("OpenGL runtime info query failed: %s", runtime_info_result.status().message); } return runtime_info; } bool upgrade_to_core_gl_context(const MainWindowStartupState& startup, HWND& hWnd, HINSTANCE hInst, const wchar_t* window_title, OpenGlWindowContext& context) { if (!GLAD_WGL_ARB_create_context) { LOG("WGL_ARB_create_context not supported"); // If not supported, go fuck yourself we are not gonna support your shitty device return false; } const auto wgl_config = pp::renderer::gl::windows_wgl_core_context_3_3_config(); UINT num_format = 0; wglMakeCurrent(NULL, NULL); wglDeleteContext(context.render_context); DestroyWindow(hWnd); create_main_window(startup, hWnd, hInst, window_title); context.device_context = GetDC(hWnd); int pixel_format = 0; wglChoosePixelFormatARB( context.device_context, wgl_config.pixel_format_attributes.data(), nullptr, 1, &pixel_format, &num_format); SetPixelFormat(context.device_context, pixel_format, &startup.pixel_format); context.render_context = wglCreateContextAttribsARB( context.device_context, NULL, wgl_config.context_attributes.data()); wglMakeCurrent(context.device_context, context.render_context); set_async_render_context(context.device_context, context.render_context); return true; } MainStartupResult initialize_main_window_and_gl(MainWindowStartupState& startup, HWND& hWnd, HINSTANCE hInst, wchar_t* window_title, OpenGlWindowContext& context) { create_main_window(startup, hWnd, hInst, L"PanoPainter"); initialize_pixel_format_descriptor(startup.pixel_format); context.device_context = GetDC(hWnd); const int pixel_format = ChoosePixelFormat(context.device_context, &startup.pixel_format); SetPixelFormat(context.device_context, pixel_format, &startup.pixel_format); context.render_context = wglCreateContext(context.device_context); wglMakeCurrent(context.device_context, context.render_context); set_async_render_context(context.device_context, context.render_context); if (!load_glad_entry_points(context.device_context)) return MainStartupResult::GladLoadFailure; context.runtime_info = log_runtime_info(); #ifdef USE_RENDERDOC if (!win32_renderdoc_init()) LOG("Renderdoc not started"); #endif const auto renderer_name = std::string(context.runtime_info.renderer != nullptr ? context.runtime_info.renderer : ""); swprintf_s( window_title, 512, L"PanoPainter %s (%s)", g_version_number_w, str2wstr(renderer_name).c_str()); if (!upgrade_to_core_gl_context(startup, hWnd, hInst, window_title, context)) return MainStartupResult::MissingCoreContextSupport; return MainStartupResult::Ok; } BOOL UnadjustWindowRectEx(LPRECT prc, DWORD dwStyle, BOOL fMenu, DWORD dwExStyle) { RECT rc; SetRectEmpty(&rc); BOOL fRc = AdjustWindowRectEx(&rc, dwStyle, fMenu, dwExStyle); if (fRc) { prc->left -= rc.left; prc->top -= rc.top; prc->right -= rc.right; prc->bottom -= rc.bottom; } return fRc; } void _pre_call_callback(const char* name, void* funcptr, int len_args, ...) { assert(App::I->is_render_thread()); } void _post_call_callback(const char* name, void* funcptr, int len_args, ...) { GLenum error_code; error_code = glad_glGetError(); if (error_code != pp::renderer::gl::no_error_code()) { LOG("ERROR %d in %s\n", error_code, name); } } }