From a4499c1c1674039664cd1058d92e58448c484dba Mon Sep 17 00:00:00 2001 From: DeeJanuz <45082401+DeeJanuz@users.noreply.github.com> Date: Sat, 26 Sep 2026 19:59:38 -0600 Subject: [PATCH] Reveal a screen's controls when a laser lands on them Hidden controls were taken out of SteamVR, so only ft-screens' own proximity test could bring them back, and that test didn't match every controller's laser. They now stay in place fully transparent while hidden, and SteamVR's hover event on one reveals them, for any laser. Co-Authored-By: Claude Opus 5.5 --- docs/reference.md | 2 +- screens/vr.cpp | 25 ++++++++++++------------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/docs/reference.md b/docs/reference.md index d0d564f..1602331 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -35,7 +35,7 @@ Every screen is an overlay named `frametop.screen.N` with four controls: - `.roll` rolls the screen when you drag it sideways, like a knob. It snaps level within 2.5°, and scrolling on it turns 5° per notch. - `.resize`, the tab on the bottom right corner, sets the width. Screens go down to 15 cm wide. -The controls are sized from both the screen's width and its distance from you, follow the surface of a curved screen, and stay invisible until a laser or the 3D mouse's cursor comes within about 1.5 times a button's size of one. They're translucent until a laser is on them, like SteamVR's own window controls. +The controls are sized from both the screen's width and its distance from you, follow the surface of a curved screen, and stay invisible until a laser or the 3D mouse's cursor lands on one or comes within about 1.5 times a button's size of it. While invisible they're still there, fully transparent, so SteamVR's laser can find them. They're translucent until a laser is on them, like SteamVR's own window controls. To pin a screen to a wrist, carry it by its bar and sweep the laser across your other controller. A ring around that controller marks the target, and a dot shows where the laser passes. Crossing the ring arms the pin, and the ring and bar turn blue; crossing it again disarms it. When you let go while armed, the screen rides on that controller at the size, distance, and angle it had, so you can arm the pin first and then turn the screen the way you want. Grab a pinned screen's bar to adjust it; it goes back to the same wrist when you let go unless you disarm it. A pinned screen shows only while you're looking at its front, within the wrist angle, and fades out over the last 10°. diff --git a/screens/vr.cpp b/screens/vr.cpp index cfdc9ea..e0cf256 100644 --- a/screens/vr.cpp +++ b/screens/vr.cpp @@ -12,7 +12,7 @@ // - a resize tab on the bottom right corner: drag it to set the width (the height // follows the screen's resolution). // The controls are translucent, like SteamVR's own, and brighten under a laser. They -// are invisible until a laser (a controller's, or the 3D mouse's) passes very close to +// are invisible until a laser (a controller's, or the 3D mouse's) lands on or passes very close to // one of them (UpdateControls). // - pin to a wrist: while carrying a screen, sweep the laser (the line from the carrying // device to the bar) across your other controller. A ring around each controller @@ -672,9 +672,9 @@ void UpdateLasers() { } } -// The controls are invisible until a laser passes very close to one of them (within -// `reach`, about 1.5 times a button's size); they stay kControlsLinger ticks after it -// leaves, and while in use. +// The controls are invisible until a laser is on one of them (SteamVR's hover event) or +// passes very close (within `reach`, about 1.5 times a button's size); they stay +// kControlsLinger ticks after it leaves, and while in use. void UpdateControls() { std::vector lasers; for (vr::TrackedDeviceIndex_t i = 1; i < vr::k_unMaxTrackedDeviceCount; ++i) { @@ -711,18 +711,17 @@ void UpdateControls() { } const bool inUse = s.drag != Drag::None || s.hover[0] || s.hover[1] || s.hover[2] || s.hover[3]; const bool want = s.visible && (inUse || g_tick < s.nearUntil); - const float before = s.controls; - s.controls = std::clamp(s.controls + (want ? 0.2f : -0.1f), 0.f, 1.f); - if (s.controls == before) continue; - if (s.controls > 0 && !s.controlsUp) { + // The controls stay shown while their screen is, just fully transparent when not + // wanted: SteamVR's laser still hits them, and the hover event brings them in, for + // any device's laser, whatever its shape. + if (s.visible && !s.controlsUp) { for (auto o : s.Controls()) vr::VROverlay()->ShowOverlay(o); s.controlsUp = true; + ApplyAlpha(s); } - ApplyAlpha(s); - if (s.controls == 0 && s.controlsUp) { - for (auto o : s.Controls()) vr::VROverlay()->HideOverlay(o); - s.controlsUp = false; - } + const float before = s.controls; + s.controls = std::clamp(s.controls + (want ? 0.2f : -0.1f), 0.f, 1.f); + if (s.controls != before) ApplyAlpha(s); } }