mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-06 01:00:14 +02:00
The pure pieces of the first-person cockpit and hand steering, ported from
heurazy's mario-kart-wii-VR-port: the SteeringWheel grab/turn model, the
native wheel vertex rotation, the level seat stabiliser, the seated-eye and
wheel/handlebar geometry, and the XR_FB_hand_tracking_mesh loader. Adds
openxr_driving.h, the OpenXR-free snapshot the pacing thread will publish for
the guest thread, with the hand-off rule (a held wheel replaces the left
stick's X and releases that hand's grip for the game) and the wheel's
displayed angle.
New [vr] keys: first_person_seat (cockpit), cockpit_units_per_meter (100),
steering_wheel (true), native_steering_wheel (true), hand_steering (false)
and the seven wheel_* tuning keys. Nothing reads them yet.
The fresh-config template now writes the first-person defaults the
constants hold (50 / 1.5 / 0); d86dcb0 updated the constants but not the
template.
Tests: mkw_steering_wheel_tests (the fork's), mkw_vr_cockpit_tests,
mkw_vr_hand_steering_tests.
76 lines
4.2 KiB
C++
76 lines
4.2 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
// Ported from heurazy's mario-kart-wii-VR-port (GPL-3.0-or-later).
|
|
#pragma once
|
|
#include "vr/openxr_runtime.h"
|
|
#include <aurora/aurora.h>
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <cstring>
|
|
#include <vector>
|
|
|
|
namespace mkw::vr {
|
|
// AnimalCrossing-VR-MR-Standalone obtains its white hands from this Meta
|
|
// runtime extension, not from a distributable model asset. Use the same API,
|
|
// with a procedural fallback on PC runtimes that do not expose Meta meshes.
|
|
inline bool LoadRuntimeHandMeshes(OpenXRRuntime& runtime) {
|
|
for (uint32_t h = 0; h < 2; ++h)
|
|
aurora_set_vr_hand_mesh(h, nullptr, 0, nullptr, 0, nullptr, nullptr, 0);
|
|
const auto& extensions = runtime.EnabledExtensions();
|
|
if (std::find(extensions.begin(), extensions.end(), XR_FB_HAND_TRACKING_MESH_EXTENSION_NAME) == extensions.end())
|
|
return false;
|
|
PFN_xrCreateHandTrackerEXT create = nullptr;
|
|
PFN_xrDestroyHandTrackerEXT destroy = nullptr;
|
|
PFN_xrGetHandMeshFB meshFn = nullptr;
|
|
xrGetInstanceProcAddr(runtime.Instance(), "xrCreateHandTrackerEXT", reinterpret_cast<PFN_xrVoidFunction*>(&create));
|
|
xrGetInstanceProcAddr(runtime.Instance(), "xrDestroyHandTrackerEXT", reinterpret_cast<PFN_xrVoidFunction*>(&destroy));
|
|
xrGetInstanceProcAddr(runtime.Instance(), "xrGetHandMeshFB", reinterpret_cast<PFN_xrVoidFunction*>(&meshFn));
|
|
if (!create || !destroy || !meshFn) return false;
|
|
bool any = false;
|
|
for (uint32_t h = 0; h < 2; ++h) {
|
|
XrHandTrackerCreateInfoEXT info{XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT};
|
|
info.hand = h ? XR_HAND_RIGHT_EXT : XR_HAND_LEFT_EXT;
|
|
info.handJointSet = XR_HAND_JOINT_SET_DEFAULT_EXT;
|
|
XrHandTrackerEXT tracker = XR_NULL_HANDLE;
|
|
if (XR_FAILED(create(runtime.Session(), &info, &tracker))) continue;
|
|
struct Guard { XrHandTrackerEXT tracker; PFN_xrDestroyHandTrackerEXT destroy; ~Guard() { destroy(tracker); } } guard{tracker, destroy};
|
|
XrHandTrackingMeshFB mesh{XR_TYPE_HAND_TRACKING_MESH_FB};
|
|
if (XR_FAILED(meshFn(tracker, &mesh)) || mesh.jointCountOutput != 26 ||
|
|
!mesh.vertexCountOutput || mesh.vertexCountOutput > 65535 || !mesh.indexCountOutput ||
|
|
mesh.indexCountOutput > 100000 || mesh.indexCountOutput % 3) continue;
|
|
std::vector<XrPosef> poses(mesh.jointCountOutput);
|
|
std::vector<float> radii(mesh.jointCountOutput);
|
|
std::vector<XrHandJointEXT> parents(mesh.jointCountOutput);
|
|
std::vector<XrVector3f> positions(mesh.vertexCountOutput), normals(mesh.vertexCountOutput);
|
|
std::vector<XrVector2f> uv(mesh.vertexCountOutput);
|
|
std::vector<XrVector4sFB> joints(mesh.vertexCountOutput);
|
|
std::vector<XrVector4f> weights(mesh.vertexCountOutput);
|
|
std::vector<int16_t> indices(mesh.indexCountOutput);
|
|
mesh.jointCapacityInput = poses.size(); mesh.jointBindPoses = poses.data();
|
|
mesh.jointRadii = radii.data(); mesh.jointParents = parents.data();
|
|
mesh.vertexCapacityInput = positions.size(); mesh.vertexPositions = positions.data();
|
|
mesh.vertexNormals = normals.data(); mesh.vertexUVs = uv.data();
|
|
mesh.vertexBlendIndices = joints.data(); mesh.vertexBlendWeights = weights.data();
|
|
mesh.indexCapacityInput = indices.size(); mesh.indices = indices.data();
|
|
if (XR_FAILED(meshFn(tracker, &mesh))) continue;
|
|
std::vector<AuroraVRHandVertex> vertices(positions.size());
|
|
for (size_t i = 0; i < vertices.size(); ++i) {
|
|
auto& v = vertices[i];
|
|
std::memcpy(v.position, &positions[i], sizeof(v.position));
|
|
std::memcpy(v.joints, &joints[i], sizeof(v.joints));
|
|
std::memcpy(v.weights, &weights[i], sizeof(v.weights));
|
|
}
|
|
std::array<float, 26 * 7> bind{};
|
|
std::array<int32_t, 26> parentIds{};
|
|
for (size_t j = 0; j < poses.size(); ++j) {
|
|
std::memcpy(bind.data() + j * 7, &poses[j], 7 * sizeof(float));
|
|
parentIds[j] = static_cast<int32_t>(parents[j]);
|
|
}
|
|
aurora_set_vr_hand_mesh(h, vertices.data(), vertices.size(),
|
|
reinterpret_cast<const uint16_t*>(indices.data()), indices.size(), bind.data(), parentIds.data(), poses.size());
|
|
any = true;
|
|
}
|
|
return any;
|
|
}
|
|
} // namespace mkw::vr
|