Launcher/build-dawn-linux.sh builds the pinned Dawn with Aurora's Vulkan hook
and density map patches into a package local-build.sh takes through the new
--dawn-package option, together with --openxr, --headset steam_frame and
--cpu. docs/steam-frame.md now leads with the native SteamOS build (building
in a podman container on the Frame, running it, the log lines to expect);
OPENXR.md's backend table records the Linux Vulkan backend and why the Lepton
flavour cannot present.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019HBRGKTE1GnN2ah8gcZKr3
docs/steam-frame.md covers the steamFrame flavour: the CPU target and
why it excludes SVE, the Lepton entry activity and manifest, the Frame
controller map, the refresh rate and eye-tracked foveation, building and
installing, the device checklist (what to collect from the headset, the
log lines a first session should show, the open questions), and what a
native SteamOS build would need. OPENXR.md documents refresh_rate and
eye_tracked_foveation and the Frame controller profile; the Quest doc,
the Android README and the README point to it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019HBRGKTE1GnN2ah8gcZKr3
- New [vr] hand_tracking (default off, Quest only for now): the Quest launcher's Settings > VR and
the headset panel's VR tab, under hand steering. Two XR_EXT_hand_tracking trackers are located
every XR frame: with the controllers held the Quest builds the joints from their touch sensors
(XR_EXT_hand_tracking_data_source's controller source), once they are put down from its
cameras. The trackers exist only while the option and hand steering are on and also serve the
runtime hand mesh; the extensions (plus XR_FB_hand_tracking_aim) are asked for when either is
on at launch.
- Aurora skins the runtime mesh with the joints themselves (tracked pose times inverse bind pose,
no curl, no grip); runtimes with joints but no mesh get a skeleton; non-finite joints put only
that hand back on its grip curl. AuroraCockpitHand carries the 26 seated-frame joints and radii.
- The manifest declares horizonos.permission.HAND_TRACKING (and the deprecated
com.oculus.permission.HAND_TRACKING), both normal permissions with no prompt on a Quest 3, and
oculus.software.handtracking as optional; without it Horizon OS keeps the app controllers-only.
Bare hands then drive khr/simple_controller, so on Android a hand whose squeeze action is
inactive and select active is treated as bare: with the option off it presses nothing but the
menu gesture, is not drawn and feeds no Wii Remote motion.
- Interaction-profile changes and tracker sources are logged. The pure rules (grasp from finger
flexion, bare latch, pinch gate, bare-hand buttons, flick) live in the OpenXR-free
vr/openxr_hand_tracking.h with mkw_vr_hand_tracking_tests; the driving and flick parts are
wired in the next commits. Docs: OPENXR.md, docs/quest-port.md, README.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
First person already seats you in the cockpit, so hand steering belongs with it:
the stick keeps steering until a grip actually takes hold of the wheel, and
nothing else changes until it does. "yaw_pitch" becomes the default anchor for
the same reason - from the driver's seat the vehicle's own climb reads as the
ground rising, where a level horizon reads as the kart sinking away.
Both defaults move together in runtime_config.h, the fresh-config template, the
F10 menu's reset, and both launchers, which mirror the runtime's constants. The
menu's reset also puts the rotation combo back on the default rather than on
"yaw", and now covers hand steering with the other cockpit keys.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ported from heurazy's mario-kart-wii-VR-port. F10 > Controllers > USB
wheel and pedals (also in the headset panel) picks and calibrates the
steering axis and both pedals by moving them, and assigns buttons by
pressing them, over raw SDL joysticks: no per-model table or gamepad
mapping, and separate pedals, reversed axes and combined pedal axes all
calibrate the same way. Settings live in PhysicalWheel.toml beside
Config.toml; heurazy's five-button files load unchanged.
The wheel is player 1's GameCube controller. In a race it owns port 0
(steering on the stick, the accelerator on A, the brake pedal braking then
reversing over A and drift, the paddles on R and L), keeping only the
other source's pause and item aim. In menus it adds only deliberate
presses. It arms once every pedal and button is released, stays neutral
in a race while its setup is incomplete, and nothing is opened until it
is enabled. Optional light rumble follows the game's own, capped at 15 %.
Added here: its confirm, a new back button and the steering device's
first hat (D-pad) work the menus, since our VR controllers default to a
Wii Remote and the wheel needs to navigate on its own. Devices SDL
classifies as wheels are marked in the list.
In the VR cockpit the wheel follows the hardware steering and hand
steering steps aside while it drives. README documents setup and
Logitech notes (G HUB, the G29's PS3 switch, shifter gears as buttons);
not yet tried on a physical wheel.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
F10 > VR (and the headset panel) gains a Seat choice (cockpit or custom,
with the cockpit scale or the existing custom sliders), "Turn the steering
wheel", "Use the vehicle's own wheel", "Hand steering (by heurazy)" and its
tuning, plus a line saying which wheel the cockpit found and how many
draws took the animated copy. "Reset first-person defaults" covers the
seat and wheel keys; hand steering keeps its own choice.
OPENXR.md documents the seats and a new "Steering wheel and hand
steering" section, fixes the stale first-person defaults in the sample
configuration, and lists the headset validation still owed. README and
THIRD-PARTY-NOTICES credit heurazy's mario-kart-wii-VR-port (GPL-3.0) and
the references it credits.
Brings in the keyboard/mouse rebinding overhaul (#162), the Kamek
skip-return hook fixes (#182, #218), the exit button and controller LED
fix (#221), the autohide-cursor and mute hotkey fix (#211), the Linux
--sysroot plumbing (#224) and the switch to the theofficialgman
dawn-build fork (#215).
Conflicts resolved to keep the VR integration intact:
- settings_overlay.cpp/.h: kept both new declarations. The controller
rebinding UI takes upstream's click-to-rebind widgets wholesale - our
only edit there was wrapping the combo width in Scaled(), and
upstream's bindingWidth is already font-relative, so the headset
panel still scales. Kept our DrawResolutionMenu() extraction (the VR
panel reuses it) while adopting upstream's DrawExitPrompt() and its
new DrawTopBar() prologue; kept our Diagnostics menu alongside
upstream's exit-button width math. HandleEvents merges both keyboard
paths, with the VR recenter hotkey now guarded by !g_rebind.active so
it cannot fire while a binding is being captured.
- AuroraDawnProvider.cmake: dropped our now-dead Android hash block.
Upstream restructured the pins into an if/elseif chain that already
covers android/aarch64, with the digest for the new dawn-build fork;
our leftover block was unreachable and carried the old encounter
digest.
- Version plumbing (Build-Installer.ps1, Setup.Windows Program.cs and
csproj): kept this fork's own line, which is 0.2.39 and centralised in
Launcher/Directory.Build.props, rather than regressing to upstream's
hardcoded 0.2.32.
Verified: translator 654/654; runtime ctest 14/14 including every VR
test; WiiCompiled and RetroRewind link; aurora gx_fifo_tests 262/263,
the one failure being the TevRegisterLiveness case already documented as
pre-existing on this branch.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Brings in patchzyy/Wiicompiled main: os_sleep parked-thread fix (#195),
HTTPS Retro WFC payload (#198), macOS build guide (#177), and the
reverse-Z depth fix (#134).
Conflicts were in aurora-main/lib/gfx/common.cpp and lib/gx/shader.cpp,
both from #134, which lands squarely on the VR stereo replay path.
#134 makes UseReversedZ genuinely reversed: the near/far correction now
applies exactly once, inside effective_projection(), instead of being
applied there AND per-vertex in the shader (the double application had
been cancelling out, so "reversed" Z silently behaved like forward Z).
Three pieces of the VR path were built against that old behaviour and
would have broken silently, so they are adapted here:
- shader.cpp exact-screen-depth parked the virtual screen at -0.5*w
specifically so the shader's following negation would land it at
+0.5*w. With that negation gone it now writes +0.5*w directly; keeping
the minus sign would park the screen at NDC -0.5, outside the clip
volume, discarding every 2D/HUD draw.
- stereo_replay.hpp backend_ndc_depth_row re-applied the correction to
the projection it was handed. That projection is effective_projection()
output, which now already carries it, so the function is a pass-through
of the Z row and no longer depends on the reversed-Z setting; the dead
bool parameter is dropped. Re-applying it would invert the virtual
screen's depth ordering, so 2D layers meant to sit on top would lose
the depth test to the ones behind them.
- shader_info.cpp stages the host depth window for that exact-depth path.
It now uses the same reversed-Z remap as upstream's new SetViewport
code, since frag_depth is written directly and has to reproduce the
window the fixed viewport transform would have applied. Restricted
depth windows (how the game forces an element in front of everything)
are exactly the 2D draws the virtual screen carries.
The SetViewport resolution keeps upstream's remap but retains the
ordering/clamp guard our version had: for any ordered guest range the
result is identical to upstream, and it avoids handing WebGPU
minDepth > maxDepth for the swapped pair MKW is known to emit. The VR eye
replay reuses these recorded values, so the guard covers that path too.
Test updates:
- stereo_replay_test now asserts the composed Z row against the staged
projection's own Z row rather than against the helper's output, so it
actually catches a re-introduced double correction (verified: it fails
when the old negation is put back; the previous self-consistent form
passed).
- gx_fifo_test's clearDepthValue expectation followed #134's deliberate
clear_depth_value() inversion, expressed through UseReversedZ rather
than hardcoded. Upstream changed the behaviour without updating this
test, so it fails on upstream/main as-is.
Verified: aurora suite 247 passed with the same 2 failures that already
fail on the pre-merge branch (IndexedPaletteHistoryKeepsAbsoluteVertexSlots,
PacksOneUniformWhenBothHalvesNeedInitialValue - both pre-existing, unrelated
to depth); shader.cpp and common.cpp compile clean; translator suite 577
passed. Not yet validated on-device in VR.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Brings in 25 upstream commits: Dolphin-compatible input expressions and
GCPadNew.ini import, NAND setting.txt console identity, empty-MKW-save
handling, rumble toggle, LLVM 22, and CI caching.
The only conflict was runtime/CMakeLists.txt, where both sides appended
test targets after mkw_platform_paths_tests. Both blocks are kept: the VR
first-person test alongside upstream's NAND save/settings, SC serial, and
input expression tests.
runtime_config.h and settings_overlay.cpp auto-merged; the VR settings
menu, recenter hotkey, and stereo/first-person init calls are intact
alongside upstream's InputBindings wiring.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Add Dolphin-compatible input expressions and GCPadNew.ini import
Rebased onto current main; addresses both CodeRabbit reviews on #89.
- Expression engine matching Dolphin's semantics: doubles rather than
booleans, 0.5 press threshold, & as min, | as max, and the functions if,
min, max, clamp, abs, sqrt, pow, sin, cos, tan, deadzone, timer, toggle,
hold, tap, pulse and smooth. Timing uses a steady clock in seconds, as
Dolphin does, so a copied expression behaves identically.
- Expressions bind to the GameCube buttons and triggers, combined with the
existing button mapping rather than replacing it, and are skipped while
the settings overlay holds input.
- Import reads [GCPadN] from the Dolphin config directory or from
GCPadNew.ini beside the executable. Stick axes are not expression driven
and keep their normal mapping.
- Fixes#74: a digital button bound to L or R now reports a fully pulled
analog trigger, plus a PlayStation preset and a vibration toggle.
Review fixes: config paths round-trip through RuntimeConfigFile::PathToUtf8
and PathFromUtf8 so non-ASCII paths open correctly on Windows, and the
duplicated exists branch is gone; the tap count is clamped before the
unsigned conversion; the expression editor uses resizable storage via
ImGuiInputTextFlags_CallbackResize so a long expression cannot be saved
truncated; clamp bounds are ordered before std::clamp; <cstdlib> is included
for std::strtod; non-finite values are rejected at the evaluator boundary as
well as at the deadzone and timer divisions; and InputBindings::Reload() runs
from InitializeRuntimeSettings rather than the vibration handler.
runtime/tests/test_expr.cpp covers operator precedence, each stateful
function and every case raised in review.
Third review round: smooth() guards NaN as well as infinity so a zero rate
cannot latch a non-finite value in node state; division evaluates both operands
so stateful functions in the left subtree still update when the divisor is zero;
the expression editor clears stale errors when the port changes; and
runtime/tests/test_expr.cpp is registered with CTest as mkw_input_expr_tests,
following the existing test targets.
* Update runtime/src/input_expr.cpp
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update runtime/src/input_expr.cpp
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update runtime/src/input_expr.cpp
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
---------
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Bluetooth Wii Remote support: the game reads a real Wii Remote through KPAD
Enable SDL3's HIDAPI Wii driver and hand a paired Wii Remote (bare or with
Nunchuk) to the game as a real Wii Remote: WPADProbe reports CORE/FREESTYLE
and KPADRead fills KPADStatus[0] from SDL every frame (buttons, accelerometer
in KPAD's g frame, Nunchuk stick and accelerometer), while the GameCube pad
view of that port reports no controller. The game's own motion code then
handles wheelies, tricks and Wii Wheel steering. Classic Controllers and
Wii U Pro Controllers keep going through the GameCube pad path with a default
button table picked by name.
SDL's Wii driver drops a remote on a failed Bluetooth read or when the
Nunchuk is plugged or unplugged and never re-adds it, so the runtime keeps
rescanning (Dolphin style) while no Wii controller is present by toggling the
driver hint off and, a few frames later, on again; a dropped remote is back
within 1-2 s. Settings live in the F10 overlay under Wii Remotes (Bluetooth)
and in Config.toml (wii_remotes, wii_continuous_scan).
* Fix Wii U Pro / Classic Controller ZL and ZR not registering
SDL's Wii driver reports ZL/ZR as the LEFT_TRIGGER/RIGHT_TRIGGER analog
axes, never as digital shoulder buttons. Binding them to
LEFT_SHOULDER/RIGHT_SHOULDER meant they never fired and also disabled
aurora's own analog-trigger fallback (a button table entry for
PAD_TRIGGER_L/R marks the trigger as "handled", even when the bound
digital button never actually presses). Leaving them unbound lets the
default axis mapping drive them like every other analog-trigger pad.
Reported by an end-to-end tester connecting a real Classic Controller to
a Wii Remote.
* Wii Remotes menu: live raw D-pad/ZL/ZR readout for Classic Controller / Wii U Pro
Diagnostic aid for a reported issue where the Classic Controller's D-pad
does not do anything in-game (no wheelies). Shows what SDL itself sees so
a driver-level problem (nothing lights up) can be told apart from a
mapping problem (it lights up but the game does not react).
* Fix Classic Controller D-pad input
* Address CodeRabbit review on PR #73
- PADRead: hide KPAD-served ports even while input is blocked so the port
error state does not flip when the overlay opens/closes.
- WPADProbe: run the Wii Remote rescan state machine before probing so a
reconnect probe before the next PADRead can see the remote.
- EnsureSensors: only cache the gamepad id once every accelerometer enabled,
so a failed activation is retried.
- ConfigureSdlHints: reset the in-flight rescan bookkeeping.
- Settings overlay: disable "Rescan now" while Wii Remotes are turned off.
* Bluetooth Wii Remote: fix wheel steering, native Classic Controller, extension hot-swap
Accelerometer
- The SDL -> KPAD conversion negated the wrong axis: SDL's z is the remote's
+Y (towards the user), so KPAD acc is (-wiiX, -wiiZ, +wiiY). Fixes mirrored
Wii Wheel steering.
- Drop reports whose accelerometer bytes arrive zeroed (+-5.12 g on every axis,
a few times a minute over Bluetooth) and repeat the last good sample; they
read as a full-lock steer plus a 9 g shake.
- One-button zero-point calibration in the overlay (remote flat, buttons up),
stored in Config.toml as wii_accel_offset_x/y/z. SDL's read of the remote's
factory calibration times out over Bluetooth and falls back to a nominal
zero point, which left a per-axis bias of up to ~0.3 g on the tested remote.
- Live accelerometer readout and an optional per-frame CSV trace
(wii_accel_trace = true) for debugging.
Classic Controller through KPAD/WPAD
- WPADProbe reports WPAD_DEV_CLASSIC; KPADRead fills ex_status.cl and
KPADGetUnifiedWpadStatus the raw WPADCLStatus (WPAD_CL_BUTTON_* bits, sticks
in the SDK's signed -512..511 range, triggers), so the game shows the Classic
layout and icons and no button mapping is involved. Ports served through KPAD
are hidden from PADRead; only the Wii U Pro Controller stays a GameCube pad.
Extension hot-swap
- SDL's Wii driver destroys the joystick on an extension change but keeps the
HID handle open, and HIDAPI never re-creates a joystick for such a device.
Patch the vendored SDL at configure time (AuroraSDL3Patches.cmake, wired into
AuroraSDL3Provider.cmake for both the downloaded tarball and a pre-provided
FETCHCONTENT_SOURCE_DIR_SDL) so the joystick is rebuilt in place with the new
extension type, without touching the Bluetooth handle.
- Keep a vanished remote's channel alive with neutral input for up to 3 s while
SDL re-creates the joystick, so the game never sees a disconnection. The
driver-hint rescan stays as a fallback for real drops, starting 3 s after
the loss, and also runs from the overlay's per-frame Draw. Log rescans.
Mappings / overlay
- Do not apply the shared positional [controller] bindings to Wii pads: that
override is what made a Classic Controller's A/B and X/Y look swapped.
- Raw D-pad fallback also for the Wii U Pro Controller; overlay readouts read
joystick buttons directly (SDL's generated HIDAPI mapping expects a hat).
- Overlay: Classic Controller readout, accelerometer readout and calibration.
- README: Bluetooth Wii Remote section and known limitations.
* Review pass on the Wii Remote input path
- EffectiveKind: stop bridging an extension swap once a different controller
has taken the port, and note that everything touching the scanner state runs
on the guest thread.
- KPADGetUnifiedWpadStatus: fill every requested entry (the SDK returns `count`
recent samples), capped at KPAD's 16 read buffers.
- IsKpadKind gets internal linkage; the calibration accessors get their
comments; clarify why Draw() also runs Poll().
* Drop the dead Classic-Controller-as-GameCube-pad matching
A Wii Remote with a Classic Controller is served through KPAD and its port is
hidden from PADRead, so the name matches that once gave it a GameCube button
table and the raw D-pad fallback could never take effect any more. Both now
match only the Wii U Pro Controller, and the default table is renamed
accordingly (g_defaultButtonsWiiUPro).
---------
Co-authored-by: LOL <andresguerra2k26@gmail.com>
Co-authored-by: Nick <89667145+Nick1232345@users.noreply.github.com>