Retain Win32 entry state and trim canvas/platform seams
This commit is contained in:
@@ -18,6 +18,23 @@ agent or engineer to remove them without reconstructing context from chat.
|
||||
|
||||
## Reductions
|
||||
|
||||
- 2026-06-16: `DEBT-0003` was narrowed again. `src/main.cpp` now keeps Win32
|
||||
window handles, GL/task mutex state, stylus timers, splash-dialog state, and
|
||||
VR worker state behind one retained local state object instead of separate
|
||||
file-scope globals; retained entrypoint orchestration, direct `App::I`
|
||||
mutation, and broader platform/runtime coupling remain.
|
||||
- 2026-06-16: `DEBT-0017` was narrowed again. Retained GLFW window hooks and
|
||||
the non-Linux fallback storage-path return in
|
||||
`src/platform_legacy/legacy_platform_services.cpp` now route through local
|
||||
retained-state helpers instead of direct method-body `App::I` reads; the
|
||||
retained platform fallback adapter and broader platform-to-app singleton
|
||||
reach remain.
|
||||
- 2026-06-16: `DEBT-0036` was narrowed again. `NodeCanvas` heightmap draw
|
||||
callback setup now routes through
|
||||
`make_legacy_canvas_draw_merge_heightmap_draw(...)` in
|
||||
`src/legacy_canvas_draw_merge_services.h` instead of keeping that callback
|
||||
body inline in `NodeCanvas::draw()`; broader canvas draw orchestration and
|
||||
retained GL resource ownership remain.
|
||||
- 2026-06-16: `DEBT-0003` was narrowed again. The Windows main-loop run-state
|
||||
and VR worker coordination flags in `src/main.cpp` now use `std::atomic`
|
||||
instead of unsynchronized globals; retained Win32 entrypoint ownership,
|
||||
|
||||
@@ -104,7 +104,9 @@ Current architecture mismatches that must be treated as real blockers:
|
||||
while Linux/Web GLFW render-context acquire/present and Linux app-close now
|
||||
route through retained local GLFW callback hooks, and retained Apple ObjC
|
||||
handles plus storage paths now sit behind one local `platform_legacy`
|
||||
helper instead of being re-read through `App::I` in each touched path.
|
||||
helper instead of being re-read through `App::I` in each touched path, with
|
||||
the retained GLFW window hooks and fallback storage-path return now also
|
||||
using local retained-state helpers instead of direct method-body reads.
|
||||
- `src/platform_legacy/legacy_platform_services.*` is still part of the live
|
||||
app shell.
|
||||
- `pp_panopainter_ui` still depends on `pp_legacy_app`.
|
||||
@@ -115,7 +117,8 @@ Current architecture mismatches that must be treated as real blockers:
|
||||
checkerboard background setup now route through retained draw-merge helpers,
|
||||
with the cache-to-screen checkerboard-plane callback setup also reduced and
|
||||
the merged-path per-plane merged-texture draw plus the smoothing-mask face
|
||||
shader/draw pass now routed through the same retained helper family.
|
||||
shader/draw pass plus heightmap callback setup now routed through the same
|
||||
retained helper family.
|
||||
- `app_layout.cpp` and `app_dialogs.cpp` are still mixed shell/controller files
|
||||
rather than thin composition/binding surfaces.
|
||||
- `App`, `Canvas`, `Node`, retained workers, and platform entrypoints still use
|
||||
@@ -128,7 +131,9 @@ Current architecture mismatches that must be treated as real blockers:
|
||||
also use owned `std::jthread` lifecycle, `LogRemote` now uses the same
|
||||
ownership model, the Windows VR device now has explicit `std::unique_ptr`
|
||||
ownership instead of raw global lifetime, and the Windows main-loop/VR
|
||||
coordination flags now use `std::atomic` instead of unsynchronized globals.
|
||||
coordination flags now use `std::atomic` instead of unsynchronized globals,
|
||||
while the main Win32 entrypoint now groups window/GL/task/VR state behind a
|
||||
retained local state object instead of separate process-wide globals.
|
||||
- Modern C++23 usage exists in extracted components, especially `std::span`,
|
||||
explicit result/status objects, and a few concepts, but the live app still
|
||||
does not consistently express ownership, thread affinity, or renderer
|
||||
|
||||
@@ -143,6 +143,9 @@ Current slice:
|
||||
draw, heightmap draw, and current-mode draw now also route through
|
||||
`execute_legacy_canvas_draw_merge_post_draw(...)`, but broader canvas draw
|
||||
orchestration is still inline.
|
||||
- `NodeCanvas` heightmap draw callback setup now also routes through
|
||||
`make_legacy_canvas_draw_merge_heightmap_draw(...)`, but the node still owns
|
||||
current-mode traversal and broader post-draw orchestration.
|
||||
- `NodeCanvas` smoothing-mask face shader setup plus per-face draw execution
|
||||
now also route through
|
||||
`execute_legacy_canvas_draw_merge_smask_faces(...)`, but the node still owns
|
||||
@@ -341,6 +344,9 @@ Current slice:
|
||||
explicit stop requests instead of raw `std::thread`
|
||||
- Windows main-loop run-state and VR worker coordination flags in `main.cpp`
|
||||
now use `std::atomic` ownership instead of unsynchronized globals
|
||||
- `main.cpp` Win32 window handles, GL task/mutex state, splash-dialog state,
|
||||
stylus timers, and VR worker state now sit behind one retained local state
|
||||
object instead of separate file-scope globals
|
||||
- retained `App` composition, task call sites, and platform/runtime entrypoint
|
||||
coupling are still not fully reduced behind the runtime contract
|
||||
|
||||
@@ -616,6 +622,9 @@ Current slice:
|
||||
- Linux/Web GLFW render-context acquire/present hooks and Linux app-close now
|
||||
also route through retained local GLFW callback hooks instead of direct
|
||||
method-body `App::I` access in `LegacyPlatformServices`
|
||||
- retained GLFW window hooks and the non-Linux fallback storage-path return now
|
||||
also route through retained local state helpers instead of reading `App::I`
|
||||
directly in those method bodies
|
||||
- retained Apple callback injection and broader `platform_legacy` singleton
|
||||
reach are still open
|
||||
|
||||
|
||||
@@ -239,6 +239,17 @@ struct LegacyCanvasDrawMergePostDrawExecution {
|
||||
std::function<void()> draw_current_modes;
|
||||
};
|
||||
|
||||
template <typename GridT>
|
||||
[[nodiscard]] inline auto make_legacy_canvas_draw_merge_heightmap_draw(
|
||||
GridT* grid,
|
||||
const glm::mat4& proj,
|
||||
const glm::mat4& camera)
|
||||
{
|
||||
return [grid, proj, camera] {
|
||||
grid->draw_heightmap(proj, camera, false);
|
||||
};
|
||||
}
|
||||
|
||||
struct LegacyCanvasDrawMergeSmaskFacesExecution {
|
||||
std::function<void()> set_active_texture_unit;
|
||||
std::function<void()> enable_blend;
|
||||
|
||||
281
src/main.cpp
281
src/main.cpp
@@ -38,31 +38,43 @@
|
||||
#define WM_USER_WAKEUP (WM_USER + 2)
|
||||
|
||||
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp);
|
||||
HINSTANCE hInst;
|
||||
HWND hWnd;
|
||||
HDC hDC;
|
||||
HGLRC hRC;
|
||||
const wchar_t* className;
|
||||
bool keys[256];
|
||||
std::mutex gl_mutex;
|
||||
std::mutex async_mutex;
|
||||
std::thread::id gl_thread;
|
||||
std::map<kKey, int> vkey_map;
|
||||
static wchar_t window_title[512];
|
||||
struct RetainedState
|
||||
{
|
||||
HINSTANCE hInst{};
|
||||
HWND hWnd{};
|
||||
HDC hDC{};
|
||||
HGLRC hRC{};
|
||||
const wchar_t* className{};
|
||||
bool keys[256]{};
|
||||
std::mutex gl_mutex;
|
||||
std::mutex async_mutex;
|
||||
std::thread::id gl_thread{};
|
||||
std::map<kKey, int> vkey_map;
|
||||
wchar_t window_title[512]{};
|
||||
std::jthread hmd_renderer;
|
||||
int gl_count = 0;
|
||||
std::deque<std::packaged_task<void()>> main_tasklist;
|
||||
std::mutex main_task_mutex;
|
||||
float timer_stylus = 0;
|
||||
float timer_ink_touch = 0;
|
||||
float timer_ink_pen = 0;
|
||||
bool sandboxed = false;
|
||||
std::mutex hmd_render_mutex;
|
||||
std::condition_variable hmd_render_cv;
|
||||
std::unique_ptr<Vive> vive;
|
||||
HWND splash_dialog{};
|
||||
};
|
||||
|
||||
RetainedState& retained_state()
|
||||
{
|
||||
static RetainedState state;
|
||||
return state;
|
||||
}
|
||||
|
||||
std::jthread hmd_renderer;
|
||||
std::atomic<int> vr_frames{0};
|
||||
std::atomic<int> running{-1};
|
||||
std::atomic_bool vr_running{false};
|
||||
|
||||
int gl_count = 0;
|
||||
std::deque<std::packaged_task<void()>> main_tasklist;
|
||||
std::mutex main_task_mutex;
|
||||
float timer_stylus = 0;
|
||||
float timer_ink_touch = 0;
|
||||
float timer_ink_pen = 0;
|
||||
bool sandboxed = false;
|
||||
|
||||
#ifdef USE_RENDERDOC
|
||||
RENDERDOC_API_1_4_0* rdoc_api = NULL;
|
||||
bool win32_renderdoc_init()
|
||||
@@ -149,8 +161,9 @@ std::string GetLastErrorAsString()
|
||||
|
||||
void destroy_window()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(main_task_mutex);
|
||||
main_tasklist.emplace_back([=] {
|
||||
auto& state = retained_state();
|
||||
std::lock_guard<std::mutex> lock(state.main_task_mutex);
|
||||
state.main_tasklist.emplace_back([hWnd = state.hWnd] {
|
||||
PostMessage(hWnd, WM_USER_CLOSE, 0, 0);
|
||||
});
|
||||
}
|
||||
@@ -158,73 +171,77 @@ void destroy_window()
|
||||
void async_lock()
|
||||
{
|
||||
//std::lock_guard<std::mutex> _lock(async_mutex);
|
||||
if (gl_count == 0 || gl_thread != std::this_thread::get_id())
|
||||
auto& state = retained_state();
|
||||
if (state.gl_count == 0 || state.gl_thread != std::this_thread::get_id())
|
||||
{
|
||||
gl_mutex.lock();
|
||||
bool ret = wglMakeCurrent(hDC, hRC);
|
||||
state.gl_mutex.lock();
|
||||
bool ret = wglMakeCurrent(state.hDC, state.hRC);
|
||||
if (ret == false)
|
||||
LOG("FAILED wglMakeCurrent: %s", GetLastErrorAsString().c_str());
|
||||
gl_thread = std::this_thread::get_id();
|
||||
state.gl_thread = std::this_thread::get_id();
|
||||
//LOG("lock");
|
||||
}
|
||||
gl_count++;
|
||||
state.gl_count++;
|
||||
//assert(ret == true);
|
||||
}
|
||||
|
||||
bool async_lock_try()
|
||||
{
|
||||
//std::lock_guard<std::mutex> _lock(async_mutex);
|
||||
if (gl_count == 0 || gl_thread != std::this_thread::get_id())
|
||||
auto& state = retained_state();
|
||||
if (state.gl_count == 0 || state.gl_thread != std::this_thread::get_id())
|
||||
{
|
||||
if (!gl_mutex.try_lock())
|
||||
if (!state.gl_mutex.try_lock())
|
||||
return false;
|
||||
bool ret = wglMakeCurrent(hDC, hRC);
|
||||
bool ret = wglMakeCurrent(state.hDC, state.hRC);
|
||||
if (ret == false)
|
||||
LOG("FAILED wglMakeCurrent: %s", GetLastErrorAsString().c_str());
|
||||
gl_thread = std::this_thread::get_id();
|
||||
state.gl_thread = std::this_thread::get_id();
|
||||
//LOG("lock");
|
||||
}
|
||||
gl_count++;
|
||||
state.gl_count++;
|
||||
//assert(ret == true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void win32_async_swap()
|
||||
{
|
||||
SwapBuffers(hDC);
|
||||
SwapBuffers(retained_state().hDC);
|
||||
//LOG("swap");
|
||||
}
|
||||
|
||||
void async_unlock()
|
||||
{
|
||||
//std::lock_guard<std::mutex> _lock(async_mutex);
|
||||
gl_count--;
|
||||
if (gl_count == 0)
|
||||
auto& state = retained_state();
|
||||
state.gl_count--;
|
||||
if (state.gl_count == 0)
|
||||
{
|
||||
//LOG("unlock");
|
||||
wglMakeCurrent(0, 0);
|
||||
gl_mutex.unlock();
|
||||
state.gl_mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void win32_update_stylus(float dt)
|
||||
{
|
||||
timer_stylus += dt;
|
||||
timer_ink_touch += dt;
|
||||
timer_ink_pen += dt;
|
||||
auto& state = retained_state();
|
||||
state.timer_stylus += dt;
|
||||
state.timer_ink_touch += dt;
|
||||
state.timer_ink_pen += dt;
|
||||
|
||||
if (timer_stylus > 0.1 && (WacomTablet::I.m_stylus || WacomTablet::I.m_eraser))
|
||||
if (state.timer_stylus > 0.1 && (WacomTablet::I.m_stylus || WacomTablet::I.m_eraser))
|
||||
{
|
||||
WacomTablet::I.m_stylus = false;
|
||||
WacomTablet::I.m_eraser = false;
|
||||
App::I->redraw = true;
|
||||
}
|
||||
if (timer_ink_pen > 0.1 && WacomTablet::I.m_ink_pen)
|
||||
if (state.timer_ink_pen > 0.1 && WacomTablet::I.m_ink_pen)
|
||||
{
|
||||
WacomTablet::I.m_ink_pen = false;
|
||||
App::I->redraw = true;
|
||||
}
|
||||
if (timer_ink_touch > 0.1 && WacomTablet::I.m_ink_touch)
|
||||
if (state.timer_ink_touch > 0.1 && WacomTablet::I.m_ink_touch)
|
||||
{
|
||||
WacomTablet::I.m_ink_touch = false;
|
||||
App::I->redraw = true;
|
||||
@@ -235,18 +252,19 @@ void win32_update_fps(int frames)
|
||||
{
|
||||
static wchar_t title_fps[512];
|
||||
const int vr_fps = vr_frames.load(std::memory_order_relaxed);
|
||||
auto& state = retained_state();
|
||||
if (App::I->vr_active)
|
||||
swprintf_s(title_fps, L"%s - %d fps - %d vr fps", window_title, frames, vr_fps);
|
||||
swprintf_s(title_fps, L"%s - %d fps - %d vr fps", state.window_title, frames, vr_fps);
|
||||
else
|
||||
swprintf_s(title_fps, L"%s - %d fps", window_title, frames);
|
||||
swprintf_s(title_fps, L"%s - %d fps", state.window_title, frames);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(main_task_mutex);
|
||||
main_tasklist.emplace_back([] {
|
||||
std::lock_guard<std::mutex> lock(state.main_task_mutex);
|
||||
state.main_tasklist.emplace_back([hWnd = state.hWnd] {
|
||||
SetWindowText(hWnd, title_fps);
|
||||
});
|
||||
}
|
||||
PostMessage(hWnd, WM_USER_WAKEUP, 0, 0);
|
||||
PostMessage(state.hWnd, WM_USER_WAKEUP, 0, 0);
|
||||
}
|
||||
|
||||
int read_WMI_info()
|
||||
@@ -403,7 +421,7 @@ int read_WMI_info()
|
||||
if (get_int(clsObj, L"CodeIntegrityPolicyEnforcementStatus") > 0)
|
||||
{
|
||||
LOG("SANDBOX DETECTED");
|
||||
sandboxed = true;
|
||||
retained_state().sandboxed = true;
|
||||
}
|
||||
|
||||
SAFEARRAY *psaNames = NULL;
|
||||
@@ -491,7 +509,7 @@ static void SetupExceptionHandler()
|
||||
GetFullPathNameA(path.c_str(), MAX_PATH, abspath, NULL);
|
||||
static char message[4096];
|
||||
snprintf(message, sizeof(message), "File recovered in: %s", abspath);
|
||||
MessageBoxA(hWnd, message, "File Recovery", MB_OK | MB_ICONWARNING);
|
||||
MessageBoxA(retained_state().hWnd, message, "File Recovery", MB_OK | MB_ICONWARNING);
|
||||
}
|
||||
LogRemote::I.file_close();
|
||||
}, 0);
|
||||
@@ -500,50 +518,49 @@ static void SetupExceptionHandler()
|
||||
// create a reverse map from kKey to VK_XXX
|
||||
void init_vk_map()
|
||||
{
|
||||
auto& state = retained_state();
|
||||
for (int k = 1; k < 256; k++) // ignore kKey::Unknown = 0
|
||||
{
|
||||
for (int vk = 0; vk < 256; vk++)
|
||||
{
|
||||
if (k == (int)convert_key(vk))
|
||||
{
|
||||
if (vkey_map.find((kKey)k) == vkey_map.end())
|
||||
if (state.vkey_map.find((kKey)k) == state.vkey_map.end())
|
||||
{
|
||||
vkey_map.insert({ (kKey)k, vk });
|
||||
state.vkey_map.insert({ (kKey)k, vk });
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("KEY MAP COLLISION %d and %d maps to %d",
|
||||
(int)vk, (int)vkey_map[(kKey)k], (int)k);
|
||||
(int)vk, (int)state.vkey_map[(kKey)k], (int)k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::mutex hmd_render_mutex;
|
||||
std::condition_variable hmd_render_cv;
|
||||
std::unique_ptr<Vive> vive;
|
||||
bool win32_vr_start()
|
||||
{
|
||||
if (sandboxed)
|
||||
auto& state = retained_state();
|
||||
if (state.sandboxed)
|
||||
return false;
|
||||
|
||||
vive = std::make_unique<Vive>();
|
||||
vive->on_draw = [](const glm::mat4& proj, const glm::mat4& view, const glm::mat4& pose) { App::I->vr_draw(proj, view, pose); };
|
||||
if (!vive->Initialize())
|
||||
state.vive = std::make_unique<Vive>();
|
||||
state.vive->on_draw = [](const glm::mat4& proj, const glm::mat4& view, const glm::mat4& pose) { App::I->vr_draw(proj, view, pose); };
|
||||
if (!state.vive->Initialize())
|
||||
{
|
||||
vive.reset();
|
||||
state.vive.reset();
|
||||
LOG("VR: failed to initialize vive");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hmd_renderer.joinable())
|
||||
if (state.hmd_renderer.joinable())
|
||||
{
|
||||
hmd_renderer.request_stop();
|
||||
hmd_renderer.join();
|
||||
state.hmd_renderer.request_stop();
|
||||
state.hmd_renderer.join();
|
||||
}
|
||||
hmd_renderer = std::jthread([&](std::stop_token stop_token) {
|
||||
if (!vive)
|
||||
state.hmd_renderer = std::jthread([&state](std::stop_token stop_token) {
|
||||
if (!state.vive)
|
||||
return;
|
||||
|
||||
BT_SetTerminate();
|
||||
@@ -551,9 +568,9 @@ bool win32_vr_start()
|
||||
App::I->has_vr = true;
|
||||
vr_running.store(true, std::memory_order_relaxed);
|
||||
|
||||
vive->on_analog_button = std::bind(&App::vr_analog, App::I, std::placeholders::_1,
|
||||
state.vive->on_analog_button = std::bind(&App::vr_analog, App::I, std::placeholders::_1,
|
||||
std::placeholders::_2, std::placeholders::_3, std::placeholders::_4);
|
||||
vive->on_button = std::bind(&App::vr_digital, App::I, std::placeholders::_1,
|
||||
state.vive->on_button = std::bind(&App::vr_digital, App::I, std::placeholders::_1,
|
||||
std::placeholders::_2, std::placeholders::_3, std::placeholders::_4);
|
||||
|
||||
App::I->render_task([] {
|
||||
@@ -564,9 +581,9 @@ bool win32_vr_start()
|
||||
auto t0 = GetTickCount64();
|
||||
float one_sec_timer = 0;
|
||||
int frames = 0;
|
||||
while (!stop_token.stop_requested() && vr_running.load(std::memory_order_relaxed) && running.load(std::memory_order_relaxed) == 1 && vive->Valid())
|
||||
while (!stop_token.stop_requested() && vr_running.load(std::memory_order_relaxed) && running.load(std::memory_order_relaxed) == 1 && state.vive->Valid())
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(hmd_render_mutex);
|
||||
std::unique_lock<std::mutex> lock(state.hmd_render_mutex);
|
||||
auto t1 = GetTickCount64();
|
||||
float dt = (float)(t1 - t0) / 1000.0f;
|
||||
|
||||
@@ -579,28 +596,28 @@ bool win32_vr_start()
|
||||
}
|
||||
frames++;
|
||||
|
||||
vive->Update();
|
||||
App::I->vr_active = vive->m_active;
|
||||
App::I->vr_controllers[0] = vive->m_controllers[0];
|
||||
App::I->vr_head = vive->m_pose;
|
||||
state.vive->Update();
|
||||
App::I->vr_active = state.vive->m_active;
|
||||
App::I->vr_controllers[0] = state.vive->m_controllers[0];
|
||||
App::I->vr_head = state.vive->m_pose;
|
||||
App::I->vr_update(dt);
|
||||
|
||||
if (vr_running.load(std::memory_order_relaxed) && vive->m_active)
|
||||
if (vr_running.load(std::memory_order_relaxed) && state.vive->m_active)
|
||||
{
|
||||
App::I->render_task([] {
|
||||
vive->Draw();
|
||||
App::I->render_task([&state] {
|
||||
state.vive->Draw();
|
||||
});
|
||||
}
|
||||
|
||||
const int framerate = (1.f / target_tick_rate) * 1000;
|
||||
const int diff = framerate - (t1 - t0);
|
||||
//hmd_render_cv.wait_for(lock, std::chrono::milliseconds(diff));
|
||||
//state.hmd_render_cv.wait_for(lock, std::chrono::milliseconds(diff));
|
||||
t0 = t1;
|
||||
}
|
||||
App::I->vr_active = false;
|
||||
App::I->has_vr = false;
|
||||
vr_running.store(false, std::memory_order_relaxed);
|
||||
vive->Terminate();
|
||||
state.vive->Terminate();
|
||||
LOG("hmd renderer terminated");
|
||||
});
|
||||
return true;
|
||||
@@ -608,23 +625,25 @@ bool win32_vr_start()
|
||||
|
||||
void win32_vr_stop()
|
||||
{
|
||||
if (vive)
|
||||
auto& state = retained_state();
|
||||
if (state.vive)
|
||||
{
|
||||
vr_running.store(false, std::memory_order_relaxed);
|
||||
if (hmd_renderer.joinable())
|
||||
if (state.hmd_renderer.joinable())
|
||||
{
|
||||
hmd_renderer.request_stop();
|
||||
hmd_renderer.join();
|
||||
state.hmd_renderer.request_stop();
|
||||
state.hmd_renderer.join();
|
||||
}
|
||||
vive->Terminate();
|
||||
vive.reset();
|
||||
state.vive->Terminate();
|
||||
state.vive.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void win32_save_window_state()
|
||||
{
|
||||
auto& state = retained_state();
|
||||
WINDOWPLACEMENT p;
|
||||
GetWindowPlacement(hWnd, &p);
|
||||
GetWindowPlacement(state.hWnd, &p);
|
||||
pp::panopainter::set_legacy_window_preferences(p.showCmd, {
|
||||
p.rcNormalPosition.left,
|
||||
p.rcNormalPosition.top,
|
||||
@@ -690,23 +709,23 @@ LRESULT CALLBACK splash_proc(HWND hWndDlg, UINT Msg, WPARAM wParam, LPARAM lPara
|
||||
return DefWindowProc(hWndDlg, Msg, wParam, lParam);;
|
||||
}
|
||||
|
||||
HWND splash_dialog;
|
||||
void splash_thread_loop()
|
||||
{
|
||||
auto& state = retained_state();
|
||||
BT_SetTerminate();
|
||||
splash_dialog = CreateDialog(hInst, MAKEINTRESOURCE(IDD_SPLASH), NULL, reinterpret_cast<DLGPROC>(splash_proc));
|
||||
state.splash_dialog = CreateDialog(state.hInst, MAKEINTRESOURCE(IDD_SPLASH), NULL, reinterpret_cast<DLGPROC>(splash_proc));
|
||||
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, 0, 0, 0) > 0)
|
||||
{
|
||||
if (IsDialogMessage(splash_dialog, &msg))
|
||||
if (IsDialogMessage(state.splash_dialog, &msg))
|
||||
{
|
||||
DispatchMessage(&msg);
|
||||
TranslateMessage(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
DestroyWindow(splash_dialog);
|
||||
DestroyWindow(state.splash_dialog);
|
||||
}
|
||||
|
||||
BOOL UnadjustWindowRectEx(LPRECT prc, DWORD dwStyle, BOOL fMenu, DWORD dwExStyle)
|
||||
@@ -741,6 +760,7 @@ void _post_call_callback(const char* name, void* funcptr, int len_args, ...)
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
auto& state = retained_state();
|
||||
WNDCLASS wc;
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
|
||||
@@ -785,17 +805,17 @@ int main(int argc, char** argv)
|
||||
|
||||
// Inizialize data structures to zero
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
memset(&keys, 0, sizeof(keys));
|
||||
memset(&state.keys, 0, sizeof(state.keys));
|
||||
memset(&pfd, 0, sizeof(pfd));
|
||||
|
||||
// Create the main window
|
||||
|
||||
hInst = GetModuleHandle(NULL);
|
||||
className = L"EngineMain";
|
||||
state.hInst = GetModuleHandle(NULL);
|
||||
state.className = L"EngineMain";
|
||||
|
||||
wc.hInstance = hInst;
|
||||
wc.hInstance = state.hInst;
|
||||
wc.lpfnWndProc = (WNDPROC)WndProc;
|
||||
wc.lpszClassName = className;
|
||||
wc.lpszClassName = state.className;
|
||||
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
|
||||
@@ -833,9 +853,9 @@ int main(int argc, char** argv)
|
||||
{
|
||||
AdjustWindowRect(&clientRect, wnd_style, false);
|
||||
}
|
||||
hWnd = CreateWindow(wc.lpszClassName, L"PanoPainter", wnd_style, clientPos.x, clientPos.y,
|
||||
state.hWnd = CreateWindow(wc.lpszClassName, L"PanoPainter", wnd_style, clientPos.x, clientPos.y,
|
||||
(float)(clientRect.right - clientRect.left),
|
||||
(float)(clientRect.bottom - clientRect.top), 0, 0, hInst, 0);
|
||||
(float)(clientRect.bottom - clientRect.top), 0, 0, state.hInst, 0);
|
||||
|
||||
// Setup GL Rendering Context
|
||||
pfd.nSize = sizeof(pfd);
|
||||
@@ -846,11 +866,11 @@ int main(int argc, char** argv)
|
||||
pfd.cDepthBits = 24;
|
||||
pfd.iLayerType = PFD_MAIN_PLANE;
|
||||
|
||||
hDC = GetDC(hWnd);
|
||||
int pxfmt = ChoosePixelFormat(hDC, &pfd);
|
||||
SetPixelFormat(hDC, pxfmt, &pfd);
|
||||
hRC = wglCreateContext(hDC); // Create OpenGL 2.1 or less
|
||||
wglMakeCurrent(hDC, hRC);
|
||||
state.hDC = GetDC(state.hWnd);
|
||||
int pxfmt = ChoosePixelFormat(state.hDC, &pfd);
|
||||
SetPixelFormat(state.hDC, pxfmt, &pfd);
|
||||
state.hRC = wglCreateContext(state.hDC); // Create OpenGL 2.1 or less
|
||||
wglMakeCurrent(state.hDC, state.hRC);
|
||||
|
||||
// Initialize extensions
|
||||
if (!gladLoadGL())
|
||||
@@ -858,7 +878,7 @@ int main(int argc, char** argv)
|
||||
LOG("gladLoadGL() failed");
|
||||
return 0;
|
||||
}
|
||||
if (!gladLoadWGL(hDC))
|
||||
if (!gladLoadWGL(state.hDC))
|
||||
{
|
||||
LOG("gladLoadWGL() failed");
|
||||
return 0;
|
||||
@@ -882,7 +902,7 @@ int main(int argc, char** argv)
|
||||
#endif // USE_RENDERDOC
|
||||
|
||||
const auto renderer_name = std::string(runtime_info.renderer != nullptr ? runtime_info.renderer : "");
|
||||
swprintf_s(window_title, L"PanoPainter %s (%s)", g_version_number_w,
|
||||
swprintf_s(state.window_title, L"PanoPainter %s (%s)", g_version_number_w,
|
||||
str2wstr(renderer_name).c_str());
|
||||
|
||||
// If supported create a 3.3 context
|
||||
@@ -892,18 +912,18 @@ int main(int argc, char** argv)
|
||||
UINT numFormat;
|
||||
|
||||
wglMakeCurrent(NULL, NULL);
|
||||
wglDeleteContext(hRC);
|
||||
DestroyWindow(hWnd);
|
||||
wglDeleteContext(state.hRC);
|
||||
DestroyWindow(state.hWnd);
|
||||
|
||||
hWnd = CreateWindow(wc.lpszClassName, window_title, wnd_style, clientPos.x, clientPos.y,
|
||||
state.hWnd = CreateWindow(wc.lpszClassName, state.window_title, wnd_style, clientPos.x, clientPos.y,
|
||||
(float)(clientRect.right - clientRect.left),
|
||||
(float)(clientRect.bottom - clientRect.top), 0, 0, hInst, 0);
|
||||
(float)(clientRect.bottom - clientRect.top), 0, 0, state.hInst, 0);
|
||||
|
||||
hDC = GetDC(hWnd);
|
||||
wglChoosePixelFormatARB(hDC, wgl_config.pixel_format_attributes.data(), nullptr, 1, &pxfmt, &numFormat);
|
||||
SetPixelFormat(hDC, pxfmt, &pfd);
|
||||
hRC = wglCreateContextAttribsARB(hDC, NULL, wgl_config.context_attributes.data());
|
||||
wglMakeCurrent(hDC, hRC);
|
||||
state.hDC = GetDC(state.hWnd);
|
||||
wglChoosePixelFormatARB(state.hDC, wgl_config.pixel_format_attributes.data(), nullptr, 1, &pxfmt, &numFormat);
|
||||
SetPixelFormat(state.hDC, pxfmt, &pfd);
|
||||
state.hRC = wglCreateContextAttribsARB(state.hDC, NULL, wgl_config.context_attributes.data());
|
||||
wglMakeCurrent(state.hDC, state.hRC);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -932,7 +952,7 @@ int main(int argc, char** argv)
|
||||
}
|
||||
|
||||
// link: https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-registertouchwindow
|
||||
if (RegisterTouchWindow(hWnd, 0) == 0)
|
||||
if (RegisterTouchWindow(state.hWnd, 0) == 0)
|
||||
{
|
||||
LOG("RegisterTouchWindow error: %s", GetLastErrorAsString().c_str());
|
||||
}
|
||||
@@ -948,10 +968,10 @@ int main(int argc, char** argv)
|
||||
glad_set_post_callback(_post_call_callback);
|
||||
#endif
|
||||
|
||||
if (!sandboxed)
|
||||
if (!state.sandboxed)
|
||||
{
|
||||
LOG("init WinTab");
|
||||
WacomTablet::I.init(hWnd);
|
||||
WacomTablet::I.init(state.hWnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -959,16 +979,16 @@ int main(int argc, char** argv)
|
||||
}
|
||||
|
||||
LOG("change icon");
|
||||
SendMessage(hWnd, WM_SETICON, ICON_SMALL,
|
||||
SendMessage(state.hWnd, WM_SETICON, ICON_SMALL,
|
||||
(LPARAM)LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(IDI_ICON1)));
|
||||
|
||||
App::I->ui_sync();
|
||||
|
||||
{
|
||||
WINDOWPLACEMENT wp;
|
||||
GetWindowPlacement(hWnd, &wp);
|
||||
GetWindowPlacement(state.hWnd, &wp);
|
||||
wp.showCmd = show_cmd;
|
||||
SetWindowPlacement(hWnd, &wp);
|
||||
SetWindowPlacement(state.hWnd, &wp);
|
||||
//GetClientRect(hWnd, &clientRect);
|
||||
//App::I->width = clientRect.right - clientRect.left;
|
||||
//App::I->height = clientRect.bottom - clientRect.top;
|
||||
@@ -978,10 +998,10 @@ int main(int argc, char** argv)
|
||||
App::I->vr_start();
|
||||
|
||||
LOG("show main window");
|
||||
SetForegroundWindow(hWnd);
|
||||
SetForegroundWindow(state.hWnd);
|
||||
//ShowWindow(hWnd, show_cmd);
|
||||
|
||||
SendMessage(splash_dialog, WM_USER_CLOSE, 0, 0);
|
||||
SendMessage(state.splash_dialog, WM_USER_CLOSE, 0, 0);
|
||||
if (dialog_thread.joinable())
|
||||
dialog_thread.join();
|
||||
|
||||
@@ -1006,8 +1026,8 @@ int main(int argc, char** argv)
|
||||
{
|
||||
std::deque<std::packaged_task<void()>> working_list;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(main_task_mutex);
|
||||
working_list = std::move(main_tasklist);
|
||||
std::lock_guard<std::mutex> lock(state.main_task_mutex);
|
||||
working_list = std::move(state.main_tasklist);
|
||||
}
|
||||
|
||||
if (!working_list.empty())
|
||||
@@ -1023,12 +1043,13 @@ int main(int argc, char** argv)
|
||||
// Clean up
|
||||
WacomTablet::I.terminate();
|
||||
|
||||
UnregisterClass(className, hInst);
|
||||
UnregisterClass(state.className, state.hInst);
|
||||
LogRemote::I.stop();
|
||||
}
|
||||
|
||||
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
||||
{
|
||||
auto& state = retained_state();
|
||||
static bool leftDown = false;
|
||||
static DWORD lastTime;
|
||||
static glm::vec2 lastPoint;
|
||||
@@ -1041,10 +1062,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
||||
{
|
||||
case WM_USER_CLOSE:
|
||||
running.store(0, std::memory_order_relaxed);
|
||||
if (hmd_renderer.joinable())
|
||||
if (state.hmd_renderer.joinable())
|
||||
{
|
||||
hmd_renderer.request_stop();
|
||||
hmd_renderer.join();
|
||||
state.hmd_renderer.request_stop();
|
||||
state.hmd_renderer.join();
|
||||
}
|
||||
App::I->runtime().ui_thread_stop();
|
||||
App::I->runtime().render_thread_stop();
|
||||
@@ -1093,7 +1114,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
||||
if (GetKeyboardState(keys))
|
||||
{
|
||||
bool alt = keys[VK_MENU] & 0x80;
|
||||
for (auto k : vkey_map)
|
||||
for (auto k : state.vkey_map)
|
||||
{
|
||||
// ignore alt + tab
|
||||
if (alt && k.first == kKey::KeyTab)
|
||||
@@ -1118,7 +1139,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
||||
case WT_PACKET:
|
||||
{
|
||||
App::I->set_stylus();
|
||||
timer_stylus = 0;
|
||||
state.timer_stylus = 0;
|
||||
App::I->ui_task_async([=] {
|
||||
WacomTablet::I.handle_message(hWnd, msg, wp, lp);
|
||||
});
|
||||
@@ -1318,7 +1339,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
||||
// success, process touchInfo
|
||||
// mark as handled to skip call to DefWindowProc
|
||||
//fHandled = TRUE;
|
||||
timer_ink_touch = 0;
|
||||
state.timer_ink_touch = 0;
|
||||
WacomTablet::I.m_ink_touch = true;
|
||||
WacomTablet::I.m_pen_pres = 1;
|
||||
}
|
||||
@@ -1335,7 +1356,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
||||
// mark as handled to skip call to DefWindowProc
|
||||
//fHandled = TRUE;
|
||||
//penInfo.pressure
|
||||
timer_ink_pen = 0;
|
||||
state.timer_ink_pen = 0;
|
||||
WacomTablet::I.m_ink_pen = true;
|
||||
WacomTablet::I.m_pen_pres = (float)penInfo.pressure / 1024.f;
|
||||
App::I->set_stylus();
|
||||
|
||||
@@ -769,9 +769,7 @@ void NodeCanvas::draw()
|
||||
for (auto& mode : Canvas::modes[(int)kCanvasMode::Grid])
|
||||
mode->on_Draw(ortho_proj, proj, camera);
|
||||
},
|
||||
.draw_heightmap = [&] {
|
||||
App::I->grid->draw_heightmap(proj, camera, false);
|
||||
},
|
||||
.draw_heightmap = pp::panopainter::make_legacy_canvas_draw_merge_heightmap_draw(App::I->grid, proj, camera),
|
||||
.draw_current_modes = [&] {
|
||||
for (auto& mode : *m_canvas->m_mode)
|
||||
mode->on_Draw(ortho_proj, proj, camera);
|
||||
|
||||
@@ -101,26 +101,55 @@ struct RetainedLegacyGlfwWindowHooks final {
|
||||
std::function<void()> request_app_close;
|
||||
};
|
||||
|
||||
[[nodiscard]] RetainedLegacyGlfwWindowHooks& active_legacy_glfw_window_hooks()
|
||||
struct RetainedLegacyGlfwWindowState final {
|
||||
decltype(App::I->glfw_window) window = nullptr;
|
||||
RetainedLegacyGlfwWindowHooks hooks;
|
||||
};
|
||||
|
||||
[[nodiscard]] RetainedLegacyGlfwWindowState& active_legacy_glfw_window_state()
|
||||
{
|
||||
static RetainedLegacyGlfwWindowHooks hooks = [] {
|
||||
RetainedLegacyGlfwWindowHooks retained;
|
||||
GLFWwindow* const window = App::I->glfw_window;
|
||||
retained.acquire_render_context = [window] {
|
||||
static RetainedLegacyGlfwWindowState state = [] {
|
||||
RetainedLegacyGlfwWindowState retained;
|
||||
retained.window = App::I->glfw_window;
|
||||
retained.hooks.acquire_render_context = [window = retained.window] {
|
||||
glfwMakeContextCurrent(window);
|
||||
};
|
||||
retained.present_render_context = [window] {
|
||||
retained.hooks.present_render_context = [window = retained.window] {
|
||||
glfwSwapBuffers(window);
|
||||
};
|
||||
retained.request_app_close = [window] {
|
||||
retained.hooks.request_app_close = [window = retained.window] {
|
||||
glfwSetWindowShouldClose(window, GLFW_TRUE);
|
||||
};
|
||||
return retained;
|
||||
}();
|
||||
return hooks;
|
||||
return state;
|
||||
}
|
||||
|
||||
[[nodiscard]] RetainedLegacyGlfwWindowHooks& active_legacy_glfw_window_hooks()
|
||||
{
|
||||
return active_legacy_glfw_window_state().hooks;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct RetainedLegacyStoragePaths final {
|
||||
pp::platform::PlatformStoragePaths storage_paths;
|
||||
};
|
||||
|
||||
[[nodiscard]] RetainedLegacyStoragePaths& active_legacy_storage_paths()
|
||||
{
|
||||
static RetainedLegacyStoragePaths state = [] {
|
||||
RetainedLegacyStoragePaths retained;
|
||||
retained.storage_paths = {
|
||||
App::I->data_path,
|
||||
App::I->work_path,
|
||||
App::I->rec_path,
|
||||
App::I->tmp_path,
|
||||
};
|
||||
return retained;
|
||||
}();
|
||||
return state;
|
||||
}
|
||||
|
||||
#if defined(__IOS__) || defined(__OSX__)
|
||||
[[nodiscard]] NSMutableArray<NSString*>* apple_file_types_array(const std::vector<std::string>& file_types)
|
||||
{
|
||||
@@ -377,12 +406,7 @@ public:
|
||||
{},
|
||||
};
|
||||
#else
|
||||
return {
|
||||
App::I->data_path,
|
||||
App::I->work_path,
|
||||
App::I->rec_path,
|
||||
App::I->tmp_path,
|
||||
};
|
||||
return active_legacy_storage_paths().storage_paths;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user