#include "pch.h" #include "platform_windows/windows_platform_services.h" #include "renderer_gl/opengl_capabilities.h" #include extern HWND hWnd; extern std::deque> main_tasklist; extern std::mutex main_task_mutex; void destroy_window(); void async_lock(); void async_unlock(); void win32_async_swap(); void win32_renderdoc_frame_start(); void win32_renderdoc_frame_end(); void win32_update_fps(int frames); void win32_update_stylus(float dt); namespace { void show_cursor(bool visible) { std::lock_guard lock(main_task_mutex); main_tasklist.emplace_back([=] { if (visible) while (ShowCursor(true) < 0); else while (ShowCursor(false) >= 0); }); } std::string clipboard_text() { std::string ret; if (OpenClipboard(hWnd)) { if (HANDLE h = GetClipboardData(CF_TEXT)) { if (char* s = static_cast(GlobalLock(h))) { ret = s; GlobalUnlock(h); } } CloseClipboard(); } return ret; } bool set_clipboard_text(const std::string& s) { bool success = false; if (OpenClipboard(hWnd)) { // owned by SetClipboardData if (HGLOBAL h = GlobalAlloc(GMEM_MOVEABLE, s.size() + 1)) { if (char* p = static_cast(GlobalLock(h))) { std::copy(s.begin(), s.end(), p); p[s.size()] = 0; GlobalUnlock(h); success = true; } EmptyClipboard(); SetClipboardData(CF_TEXT, h); } CloseClipboard(); } return success; } std::string open_file(const char* filter) { OPENFILENAMEA ofn; char fileName[MAX_PATH] = ""; ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hWnd; ofn.lpstrFilter = filter; ofn.lpstrFile = fileName; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR; ofn.lpstrDefExt = ""; ofn.lpstrInitialDir = ""; if (GetOpenFileNameA(&ofn) != NULL) return fileName; return ""; } std::string save_file(const char* filter) { OPENFILENAMEA ofn; char fileName[MAX_PATH] = ""; ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hWnd; ofn.lpstrFilter = filter; ofn.lpstrFile = fileName; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_OVERWRITEPROMPT; ofn.lpstrDefExt = ""; ofn.lpstrInitialDir = ""; if (GetSaveFileNameA(&ofn) != NULL) return fileName; return ""; } std::string open_directory() { BROWSEINFOA bi; char Buffer[MAX_PATH]; ZeroMemory(Buffer, MAX_PATH); ZeroMemory(&bi, sizeof(bi)); bi.hwndOwner = hWnd; bi.pszDisplayName = Buffer; bi.lpszTitle = "Title"; bi.ulFlags = BIF_EDITBOX | BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS | BIF_SHAREABLE; LPCITEMIDLIST pFolder = SHBrowseForFolderA(&bi); if (pFolder == NULL) return ""; if (!SHGetPathFromIDListA(pFolder, Buffer)) return ""; return Buffer; } void invoke_selected_path( const std::string& path, const pp::platform::PickedPathCallback& callback) { if (!path.empty()) callback(path); } void ensure_directory(const std::string& path) { if (!PathFileExistsA(path.c_str())) CreateDirectoryA(path.c_str(), NULL); } std::string build_supported_files_filter(const std::vector& types) { std::string filter = "Supported Files ("; bool first_type = true; for (const auto& t : types) { filter.append(std::string(first_type ? "" : " ,") + "*." + t); first_type = false; } filter.append(")"); filter.push_back(0); first_type = true; for (const auto& t : types) { filter.append(std::string(first_type ? "" : ";") + "*." + t); first_type = false; } filter.push_back(0); return filter; } class WindowsPlatformServices final : public pp::platform::PlatformServices { public: [[nodiscard]] pp::platform::PlatformStoragePaths prepare_storage_paths() override { std::string data_path; CHAR my_documents[MAX_PATH]; HRESULT result = SHGetFolderPathA(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, my_documents); if (SUCCEEDED(result)) { data_path = std::string(my_documents) + "\\PanoPainter"; ensure_directory(data_path); } else { CHAR path[MAX_PATH]; GetCurrentDirectoryA(sizeof(path), path); data_path = path; } ensure_directory(data_path + "\\frames"); ensure_directory(data_path + "\\brushes"); ensure_directory(data_path + "\\brushes\\thumbs"); ensure_directory(data_path + "\\patterns"); ensure_directory(data_path + "\\patterns\\thumbs"); ensure_directory(data_path + "\\settings"); return { data_path, data_path, data_path + "\\frames", {}, }; } void log_stacktrace() override { } void trigger_crash_test() override { __debugbreak(); } [[nodiscard]] std::string clipboard_text() override { return ::clipboard_text(); } [[nodiscard]] bool set_clipboard_text(std::string_view text) override { return ::set_clipboard_text(std::string(text)); } void set_cursor_visible(bool visible) override { show_cursor(visible); } void set_virtual_keyboard_visible(bool visible) override { (void)visible; } void attach_ui_thread() override { } void detach_ui_thread() override { } void acquire_render_context() override { async_lock(); glBindFramebuffer( static_cast(pp::renderer::gl::framebuffer_target()), static_cast(pp::renderer::gl::default_framebuffer_id())); } void release_render_context() override { async_unlock(); } void present_render_context() override { win32_async_swap(); } void bind_default_render_target() override { glBindFramebuffer( static_cast(pp::renderer::gl::framebuffer_target()), pp::renderer::gl::default_framebuffer_id()); } void bind_main_render_target() override { bind_default_render_target(); } void begin_render_capture_frame() override { win32_renderdoc_frame_start(); } void end_render_capture_frame() override { win32_renderdoc_frame_end(); } [[nodiscard]] bool deletes_recorded_files_on_clear() override { return false; } void clear_recorded_files(std::string_view recording_path) override { (void)recording_path; } [[nodiscard]] bool enables_live_asset_reloading() override { return true; } void update_platform_frame(float delta_time_seconds) override { win32_update_stylus(delta_time_seconds); } void report_rendered_frames(int frames) override { win32_update_fps(frames); } void display_file(std::string_view path) override { (void)path; } void share_file(std::string_view path) override { (void)path; } void request_app_close() override { destroy_window(); } void pick_image(pp::platform::PickedPathCallback callback) override { const std::string path = open_file("Image Files (*.jpg, *.png)\0*.jpg;*.png"); invoke_selected_path(path, callback); } void pick_file(std::vector file_types, pp::platform::PickedPathCallback callback) override { const std::string filter = build_supported_files_filter(file_types); const std::string path = open_file(filter.c_str()); invoke_selected_path(path, callback); } void pick_save_file(std::vector file_types, pp::platform::PickedPathCallback callback) override { const std::string filter = build_supported_files_filter(file_types); const std::string path = save_file(filter.c_str()); invoke_selected_path(path, callback); } void pick_directory(pp::platform::PickedPathCallback callback) override { const std::string path = open_directory(); invoke_selected_path(path, callback); } void save_prepared_file( std::string_view path, std::string_view suggested_name, pp::platform::PreparedFileCallback callback) override { (void)suggested_name; callback(std::string(path), false); } }; } namespace pp::platform::windows { PlatformServices& platform_services() { static WindowsPlatformServices services; return services; } }