Give the game quad the same laser-beam pointer as the overlays

Aiming looked and behaved differently depending on whether the
keyboard/menu was open: xr_input_try_overlay() claimed a hand's ray for
its overlay whenever the overlay was merely visible, regardless of
whether the ray was actually pointed at it - so with the keyboard open,
aiming at the main game screen still showed a beam terminating at the
keyboard's fixed depth, while closing the keyboard swapped in the old
flat cross-shaped reticle at whatever the ray was really pointing at.

Only claim an overlay when the ray is actually relevant this frame - a
real hit, or a touch/drag begun on a previous frame still pending
release - so a visible-but-unaimed-at overlay now falls through to the
next-priority target. Give the game quad its own hit-test
(xr_input_try_game_quad()) and the same billboarded laser-beam
treatment as the overlays instead of the old flat reticle, so aiming
looks and behaves identically everywhere - overlay open or not. The
old reticle GL program/shaders are now fully dead and removed. No
click/touch dispatch is added to the game quad itself; that's future
work.
This commit is contained in:
ml
2026-08-14 07:59:09 +02:00
parent 920842a465
commit 824b4a2506
4 changed files with 117 additions and 159 deletions
+23 -18
View File
@@ -1,16 +1,20 @@
// Controller input for questshock's immersive Quest build: one OpenXR
// action set (aim pose + trigger click per hand, a menu-toggle button on
// the left controller) plus ray/quad hit-testing. While neither the menu
// launcher nor keyboard overlay (see xr_overlay.h, xr_session.c) is
// visible, this tests against the game quad xr_session.c submits and draws
// a small reticle where each hand's aim ray crosses it; while either
// overlay is visible, it tests against that overlay's quad instead (the
// keyboard is tried first), forwards trigger edges as synthetic touches,
// and - since neither overlay's own on-quad cursor gives any feedback
// while the ray is short of actually landing on it - builds a thin,
// billboarded laser-beam quad per hand from the controller to wherever
// the ray currently crosses that overlay's plane (see
// xr_input_get_beam_layer()).
// the left controller) plus ray/quad hit-testing. Each hand's ray is
// tried against the keyboard overlay, then the menu overlay (see
// xr_overlay.h, xr_session.c), then - only if neither actually claims it
// this frame (landing on it now, or continuing a touch/drag begun on a
// previous frame - not merely because that overlay happens to be visible)
// - the game quad xr_session.c submits, forwarding trigger edges to
// whichever overlay claims the ray as synthetic touches. Since none of
// the three targets' own feedback (the overlays' on-quad cursor, drawn by
// their Java views; nothing at all for the game quad, which has no
// click/touch dispatch here yet) gives any indication while the ray is
// short of actually landing on something, every claimed target also
// builds a thin, billboarded laser-beam quad per hand from the controller
// to wherever the ray currently crosses that target's plane (see
// xr_input_get_beam_layer()) - so aiming looks and behaves the same
// whether the target is an overlay or the game quad itself.
#ifndef QUESTSHOCK_XR_INPUT_H
#define QUESTSHOCK_XR_INPUT_H
@@ -38,17 +42,18 @@ bool xr_input_init(XrInstance instance, XrSession session, int64_t swapchain_for
// Call once per frame from xr_frame_end(), before releasing the acquired
// swapchain image - syncs this frame's action states (always, so edge
// detection stays correct even on frames with nothing to draw), handles
// the menu_toggle button's edge, and either draws a game-quad reticle or
// forwards menu-quad touches, per the menu's current visibility (see the
// file comment above). draw gates only the reticle - if false (nothing to
// draw into this frame, e.g. no swapchain image was acquired), hit-testing
// and touch-forwarding still run. baseSpace/time must match whatever
// the menu_toggle button's edge, and hit-tests/dispatches each hand's ray
// against keyboard/menu/game quad in that priority order (see the file
// comment above). draw gates only the laser-beam visuals (and the
// head-pose locate that feeds them) - if false (nothing to draw into this
// frame, e.g. no swapchain image was acquired), hit-testing and
// touch-forwarding still run. baseSpace/time must match whatever
// xr_frame_begin() used to predict this frame.
void xr_input_sync_and_draw(XrSpace baseSpace, XrTime time, bool draw);
// Call once per hand (hand: 0=left, 1=right) after xr_input_sync_and_draw()
// in the same frame - if that hand's ray claimed the keyboard or menu
// overlay this frame (see the file comment above), fills *out_quad's
// in the same frame - if that hand's ray claimed the keyboard, menu, or
// game quad this frame (see the file comment above), fills *out_quad's
// subImage/pose/size for its laser-beam ribbon and returns true.
// space/eyeVisibility/layerFlags are left for the caller to set, same
// convention as xr_overlay_render_and_build_layer(). Returns false