Extract dialog, VR, and canvas draw helpers

This commit is contained in:
2026-06-16 11:40:00 +02:00
parent 18665bdffc
commit d2a841f348
9 changed files with 566 additions and 377 deletions

View File

@@ -0,0 +1,141 @@
#pragma once
#include "app.h"
#include "hmd.h"
#include "log.h"
#include <atomic>
#include <condition_variable>
#include <functional>
#include <memory>
#include <mutex>
#include <thread>
namespace pp::platform::windows {
struct VrShellState final {
std::jthread hmd_renderer;
std::mutex hmd_render_mutex;
std::condition_variable hmd_render_cv;
std::unique_ptr<Vive> vive;
std::atomic<int> vr_frames{0};
std::atomic_bool vr_running{false};
};
inline int current_vr_fps(const VrShellState& state)
{
return state.vr_frames.load(std::memory_order_relaxed);
}
inline void request_stop_and_join_vr_thread(VrShellState& state)
{
if (state.hmd_renderer.joinable())
{
state.hmd_renderer.request_stop();
state.hmd_renderer.join();
}
}
inline bool start_vr_shell(VrShellState& state, bool sandboxed, std::atomic<int>& running)
{
if (sandboxed)
return false;
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())
{
state.vive.reset();
LOG("VR: failed to initialize vive");
return false;
}
if (state.hmd_renderer.joinable())
{
state.hmd_renderer.request_stop();
state.hmd_renderer.join();
}
state.hmd_renderer = std::jthread([&state, &running](std::stop_token stop_token) {
if (!state.vive)
return;
BT_SetTerminate();
LOG("start hmd render thread");
App::I->has_vr = true;
state.vr_running.store(true, std::memory_order_relaxed);
state.vive->on_analog_button = std::bind(&App::vr_analog, App::I, std::placeholders::_1,
std::placeholders::_2, std::placeholders::_3, std::placeholders::_4);
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([] {
App::I->vr_draw_ui();
});
const float target_tick_rate = 90;
auto t0 = GetTickCount64();
float one_sec_timer = 0;
int frames = 0;
while (!stop_token.stop_requested() &&
state.vr_running.load(std::memory_order_relaxed) &&
running.load(std::memory_order_relaxed) == 1 &&
state.vive->Valid())
{
std::unique_lock<std::mutex> lock(state.hmd_render_mutex);
auto t1 = GetTickCount64();
float dt = (float)(t1 - t0) / 1000.0f;
one_sec_timer += dt;
if (one_sec_timer >= 1.f)
{
one_sec_timer = 0;
state.vr_frames.store(frames, std::memory_order_relaxed);
frames = 0;
}
frames++;
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 (state.vr_running.load(std::memory_order_relaxed) && state.vive->m_active)
{
App::I->render_task([&state] {
state.vive->Draw();
});
}
const int framerate = (1.f / target_tick_rate) * 1000;
const int diff = framerate - (t1 - t0);
(void)diff;
//state.hmd_render_cv.wait_for(lock, std::chrono::milliseconds(diff));
t0 = t1;
}
App::I->vr_active = false;
App::I->has_vr = false;
state.vr_running.store(false, std::memory_order_relaxed);
state.vive->Terminate();
LOG("hmd renderer terminated");
});
return true;
}
inline void stop_vr_shell(VrShellState& state)
{
if (state.vive)
{
state.vr_running.store(false, std::memory_order_relaxed);
request_stop_and_join_vr_thread(state);
state.vive->Terminate();
state.vive.reset();
}
}
}