mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-06 06:00:25 +02:00
Implement OpenXR Settings Panel and Stereo Overlay
This commit is contained in:
1 parent
f222eedf6b
commit
1346e53cd6
22 files changed
+1466
-101
No files matched your search
@@ -0,0 +1,190 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
//
|
||||
// The in-headset settings panel's controller handling, tested without a
|
||||
// headset: the thumbstick chord that opens and closes it, the release latch that
|
||||
// keeps a closing press out of the game, selection, scrolling, and where a hit
|
||||
// lands on the panel's canvas.
|
||||
|
||||
#include "vr/openxr_settings_panel.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace mkw::vr;
|
||||
using namespace mkw::vr::settings_panel;
|
||||
|
||||
int g_failures = 0;
|
||||
|
||||
void Check(bool condition, const char* what) {
|
||||
if (!condition) {
|
||||
++g_failures;
|
||||
std::cerr << "FAILED: " << what << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
void CheckNear(float actual, float expected, const char* what, float tolerance = 1.0e-3f) {
|
||||
if (!(std::fabs(actual - expected) <= tolerance)) {
|
||||
++g_failures;
|
||||
std::cerr << "FAILED: " << what << " (expected " << expected << ", got " << actual << ")\n";
|
||||
}
|
||||
}
|
||||
|
||||
constexpr float kDt = 1.0f / 90.0f;
|
||||
|
||||
std::array<HandInputs, 2> Released() {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::array<HandInputs, 2> Chord() {
|
||||
std::array<HandInputs, 2> hands{};
|
||||
hands[0].thumbstick_click = true;
|
||||
hands[1].thumbstick_click = true;
|
||||
return hands;
|
||||
}
|
||||
|
||||
void ChordOpensAndClosesOnce() {
|
||||
Controls controls;
|
||||
bool open = false;
|
||||
|
||||
auto one = Released();
|
||||
one[0].thumbstick_click = true;
|
||||
Frame frame = controls.Update(one, open, kDt);
|
||||
Check(!open && !frame.withheld, "one thumbstick click alone neither opens nor withholds");
|
||||
|
||||
frame = controls.Update(Chord(), open, kDt);
|
||||
Check(open && frame.open && frame.withheld, "clicking both thumbsticks opens the panel");
|
||||
frame = controls.Update(Chord(), open, kDt);
|
||||
Check(open, "holding the chord does not toggle again");
|
||||
frame = controls.Update(Released(), open, kDt);
|
||||
Check(open && frame.withheld, "the panel stays open and keeps the controllers after the chord is released");
|
||||
|
||||
frame = controls.Update(Chord(), open, kDt);
|
||||
Check(!open && !frame.open, "the chord closes the panel again");
|
||||
Check(frame.withheld, "the closing chord is still withheld from the game");
|
||||
frame = controls.Update(Released(), open, kDt);
|
||||
Check(!frame.withheld, "the game gets the controllers back once everything is released");
|
||||
}
|
||||
|
||||
void MenuClosesAndItsPressStaysOutOfTheGame() {
|
||||
Controls controls;
|
||||
bool open = false;
|
||||
controls.Update(Chord(), open, kDt);
|
||||
controls.Update(Released(), open, kDt);
|
||||
|
||||
auto menu = Released();
|
||||
menu[0].menu = true;
|
||||
Frame frame = controls.Update(menu, open, kDt);
|
||||
Check(!open, "the left menu button closes an open panel");
|
||||
frame = controls.Update(menu, open, kDt);
|
||||
Check(frame.withheld, "HOME held across the close does not reach the game");
|
||||
Check(!open, "a held menu button does not reopen the panel");
|
||||
frame = controls.Update(Released(), open, kDt);
|
||||
Check(!frame.withheld, "released, the controllers go back to the game");
|
||||
|
||||
frame = controls.Update(menu, open, kDt);
|
||||
Check(!open && !frame.withheld, "with the panel closed the menu button is the game's");
|
||||
}
|
||||
|
||||
void SelectWaitsForAReleaseAndFollowsTheTrigger() {
|
||||
Controls controls;
|
||||
bool open = false;
|
||||
// Opened from the settings bar while a trigger is held for the game.
|
||||
auto trigger = Released();
|
||||
trigger[1].trigger = 1.0f;
|
||||
controls.Update(trigger, open, kDt);
|
||||
open = true;
|
||||
Frame frame = controls.Update(trigger, open, kDt);
|
||||
Check(frame.open && !frame.select, "a trigger held from before the panel opened does not click");
|
||||
frame = controls.Update(Released(), open, kDt);
|
||||
Check(!frame.select, "nothing held, nothing selected");
|
||||
frame = controls.Update(trigger, open, kDt);
|
||||
Check(frame.select && frame.pointing_hand == 1, "a fresh right trigger selects and points with the right hand");
|
||||
|
||||
auto left = Released();
|
||||
left[0].trigger = 0.9f;
|
||||
controls.Update(Released(), open, kDt);
|
||||
frame = controls.Update(left, open, kDt);
|
||||
Check(frame.select && frame.pointing_hand == 0, "pulling the left trigger hands the pointer to the left hand");
|
||||
|
||||
auto button = Released();
|
||||
button[1].primary = true;
|
||||
controls.Update(Released(), open, kDt);
|
||||
frame = controls.Update(button, open, kDt);
|
||||
Check(frame.select && frame.pointing_hand == 0, "A selects without moving the pointer to another hand");
|
||||
}
|
||||
|
||||
void ThumbstickScrolls() {
|
||||
Controls controls;
|
||||
bool open = true;
|
||||
controls.Update(Released(), open, kDt);
|
||||
|
||||
auto small = Released();
|
||||
small[1].stick_y = 0.2f;
|
||||
Check(controls.Update(small, open, kDt).wheel == 0.0f, "a resting thumbstick does not scroll");
|
||||
|
||||
auto up = Released();
|
||||
up[1].stick_y = 1.0f;
|
||||
CheckNear(controls.Update(up, open, 0.5f).wheel, kScrollStepsPerSecond * 0.1f,
|
||||
"full deflection scrolls up at the full rate, with a long frame clamped");
|
||||
auto down = Released();
|
||||
down[0].stick_y = -1.0f;
|
||||
down[1].stick_y = 0.3f;
|
||||
Check(controls.Update(down, open, kDt).wheel < 0.0f, "the more deflected stick decides the direction");
|
||||
|
||||
bool closed = false;
|
||||
Controls idle;
|
||||
Check(idle.Update(up, closed, kDt).wheel == 0.0f, "a closed panel does not scroll");
|
||||
}
|
||||
|
||||
void HitsMapOntoTheCanvas() {
|
||||
wii_remote::ScreenHit hit{};
|
||||
hit.valid = true;
|
||||
hit.u = -1.0f;
|
||||
hit.v = 1.0f;
|
||||
auto point = CanvasPoint(hit);
|
||||
CheckNear(point[0], 0.0f, "the panel's left edge is canvas x 0");
|
||||
CheckNear(point[1], 0.0f, "the panel's top edge is canvas y 0");
|
||||
hit.u = 1.0f;
|
||||
hit.v = -1.0f;
|
||||
point = CanvasPoint(hit);
|
||||
CheckNear(point[0], kSettingsPanelWidthPixels, "the right edge is the canvas width");
|
||||
CheckNear(point[1], kSettingsPanelHeightPixels, "the bottom edge is the canvas height");
|
||||
|
||||
const auto extents = HalfExtents(2.4f);
|
||||
CheckNear(extents[0], 0.9f, "three quarters of a 2.4 m screen is 1.8 m across");
|
||||
CheckNear(extents[1], 0.675f, "and keeps the canvas's 4:3");
|
||||
}
|
||||
|
||||
void BridgeAccumulatesWheelUntilTaken() {
|
||||
OpenXRSetSettingsPanelOpen(true);
|
||||
Check(OpenXRSettingsPanelOpen(), "the open flag is shared");
|
||||
OpenXRPublishSettingsPanelPointer(true, 10.0f, 20.0f, false, 0.5f);
|
||||
OpenXRPublishSettingsPanelPointer(true, 11.0f, 21.0f, true, 0.25f);
|
||||
OpenXRSettingsPanelPointer pointer = OpenXRTakeSettingsPanelPointer();
|
||||
Check(pointer.valid && pointer.select, "the latest pointer state is read");
|
||||
CheckNear(pointer.x, 11.0f, "the latest x is read");
|
||||
CheckNear(pointer.wheel, 0.75f, "wheel steps from every XR frame are kept");
|
||||
pointer = OpenXRTakeSettingsPanelPointer();
|
||||
CheckNear(pointer.wheel, 0.0f, "taking the pointer consumes its wheel steps");
|
||||
OpenXRSetSettingsPanelOpen(false);
|
||||
Check(!OpenXRSettingsPanelOpen(), "and can be cleared again");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
ChordOpensAndClosesOnce();
|
||||
MenuClosesAndItsPressStaysOutOfTheGame();
|
||||
SelectWaitsForAReleaseAndFollowsTheTrigger();
|
||||
ThumbstickScrolls();
|
||||
HitsMapOntoTheCanvas();
|
||||
BridgeAccumulatesWheelUntilTaken();
|
||||
if (g_failures != 0) {
|
||||
std::cerr << g_failures << " check(s) failed\n";
|
||||
return 1;
|
||||
}
|
||||
std::cout << "vr_settings_panel_tests: all checks passed\n";
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user