Files
iChris4 50dc354123 Add the cockpit, steering-wheel and hand-steering building blocks
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.
2026-09-22 03:55:40 +02:00

41 lines
1.7 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/mkw_vr_first_person.h"
#include <algorithm>
#include <cmath>
namespace mkw::vr {
// Simulation position and driving direction, never the animated vehicle matrix.
// Follow the simulation position exactly; stabilize only impact orientation.
class CockpitStabilizer {
public:
Mtx34 Update(const Mtx34& simulation, bool damaged, float dt) {
const float yaw = std::atan2(simulation[2], simulation[10]);
const float dx = simulation[3]-position_[0], dy = simulation[7]-position_[1], dz = simulation[11]-position_[2];
if (!valid_ || dx*dx+dy*dy+dz*dz > 1500.0f*1500.0f) {
position_ = {simulation[3],simulation[7],simulation[11]};
yaw_ = yaw; valid_ = true; recovering_ = false;
}
if (damaged) recovering_ = true;
else if (recovering_) {
const float alpha = 1.0f-std::exp(-8.0f*std::clamp(dt,0.0f,0.05f));
const float delta = std::remainder(yaw-yaw_,6.283185307f);
yaw_ += delta*alpha;
if (std::abs(delta)<0.002f) recovering_=false;
} else {
position_={simulation[3],simulation[7],simulation[11]}; yaw_=yaw;
}
// Freezing/blending translation left the seat behind after collisions.
// Dynamics excludes visual shake; retain its exact kart attachment.
position_={simulation[3],simulation[7],simulation[11]};
const float c=std::cos(yaw_),s=std::sin(yaw_);
return {c,0,s,position_[0], 0,1,0,position_[1], -s,0,c,position_[2]};
}
private:
std::array<float,3> position_{};
float yaw_=0;
bool valid_=false,recovering_=false;
};
}