Add VR locomotion: move/turn with thumbsticks while the menu is open
build / build (push) Successful in 2m25s
build / build (push) Successful in 2m25s
- Left thumbstick snap-turns, right thumbstick smooth-moves, letting the
player line themselves up with the fixed game quad ("virtual screen")
without needing physical room-scale space to do it in. Implemented via
a second OpenXR reference space (a "play space") derived from the real
LOCAL space by the inverse of the player's transform, so every existing
quad/hit-testing/rendering call site just needed g_local_space swapped
for it - no manual coordinate-transform math required elsewhere
- Generalized the ray/quad hit-testing in xr_input.c to a proper
oriented-plane intersection (needed once quads can rotate); verified it
degenerates to the old axis-aligned formula when unrotated, so the
keyboard and non-recentered menu are unaffected
- The menu launcher now re-centers in front of the player, correctly
oriented to face them, each time it's freshly reopened
- "Reset Position" (Main Menu tab) recenters using the player's current
real head pose - not a plain reset-to-origin, which only undid
thumbstick movement and ignored physical drift since the session
started. The same recenter runs once automatically at startup too, as a
fallback for when there's no complete saved position to use instead
- Position/orientation persists in questshock.config.json's new
player_position group (independent of savegames), including new
numeric-value support in the config file's hand-rolled JSON parser
(previously string-enums only)
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#include "xr_overlay.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -18,11 +19,33 @@
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
|
||||
|
||||
// Same constant (deliberately not <math.h>'s M_PI, which isn't used
|
||||
// anywhere else in this codebase and isn't guaranteed by the C standard -
|
||||
// only POSIX) as xr_session.c's own play-space rebuild math.
|
||||
#define QS_DEG_TO_RAD (3.14159265358979323846f / 180.0f)
|
||||
|
||||
struct XrOverlay {
|
||||
XrInstance instance; // for error logging only
|
||||
int width, height;
|
||||
float distance_m, half_width_m, half_height_m;
|
||||
float center_x_m, center_y_m;
|
||||
// The *authored* distance_m (config->distance_m at creation time),
|
||||
// never touched again afterward by anything, including
|
||||
// xr_overlay_set_pose() - kept separate from the live, mutable
|
||||
// distance_m above because that one stops meaning "how far in front of
|
||||
// the origin" once a rotated set_pose() call (the menu recenter)
|
||||
// repurposes it as a raw base-space Z coordinate; reusing *that* as a
|
||||
// "how far in front of me" magnitude on a later recenter would drift
|
||||
// further with every reopen instead of staying at a stable distance -
|
||||
// see xr_overlay_get_default_distance_m().
|
||||
float default_distance_m;
|
||||
// Rotation about the vertical axis, applied on top of center_x_m/
|
||||
// center_y_m/distance_m (see xr_overlay_set_pose()) - 0 for every
|
||||
// overlay except the menu launcher immediately after it's freshly
|
||||
// reopened (xr_input.c re-centers it in front of wherever the player
|
||||
// is currently facing, which needs this to keep the quad actually
|
||||
// facing them instead of whatever direction it started out at).
|
||||
float yaw_deg;
|
||||
bool visible;
|
||||
|
||||
XrSwapchainState swapchain;
|
||||
@@ -205,6 +228,7 @@ XrOverlay *xr_overlay_create(XrInstance instance, XrSession session, int64_t swa
|
||||
overlay->width = config->width;
|
||||
overlay->height = config->height;
|
||||
overlay->distance_m = config->distance_m;
|
||||
overlay->default_distance_m = config->distance_m;
|
||||
overlay->half_width_m = config->width_m * 0.5f;
|
||||
overlay->half_height_m = config->width_m * 0.5f * (float)config->height / (float)config->width;
|
||||
overlay->center_x_m = config->default_center_x_m;
|
||||
@@ -281,9 +305,10 @@ void xr_overlay_set_visible(XrOverlay *overlay, bool visible) {
|
||||
bool xr_overlay_is_visible(const XrOverlay *overlay) { return overlay != NULL && overlay->visible; }
|
||||
|
||||
void xr_overlay_get_quad_extent(const XrOverlay *overlay, float *center_x_m, float *center_y_m,
|
||||
float *distance_m, float *half_width_m, float *half_height_m) {
|
||||
float *distance_m, float *half_width_m, float *half_height_m,
|
||||
float *yaw_deg) {
|
||||
if (overlay == NULL) {
|
||||
*center_x_m = *center_y_m = *distance_m = *half_width_m = *half_height_m = 0.0f;
|
||||
*center_x_m = *center_y_m = *distance_m = *half_width_m = *half_height_m = *yaw_deg = 0.0f;
|
||||
return;
|
||||
}
|
||||
*center_x_m = overlay->center_x_m;
|
||||
@@ -291,6 +316,7 @@ void xr_overlay_get_quad_extent(const XrOverlay *overlay, float *center_x_m, flo
|
||||
*distance_m = overlay->distance_m;
|
||||
*half_width_m = overlay->half_width_m;
|
||||
*half_height_m = overlay->half_height_m;
|
||||
*yaw_deg = overlay->yaw_deg;
|
||||
}
|
||||
|
||||
void xr_overlay_set_position(XrOverlay *overlay, float center_x_m, float center_y_m) {
|
||||
@@ -300,6 +326,20 @@ void xr_overlay_set_position(XrOverlay *overlay, float center_x_m, float center_
|
||||
overlay->center_y_m = center_y_m;
|
||||
}
|
||||
|
||||
void xr_overlay_set_pose(XrOverlay *overlay, float center_x_m, float center_y_m, float distance_m,
|
||||
float yaw_deg) {
|
||||
if (overlay == NULL)
|
||||
return;
|
||||
overlay->center_x_m = center_x_m;
|
||||
overlay->center_y_m = center_y_m;
|
||||
overlay->distance_m = distance_m;
|
||||
overlay->yaw_deg = yaw_deg;
|
||||
}
|
||||
|
||||
float xr_overlay_get_default_distance_m(const XrOverlay *overlay) {
|
||||
return overlay == NULL ? 0.0f : overlay->default_distance_m;
|
||||
}
|
||||
|
||||
void xr_overlay_touch(XrOverlay *overlay, float u, float v, bool down) {
|
||||
if (overlay == NULL)
|
||||
return;
|
||||
@@ -443,7 +483,17 @@ bool xr_overlay_render_and_build_layer(XrOverlay *overlay, XrCompositionLayerQua
|
||||
out_quad->subImage.swapchain = overlay->swapchain.swapchain;
|
||||
out_quad->subImage.imageRect.extent.width = overlay->swapchain.width;
|
||||
out_quad->subImage.imageRect.extent.height = overlay->swapchain.height;
|
||||
out_quad->pose.orientation.w = 1.0f;
|
||||
// Rotation about the vertical axis only (see the struct field's own
|
||||
// comment) - same R_y(-yaw_deg) quaternion construction as
|
||||
// xr_session.c's own play-space rebuild, for the same reason: this
|
||||
// quad's pose is expressed as "yaw_deg turned from its own local -Z",
|
||||
// so a point/ray in that rotated frame maps back into the (unrotated)
|
||||
// base space by rotating by -yaw_deg.
|
||||
float half = -(overlay->yaw_deg * QS_DEG_TO_RAD) * 0.5f;
|
||||
out_quad->pose.orientation.x = 0.0f;
|
||||
out_quad->pose.orientation.y = sinf(half);
|
||||
out_quad->pose.orientation.z = 0.0f;
|
||||
out_quad->pose.orientation.w = cosf(half);
|
||||
out_quad->pose.position.x = overlay->center_x_m;
|
||||
out_quad->pose.position.y = overlay->center_y_m;
|
||||
out_quad->pose.position.z = -overlay->distance_m;
|
||||
|
||||
Reference in New Issue
Block a user