Drive the engine's mouse cursor from the VR aim ray on the game quad
build / build (push) Successful in 1m44s
build / build (push) Successful in 1m44s
The game quad's laser beam was purely visual - aiming at the game's own UI (inventory, menus, dialogs) had no way to interact with it. Add a real mouse pointer: absolute cursor position plus a single left click, mirroring a plain point-and-click mouse (no mouselook, no right-click, no drag). New xr_mouse.c/h bridges the aim-ray hit-test to the vendored engine's own public mouse API - mouse_put_xy() for position, a synthetic SDL_MOUSEBUTTONDOWN/UP (SDL_BUTTON_LEFT) via SDL_PushEvent for clicks, the same technique nativeSendPrintableChar() already uses for synthetic keyboard input. No engine patch needed. Deliberately bypasses SDLActivity.onNativeMouse()/SDL_MOUSEMOTION/SetMouseXY(), whose physical-window-size scaling is unreliable in this headless immersive build. xr_input_try_game_quad() now reports the hit u,v; a new g_game_touch_active[] tracks a held click on the game quad so it survives the ray straying onto the keyboard/menu before release, gating those overlays' claims the same way pending overlay touches already do.
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <GLES3/gl3.h>
|
||||
|
||||
#include "xr_mouse.h"
|
||||
#include "xr_overlay.h"
|
||||
#include "xr_session.h"
|
||||
#include "xr_swapchain.h"
|
||||
@@ -53,6 +54,7 @@ static XrSpace g_aim_space[2] = {XR_NULL_HANDLE, XR_NULL_HANDLE};
|
||||
static bool g_prev_select[2] = {false, false};
|
||||
static bool g_prev_menu = false;
|
||||
static bool g_game_prev_hit[2] = {false, false};
|
||||
static bool g_game_touch_active[2] = {false, false};
|
||||
static bool g_menu_prev_hit[2] = {false, false};
|
||||
static bool g_menu_touch_active[2] = {false, false};
|
||||
static bool g_keyboard_prev_hit[2] = {false, false};
|
||||
@@ -524,12 +526,17 @@ static void xr_input_build_beam(int hand, const XrSpaceLocation *location, float
|
||||
|
||||
// Hit-tests this hand's ray against the game quad (xr_get_game_quad_extent())
|
||||
// - the lowest-priority target, tried only once neither the keyboard nor
|
||||
// menu overlay claimed the ray this frame. There's no touch/drag state
|
||||
// for the game quad yet (see the file comment above) - this purely drives
|
||||
// the laser-beam visual, symmetric with xr_input_try_overlay()'s `hit`
|
||||
// term but without a touch/drag component. Returns plain `hit`.
|
||||
// menu overlay claimed the ray this frame (or, symmetrically, once this
|
||||
// hand already has a pending mouse-down on the game quad - see
|
||||
// g_game_touch_active and the keyboard/menu call sites in
|
||||
// xr_input_sync_and_draw()). outU/outV (only meaningful when the
|
||||
// returned hit is true) let the caller drive the game's own mouse cursor
|
||||
// via xr_mouse.h. Returns plain `hit` - drag/touch dispatch for actual
|
||||
// clicks is the caller's responsibility (xr_mouse_click()), not this
|
||||
// function's, unlike xr_input_try_overlay().
|
||||
static bool xr_input_try_game_quad(int hand, const XrSpaceLocation *location, float fx, float fy,
|
||||
float fz, bool *outPlaneHit, float *outPlaneDistance) {
|
||||
float fz, bool *outPlaneHit, float *outPlaneDistance,
|
||||
float *outU, float *outV) {
|
||||
float distance, halfWidth, halfHeight;
|
||||
xr_get_game_quad_extent(&distance, &halfWidth, &halfHeight);
|
||||
|
||||
@@ -548,6 +555,8 @@ static bool xr_input_try_game_quad(int hand, const XrSpaceLocation *location, fl
|
||||
}
|
||||
*outPlaneHit = planeHit;
|
||||
*outPlaneDistance = t;
|
||||
*outU = u;
|
||||
*outV = v;
|
||||
|
||||
if (hit != g_game_prev_hit[hand]) {
|
||||
LOGI("XR: %s aim ray %s game quad (u=%.2f v=%.2f)", kHandName[hand],
|
||||
@@ -671,10 +680,18 @@ void xr_input_sync_and_draw(XrSpace baseSpace, XrTime time, bool draw) {
|
||||
// xr_input_try_overlay()'s doc comment) - the game quad itself.
|
||||
// Whichever target claims the ray gets a laser-beam quad built for
|
||||
// it (if a head pose is available and the ray actually crosses
|
||||
// that target's plane) - see xr_input_build_beam().
|
||||
// that target's plane) - see xr_input_build_beam(). Keyboard/menu
|
||||
// are additionally gated on !g_game_touch_active[hand]: a pending
|
||||
// mouse-down on the game quad (trigger still held since a
|
||||
// down-edge dispatched there) must keep claiming the ray even if
|
||||
// it strays onto another panel before release, the cross-target
|
||||
// analogue of xr_input_try_overlay()'s own hadTouch/hadDrag - the
|
||||
// eventual mouse-up has to reach the game quad, not whatever the
|
||||
// ray happens to be over on the release frame.
|
||||
bool keyboardPlaneHit = false;
|
||||
float keyboardPlaneDistance = 0.0f;
|
||||
if (xr_input_try_overlay(keyboardOverlay, true, hand, &location, fx, fy, fz,
|
||||
if (!g_game_touch_active[hand] &&
|
||||
xr_input_try_overlay(keyboardOverlay, true, hand, &location, fx, fy, fz,
|
||||
selectDownEdge, selectUpEdge, &g_keyboard_touch_active[hand],
|
||||
&g_keyboard_prev_hit[hand], "keyboard", &keyboardCursorU,
|
||||
&keyboardCursorV, &keyboardCursorHit, &keyboardPlaneHit,
|
||||
@@ -686,7 +703,8 @@ void xr_input_sync_and_draw(XrSpace baseSpace, XrTime time, bool draw) {
|
||||
}
|
||||
bool menuPlaneHit = false;
|
||||
float menuPlaneDistance = 0.0f;
|
||||
if (xr_input_try_overlay(menuOverlay, false, hand, &location, fx, fy, fz, selectDownEdge,
|
||||
if (!g_game_touch_active[hand] &&
|
||||
xr_input_try_overlay(menuOverlay, false, hand, &location, fx, fy, fz, selectDownEdge,
|
||||
selectUpEdge, &g_menu_touch_active[hand], &g_menu_prev_hit[hand],
|
||||
"menu", &menuCursorU, &menuCursorV, &menuCursorHit, &menuPlaneHit,
|
||||
&menuPlaneDistance)) {
|
||||
@@ -696,13 +714,36 @@ void xr_input_sync_and_draw(XrSpace baseSpace, XrTime time, bool draw) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Lowest priority: the game quad itself - purely visual (beam
|
||||
// only, same as the other two targets), no click/touch dispatch
|
||||
// here yet (see the file comment above).
|
||||
// Lowest priority (for a fresh hit): the game quad itself - drives
|
||||
// the engine's own mouse cursor/clicks via xr_mouse.h, exactly
|
||||
// like a desktop mouse (absolute position + left button), plus the
|
||||
// same laser-beam visual the other two targets get.
|
||||
bool gamePlaneHit = false;
|
||||
float gamePlaneDistance = 0.0f;
|
||||
bool gameHit =
|
||||
xr_input_try_game_quad(hand, &location, fx, fy, fz, &gamePlaneHit, &gamePlaneDistance);
|
||||
float gamePlaneDistance = 0.0f, gameU = 0.0f, gameV = 0.0f;
|
||||
bool gameHit = xr_input_try_game_quad(hand, &location, fx, fy, fz, &gamePlaneHit,
|
||||
&gamePlaneDistance, &gameU, &gameV);
|
||||
if (gameHit) {
|
||||
int gameWidth, gameHeight;
|
||||
xr_get_game_resolution(&gameWidth, &gameHeight);
|
||||
int px = (int)(gameU * (float)gameWidth);
|
||||
int py = (int)(gameV * (float)gameHeight);
|
||||
if (px < 0)
|
||||
px = 0;
|
||||
else if (px >= gameWidth)
|
||||
px = gameWidth - 1;
|
||||
if (py < 0)
|
||||
py = 0;
|
||||
else if (py >= gameHeight)
|
||||
py = gameHeight - 1;
|
||||
xr_mouse_move(px, py);
|
||||
}
|
||||
if (selectDownEdge && gameHit) {
|
||||
xr_mouse_click(true);
|
||||
g_game_touch_active[hand] = true;
|
||||
} else if (selectUpEdge && g_game_touch_active[hand]) {
|
||||
xr_mouse_click(false);
|
||||
g_game_touch_active[hand] = false;
|
||||
}
|
||||
// gameHit implies gamePlaneHit (both only ever set together above),
|
||||
// kept as a separate out-param for symmetry with
|
||||
// xr_input_try_overlay()'s outPlaneHit/outPlaneDistance pair.
|
||||
@@ -746,6 +787,7 @@ void xr_input_shutdown(void) {
|
||||
g_session = XR_NULL_HANDLE;
|
||||
memset(g_prev_select, 0, sizeof(g_prev_select));
|
||||
memset(g_game_prev_hit, 0, sizeof(g_game_prev_hit));
|
||||
memset(g_game_touch_active, 0, sizeof(g_game_touch_active));
|
||||
memset(g_menu_prev_hit, 0, sizeof(g_menu_prev_hit));
|
||||
memset(g_menu_touch_active, 0, sizeof(g_menu_touch_active));
|
||||
memset(g_keyboard_prev_hit, 0, sizeof(g_keyboard_prev_hit));
|
||||
|
||||
Reference in New Issue
Block a user