- Updated stereo_frame_worker_smoke.cpp to allow dynamic headset rates and prediction lead time.
- Improved logging to include motion diagnostics and adjusted frame submission logic based on headset frequency.
- Enhanced stereo_interpolation_test.cpp with additional tests for camera motion separation and playback cadence.
- Introduced MkwVRReadSceneView function to read the camera view matrix for improved scene rendering.
- Modified VR first-person logic to support scene view reading and validation.
- Added scene_camera.hpp to encapsulate camera motion handling and inverse view calculations.
- Ensured that the VR integration layer correctly logs motion diagnostics and handles scene playback accurately.
- Introduced `vrCockpitItemThrow` configuration option to enable throwing items in VR.
- Implemented `ThrowDetector` and `ThrowSequence` classes to manage item throwing mechanics based on hand movements.
- Updated `OpenXRInput` to handle item throwing based on hand swings, integrating with existing VR input systems.
- Enhanced settings overlay to allow users to toggle item throwing functionality.
- Added tests for item throwing mechanics, ensuring correct behavior for various hand movements and conditions.
- Implemented DVDReadVrAsset function to read mapped disc paths for VR assets.
- Created HeldItem structure and ReadHeldItem function for managing held items in the game.
- Developed unit tests for ReadHeldItem to ensure correct functionality and edge case handling.
- Added cockpit item data tests to validate model indexing and parsing of archives.
- Introduced a new configuration option for object culling in VR, allowing the game to hide objects outside the camera's view.
- Implemented native replacements for the Mario Kart functions responsible for scene culling, ensuring accurate behavior in VR.
- Added a new header file `mkw_vr_culling.h` to define the culling logic and structures.
- Created `mkw_vr_culling.cpp` to implement the culling logic, including frustum intersection checks and screen info updates.
- Updated runtime configuration to include the new object culling option, with appropriate getters and setters.
- Enhanced the settings overlay to allow users to toggle object culling in VR.
- Added tests in `vr_culling_tests.cpp` to validate the frustum intersection logic and ensure compliance with original behavior.
- Updated CMake files to include new source files and tests.
- Added support for hiding model arrays in the rendering pipeline to optimize performance during VR gameplay.
- Introduced new functions in `gx_model_visibility` to manage hidden model arrays and their visibility based on game state.
- Enhanced cockpit recentering logic to ensure accurate seat measurements and eye positioning during gameplay.
- Updated `FirstPersonState` to track cockpit height and forward direction, improving VR experience.
- Added tests for Bullet Bill model visibility and cockpit height adjustments to ensure functionality and stability.
- Refactored existing code to accommodate new features and improve overall code organization.
Bump the backend to 0.2.44 and the Quest app to versionCode 5 / 0.5.0-quest,
the first release to ship Darthcircuit's Quest 1 build beside the modern one.
The headset flavours split the kit export into one task per variant, which
picks the CMake tree by the flavour's MKW_ANDROID_CPU.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds the modernQuest and quest1 headset flavours (Kryo CPU target, direct-VR
library entry on Quest 1), records the CPU target in the game kit and checks
it wherever a kit or game package is used, and gates the Quest 1 EFB-copy and
pipeline-scheduling workarounds on the monterey device.
Resolved docs/quest-port.md by keeping both sides: the foveated rendering
section and the Quest 1 renderer compatibility section, and both Build-Quest.ps1
command lines.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Added SetRenderScale method to both D3D12 and Vulkan backends to adjust the render scale dynamically.
- Updated eye size calculations to reflect the new render scale in both backends.
- Implemented ResizeWritablePair method to handle resizing of swapchains based on the requested eye sizes.
- Modified BeginFrame methods to ensure swapchains are resized appropriately before rendering.
- Enhanced error handling to maintain current eye sizes when the requested sizes cannot be allocated.
- Added tests to validate render scale functionality, ensuring correct behavior when scaling up and down, including handling of refused sizes.
- Started with the controllers connected, a race stayed on them: Horizon OS switches all input
between controllers and hands, and back to the controllers as soon as one lying on a table moves
(a Quest 3 log went touch_controller, simple_controller, touch_controller within seconds). An
app cannot disconnect the controllers.
- With tracked hands on, the input now resumes XR_META_simultaneous_hands_and_controllers (Meta's
multimodal), which overrides that switching: a controller not in a hand no longer owns it, so the
cameras track that hand at once, and a held controller keeps working. Paused again when the
option goes off; a refused resume is logged and not retried until the option is toggled.
- A hand is bare when its squeeze action is inactive and it either drives khr/simple_controller or
has camera-tracked joints, since a free hand under simultaneous tracking may get a profile our
actions are not bound in. Docs: OPENXR.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Now that holding the wheel engages the race controls, closing the other hand on the rim could
bring thumb and index together on the way and fire an item. A pinch uses an item only while the
hand's grasp is under 0.5; a relaxed hand reads about 0, a hand closed on a rim about 0.9.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- On a Quest 3 the race controls never engaged: grabbing the wheel gave no gas and a right pinch
stayed A. They waited for the game to switch the remote's pointer off, and MKW keeps it on in a
race (the log only ever said "the game's pointer is on").
- The race controls now apply while a bare hand holds the wheel: that holds the gas, and a free
hand's pinch (either hand) uses an item. With no bare hand on the wheel a right pinch stays A,
which is what the pause menu and the results need. The flick still works in the whole cockpit.
- The game-pointer publication (KPAD hook and bridge) is gone. The "tracked hands" source line is
logged at most once a second: camera-tracked hands drop in and out of view often.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A bare hand already feeds no Wii Remote motion (camera-tracked poses are too noisy to
differentiate twice). In a cockpit race, both hands on the wheel rising together or a free bare
hand rising fast now plays one shake on the remote's accelerometer: 150 ms, so the guest sees it
on at least three frames, one cycle up to +2 g and down to the -3.6 g limit, as Dolphin's
emulated shake does. A turn (one hand up, the other down) never flicks, nor does a lone hand on
the wheel; a rise must last three samples and cover 5 cm within 150 ms, tracking jumps reset it,
and flicks are 0.5 s apart. Wii Remote presentation only.
- debug.wiicompiled.inject <n>:flick plays the same shake, with the controllers or unattended, to
tune it apart from the gesture. Docs: OPENXR.md, docs/quest-port.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- With tracked hands on, a hand driving khr/simple_controller with camera-tracked joints is bare:
latched through wheel_tracking_grace (Meta drops the select action while a hand is lost),
cleared as soon as a controller's squeeze is back. Its palm joint stands in for the grip and a
grasp from the middle, ring and little fingers' flexion (0 below 1.2 rad, 1 from 3.0) for the
squeeze, so closing a hand on the rim takes hold under the wheel's own press and release. The
grasp never reaches the game's buttons.
- In a cockpit race a bare hand holding the wheel holds the gas (A / South) and a pinch from a free
bare hand uses an item (Z / L) once the hand has been off the wheel for 0.15 s. Only while the
game has the remote's pointer off: KPAD publishes the game's pointer switch for the VR remote,
so the pause menu and the results keep a right pinch as A. The pacing thread logs each change,
to confirm on the headset that MKW turns the pointer off while driving.
- A held bare hand keeps its last joints drawn through a short loss; bare hands get no haptics.
The headset panel's readout shows grasp, hold and pinch. Docs: OPENXR.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 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>
- The pacing thread aims each immersive window eye through the window itself (AimEyesThroughWindow):
it keeps its position but looks square-on at the window's plane through an off-axis frustum just
around it, so the eye image is the window, at the display's pixel density (about 680x380 per eye
at render_scale 0.8 instead of 1344x1408), with a two-pixel border the mask leaves transparent.
The frame's views carry that pose and field of view to the projection layer.
- vulkan_interop.cpp copies an eye smaller than its AHardwareBuffer into the buffer's corner, and
the Quest layer's imageRect is the rendered part of the swapchain image.
- These eyes are not foveated: their field of view follows the head, which would rebuild the
density map every frame.
- Quest only (kWindowShapedEyesSupported); the PC backends copy whole eyes and keep masking them.
debug.wiicompiled.window_eyes 0 renders them whole and masked again for A/B timing.
- Quest 3, paused Retro Rewind race, render_scale 1.0: Immersive window runs the GPU at level 1
(456 MHz, app GPU 11.0 ms, eyes 8.4 ms) where Immersive needs level 3 (599-640 MHz, 13.4 ms,
10.3 ms), about 42% fewer GPU cycles. No edge artifacts, image as sharp. Docs: OPENXR.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Introduced a new configuration option for immersive window mode in runtime_config.h.
- Updated the parsing and setting functions to handle the immersive window state.
- Modified the OpenXR backend to support rendering with the immersive window, blending the race view with the surrounding environment.
- Enhanced the settings overlay to allow users to select between immersive, immersive window, and flat screen race views.
- Implemented GPU rendering logic for the immersive window mask, ensuring correct visual output in various rendering paths.
- Added tests to validate the immersive window functionality and its interaction with existing race view settings.
- The Quest's GPU applies the fragment density per screen tile and samples textures at a coarser
level inside reduced-rate tiles, so fine animated detail such as Retro Rewind's swamp goo shows
square tile edges at the periphery.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Retro Rewind's SNES Ghost Valley 2 at render_scale 1.0, GPU-bound at about 40 FPS: merging the
eye passes lifts it from 38.9 to 41.5 FPS (app GPU 23.3 to 21.7 ms), and no foveation level
raises the frame rate further.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Luigi Circuit Grand Prix start on a Quest 3, same-session A/B through the debug properties:
one render pass per eye saves 12% of eye GPU time at render_scale 0.8 and 8% at 1.3.
- Foveation is neutral at 0.8 (eyes are geometry and full-resolution tile-store bound) and saves
8/14/22% at Low/Medium/High at 1.3, so it stays off by default.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Eyes render under a VK_EXT_fragment_density_map: full rate around each eye's forward direction,
2x2 then 4x4 pixel blocks towards the edges ([vr] foveation = off|low|medium|high, default off).
XR_FB_foveation cannot help here: the runtime's maps only shape passes drawing into its
swapchain, and the eyes reach it through a copy.
- aurora-main/patches/dawn/aurora_fdm.inc: Dawn enables the extension only on request and for
dynamic rendering, flags every render pipeline, and chains an immutable RG8 map into any pass
whose first color attachment is a view bound to one (ABI: include/aurora/dawn_fdm_abi.h).
- android/Build-QuestDawn.ps1 builds the pinned Dawn revision with those patches for arm64
(dawn-build CI flags, protobuf off) into a cached package; Build-Quest.ps1 links it
(-StockDawn opts out) and AuroraDawnProvider.cmake enables the ABI from its manifest.
- lib/gfx/foveation.hpp generates the maps (32 px per texel, densities 255/127/63); an eye is
foveated only when single_pass_eyes draws it in one render pass. Menus never are.
- Live level from the headset panel's VR tab and the launcher; the launch decides whether the
device has maps. debug.wiicompiled.foveation and debug.wiicompiled.fdm for A/B.
- Tests: Foveation cases in gx_fifo_tests, mkw_vr_config_tests. Docs: OPENXR.md, quest-port.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Added eye_pass_plan.hpp: an eye keeps drawing in the render pass it has open across the frame's
GX copies (only the mono render performs them), skips passes a later clear of the whole color and
depth erases, and splits only for a clear of color alone or depth alone.
- render_stereo_eye follows that plan; the cockpit fallback is drawn inside the last pass instead of
a render pass of its own that loaded the eye back.
- The stencil is now cleared where the eye actually starts, so a cockpit mask drawn in an erased pass
can no longer punch holes in the HUD.
- [vr] single_pass_eyes (default on, live from F10) and debug.wiicompiled.eye_passes 0/1 on the Quest
switch back to one render pass per recorded pass for A/B timing.
- Each new plan shape is logged once ("Eye replay plan: ...").
- Tests: EyePassPlan cases in gx_fifo_tests; stereo_multiplayer_smoke and stereo_frame_worker_smoke
pass on D3D12.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Added `ic_question_tip.xml` and `ic_success_tip.xml` vector drawables for UI icons.
- Created layout files for friend-related dialogs: `dialog_add_friend.xml` and `dialog_friend_code.xml`.
- Implemented `item_friend.xml` for displaying individual friend cards in the friends list.
- Developed `page_friends.xml` for the main friends page layout, including empty state handling.
- Added unit tests in `RksysFriendsTest.kt` to validate friend management logic and interactions.
- Introduced `SidebarStatusTest.kt` to ensure proper status reading and SVG path parsing.
- Added PlayerRow.kt to bind player data for leaderboard and rooms.
- Introduced PodiumCard.kt for podium animations and display of player rankings.
- Created drawable resources for podium backgrounds, badges, and particles.
- Developed layout files for leaderboard header and podium cards.
- Implemented LeaderboardTest to validate leaderboard functionality and player ranking logic.
- Created dialog_player_profile.xml for displaying player profiles with loading and error states.
- Added item_player.xml for individual player items in lists, showing Mii, name, friend code, and VR.
- Introduced item_room.xml for room items, displaying game mode, ID, and player count.
- Developed page_room_details.xml for detailed room information, including player actions.
- Implemented page_rooms.xml for the main rooms page layout, featuring search functionality and room listings.
- Added view_vr_history.xml for visualizing player's VR history over time.
- Created LiveRoomsTest.kt to validate room and player functionalities, including leaderboard integration and search capabilities.
- Introduced PlayerMii class to encapsulate Mii data and image.
- Added parseMiiData function to decode Mii data from JSON.
- Updated miiImage function to playerMii for better clarity and functionality.
- Enhanced RksysProfiles to include Mii ID and updated parsing logic.
- Modified SidebarProfileCard to accommodate new Mii handling.
- Redesigned layout for activity_launcher.xml to improve Mii display.
- Adjusted item_mii.xml and page_profiles.xml for better Mii image sizing.
- Updated strings.xml for clarity on Mii parts and bodies.
- Added tests for Mii database and rendering to ensure functionality.
- Created MiiBodies class to handle upper body rendering for Miis.
- Implemented MiiBodiesTest to validate body model parsing and rendering.
- Introduced new layout files for Mii items, Mii editor, and My Miis page.
- Implemented MiiData serialization and deserialization tests to ensure data integrity.
- Created MiiDatabase tests to validate database creation, modification, and error handling.
- Added MiiIds tests to verify ID generation and MAC address derivation.
- Developed MiiRenderer tests to confirm rendering functionality for Mii parts.
- Added vector drawable icons: ic_chart, ic_code, ic_copy, ic_star, ic_translation, ic_user_circle.
- Created layout file for the profiles page, including UI elements for displaying user profiles, history, and statistics.
- Implemented unit tests for Retro WFC functionality, ensuring correct parsing of history, online friend codes, badges, and Mii images.
- Developed tests for Rksys profiles, validating friend code generation, license parsing, and handling of ratings.
- Introduced new drawable resources for user and warning icons.
- Created layout files for mod browser items, loading indicators, and the main mod browser page.
- Implemented IDs for resource referencing in the layout.
- Added unit tests for GameBanana API interactions, ensuring proper parsing of mod data and error handling.
- Developed Rust module for handling mod archives, supporting extraction of 7z and RAR formats with error checking.
Bump the backend to 0.2.43 and the Quest app to versionCode 4 / 0.4.0-quest
for the release that brings heurazy's cockpit and hand steering, and the
flat-screen mode and camera switching Darthcircuit suggested.
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>
OpenXR's grip +X is normal to the palm but points away from it on the left hand
and into it on the right, which is exactly what makes both grips carry the same
orientation when the hands hold a wheel symmetrically. The fingers therefore run
along -Y on both hands, and it is the geometry across the palm that mirrors.
Building the right hand's fingers on +Y instead left them pointing at the player
while the real hand faced forward.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The rule and its cost are not obvious from the code: the substitution is per
draw, so the merge test is too, and getting that wrong is worth 6 ms of GPU time
a frame in a race.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The animated copy is registered for the vehicle's whole position array, and a
race frame has 228 primitives that bind it. Suppressing draw merging for all of
them turned the kart's display list back into hundreds of separate draw calls,
each recorded once and replayed in the mono pass and both eyes: on a Quest 3 the
app frame went from 15.7 ms to 21.7 ms with the GPU pinned at 97 %, which past
the 72 Hz deadline reads as 56 FPS against 42.
Merging is unsafe only between draws that resolved the array differently, since
the merged whole renders through the binding of the draw it folds into. So
resolve the replacement once per draw, before the merge test, and merge into a
draw that reached the same decision. Draws of an opponent sharing the asset
merge with each other again too, and with no set registered the test is exactly
what it was before the feature.
Measured at the same place on a Quest 3: 60 FPS against 42, the app frame back
to 13.9 ms, 564 draw calls a frame with 11808 primitives merged away.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The Android frame-rate line already says where the wall clock went; what it
could not say is how many draw commands the recorded frame holds, which is what
the mono pass and both eye replays each pay for. An overlay that stops draws
merging shows up here long before it shows up as a frame rate.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The Quest offers XR_FB_hand_tracking_mesh without the app declaring hand
tracking, so a Quest 3 draws the runtime's own hand mesh rather than the
procedural gloves, and its fingers bent backwards on grip: the mesh's
joints point -Z towards the fingertip and +Y out of the back of the hand,
so flexion is negative about the joint's own X, on both hands. Fix and
test by the repository owner; OPENXR.md said the Quest always drew the
gloves, which was wrong.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The kart's own wheel animates and the wheel can be grabbed and turned. The
driver's eye still went uncalibrated in that race, leaving the wheel about
13 cm above eye level.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
On a Quest 3 the gloves' fingers pointed up out of the fist and bent out
of the back of the hand as the grip closed: they were built along the
grip's -Z, which runs up the tube the curled fingers form towards the
thumb, and curled towards -Y, which is backwards on the right hand.
The fingers now run along Y, forwards out of the palm (+Y on the right
hand, -Y on the left, the frame being right-handed), and close towards
+X, the palm's outward normal, with the thumb on the -Z side of both
hands. A test pins the reach, the closing direction and that nothing
bends out of the back of the hand.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The Quest launcher's Settings > VR gains a Seat choice (cockpit or
custom, first_person_seat) and a Hand steering switch (hand_steering, off
by default like the runtime), which is only enabled in the first-person
cockpit because the wheel belongs to that seat. About credits heurazy for
the turning steering wheel and hand steering. The runtime side was already
shared with the Quest build.
OPENXR.md records what one Quest 3 race showed: the kart's own wheel
animated (228 draws a frame) with the race camera's view matching the
scene's exactly, but the driver's eye was never calibrated and the
fallback put the wheel centre about 13 cm above eye level. The Quest
declares no hand-tracking permission, so hands are the procedural gloves.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The panel was drawn into the eye images, so below a 1.00x OpenXR
resolution its 1440x1080 canvas was minified into a small eye region and
the text became hard to read. It is now submitted as a quad layer of its
own over the scene's projection or menu quad, which the compositor samples
directly at any render scale.
Each backend (D3D12, Windows Vulkan, Quest) makes the panel's swapchain
pair (plus two shared buffers on the Quest) the first time the panel
opens. While it is open, the frame hands Aurora one more stereo target
after the eyes, which the bridge fills with the panel texture or a
transparent image. The panel image follows the eyes' displayed/retained
pairing, so a cancelled frame never shows an unwritten panel. The quad
hangs where the pointer's hits are tested. Aurora leaves the panel out of
the eyes in layer mode, and a backend that cannot make the layer falls
back to drawing it into the eyes.
On the Quest, debug.wiicompiled.panel_layer 0 selects the old path at
run time. Measured there at a race start (render_scale 0.8), the layer
costs nothing while the panel is closed; while it is open, app GPU time is
10.5 ms against 9.7 ms drawn into the eyes, with unchanged frame rates.
The replay tests cover lazy creation, cancelled frames, closed and
unplaced panels, and render-first pacing on D3D12 and Windows Vulkan.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Clicking the right thumbstick flips first person exactly as the F10
checkbox does, and saves it the same way. It works on the VR controllers
in either presentation (with a short tick on the right controller) and on
any other gamepad while VR is running. It never reached the game: SDL's
stick click only lands in Aurora's extended buttons.
A click counts on release, and only if the left thumbstick stayed up and
the headset settings panel stayed closed throughout, so the two-thumbstick
panel chord in gamepad mode never toggles the camera. A gamepad whose
right stick click is bound to a GameCube control on its port, as a button
or in an input expression, keeps it for the game. The XR side only posts
a request; the toggle itself runs on the game thread with the checkbox.
[vr] first_person_toggle_click (default true) and a checkbox under the
camera toggle turn the click off. mkw_vr_camera_toggle_tests covers the
click rule.
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>
Found on a Quest 3 through Virtual Desktop (VirtualDesktopXR, Vulkan):
the race camera's view matched the scene camera exactly and the kart's
own wheel animated (228 draws a frame took the copy), but during the
race's opening pan no draw took it, the 30-frame fallback latched the VR
wheel for that vehicle, and it stayed until the scene changed.
The fallback now heals: copies keep being published, the VR wheel stands
in only while draws are not taking them, and the vehicle's own wheel
returns as soon as they are. Both switches are logged, a few per race.
With first_person_rotation "yaw_pitch" or "full" the wheel copy and the
hands' wheel geometry now ride in the view's own frame (the kart's
orientation around the seat) instead of the level seat, so the wheel no
longer tilts against the view on slopes.
Aurora logs, after about half a second, five seconds and a minute of
copies, how many draws bound a copied array (inside and outside its
window), how many matched, and the closest position matrix against the
expected one, so a mismatch says whether the array or the matrix differs.
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.
Every XR frame in the cockpit seat the pacing thread locates both grips in
the seated frame (the immersive base turned by the lean-back angle, the
frame the eye transforms place the vehicle in) and publishes a driving
snapshot. The wheel or handlebar shows the left stick's steering at the
configured full-lock angle, eased; the vehicle's own wheel reads that angle
on the guest thread.
With hand_steering on (off by default), squeezing a grip near the wheel or
handlebar takes hold of it (a short pulse on grab and release); one or two
hands turn it through heurazy's SteeringWheel, and while it is held the
wheel replaces the left stick's X axis in both the Wii Remote and gamepad
presentations, the stick's Y still aims items, and a holding grip no
longer presses C or a shoulder. The settings panel withholds it like any
other input.
The stereo packet carries the cockpit overlay: the hands, in the runtime's
hand mesh (XR_EXT_hand_tracking + XR_FB_hand_tracking_mesh, requested only
when hand steering is on at launch) or procedural gloves, and the separate
VR wheel or handlebar whenever the vehicle's own is not the one turning.
first_person_seat = "cockpit" (the new default) places the head at the
driver's own eyes, measured once from the character's head bone while the
kart drives straight and undamaged, kept behind the steering wheel, at a
life-size scale (cockpit_units_per_meter, grown with the character's
height and the player's size). "yaw" takes the kart's driving direction
from a level seat frame that follows the simulation's position and
direction, so damage spins and tricks do not turn the seat.
first_person_seat = "custom" keeps the previous offset placement.
At the race draw boundary the vehicle's steering wheel disc (karts) or
handle part (bikes, re-seated level while the bike banks) is decoded from
its MDL0, turned on a copy, and posted to the GX thread for Aurora to
substitute into the player's own draws; the copies are dropped after the
frame's draws. The anchor carries the wheel or handlebar geometry in the
seated frame and the frame's exact scale, which reaches the policy and
aurora_set_stereo_scene_anchor_scaled. If no draw takes the copies for 30
frames the vehicle falls back to the VR wheel, and the log says so.
The wheel copy is matched against RaceCamera::GetViewMtx with no dolly
offset, since the scene camera is only set once the draws run; the log
reports its distance from the scene camera once a second.
Nothing turns the wheel yet: the angle comes from the XR side's driving
snapshot, which the next change publishes.
Guest offsets ported from heurazy's mario-kart-wii-VR-port, each
re-checked against the generated leaf getters and the decompilation.
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.
A stereo packet can now carry an AuroraCockpit: tracked hands and, when the
vehicle's own wheel cannot be animated, a synthetic steering wheel or
handlebar, all in metres in the seated frame. Each eye draws it inside the
scene's pass just before the first virtual-screen draw, depth-tested with
the world's own depth mapping (captured from a full-view world draw), so
the kart and track occlude the hands and the 2D layer cannot hide them.
Hands use a runtime-provided hand mesh when one is supplied and a
procedural glove otherwise.
aurora_set_stereo_scene_anchor_scaled lets the sealed frame own its world
scale: each eye's head translation is rescaled from the packet's scale to
the frame's. A non-finite cockpit is dropped with one warning; the frame
still renders.
Ported from heurazy's mario-kart-wii-VR-port (GPL-3.0-or-later).
The VR first-person camera will animate the local vehicle's steering wheel
by handing Aurora a rotated copy of one of the vehicle's position arrays.
A draw picks up the copy only when it binds that exact array with the local
vehicle's position matrix (per-position ownership for indexed-matrix
draws), so opponents sharing the asset keep the original vertices. The copy
takes the same padded upload path as the original and never touches the
shared array cache.
Ported from heurazy's mario-kart-wii-VR-port (GPL-3.0-or-later).
Dawn's install produces only its own DLL, but this package replaces
dawn_prebuilt wholesale and LocalBuild.ps1 copies dxcompiler.dll and dxil.dll
out of it into the product. Dawn loads those at run time instead of importing
them, so a package without them builds and installs cleanly and then fails to
compile shaders on D3D12.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Windows PowerShell drops the inner double quotes when it builds a native
command line, so Python received filter=data as a bare name and the build
stopped at extraction with "Python 3.12+ required".
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bump the backend to 0.2.42 and the Quest app to versionCode 3 / 0.3.0-quest.
This release carries the Windows Vulkan OpenXR binding, so it ships the custom
Dawn DLL that exports the Aurora Vulkan ABI.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The native-registration scan only knew PPC_NATIVE_OVERRIDE, so every
GX_DEFERRED_OVERRIDE_VOID was missing from the index; the deferred form
registers `symbol` and posts the hand-written `symbol_gx`.
A Retro Rewind kit built from a translation without the Retro-WFC payload now
refuses to package instead of crashing on entering WFC, and on Android ImGui
keeps off SDL's cursor, which ART aborts on from a guest fiber's stack.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Introduced a new GX thread to handle the rendering pipeline, allowing the game thread to post commands without blocking.
- Added `gx_thread.h` and `gx_thread.cpp` to manage the command ring buffer and thread synchronization.
- Updated `vi.cpp` to utilize the GX thread for rendering tasks, improving frame pacing and responsiveness.
- Modified `main.cpp` to configure and start the GX thread, ensuring it integrates with the existing rendering workflow.
- Enhanced `openxr_integration.cpp` to register the GX thread with OpenXR for better performance in VR scenarios.
- Refactored `settings_overlay.cpp` to remove unnecessary waits for the frame worker, as the overlay now draws directly into the game thread's ImGui frame.
- Improved error handling and logging in the GX thread to capture exceptions during command execution.
Bump the backend to 0.2.41 and the Quest app to versionCode 2 / 0.2.0-quest.
They ship together because the app's game kit fingerprints runtime/include,
and a 0.2.40 installation's headers no longer match it, so WheelWizard's
Build for Quest needs the matching setup.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Created InstallReset.kt to handle the removal of game files, built games, and mod packs while preserving user data.
- Implemented unit tests for InstallReset to ensure correct functionality and file handling.
- Updated RetroRewindPackTest to include new test cases for update and deletion order.
- Enhanced Vulkan interop and OpenXR integration to support new thread scheduling hints for Android.
- Improved error handling and logging for GPU submission failures in Vulkan backend.
Bump the backend version for the release that adds the Meta Quest app and
merges upstream v0.2.32, and point the DISTRIBUTION.md verify example at the
tag that goes with it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>