* Fix garbage frame flash on cinematic camera cuts
Frame interpolation blended matrices across instant camera teleports in
attract/demo and post-race cameras, flashing 1-2 frames of sheared
geometry. Complete the existing camera-epoch mechanism: flag a cut in
func_80019890 when the camera moves >100 units, and have the
interpolator snap that frame to the new view instead of blending.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Retrigger CI (transient 502 downloading libogg from gitlab.xiph.org)
* Name the cinematic shot dispatcher
Review feedback on #720: func_80019890 -> camera_start_cinematic_shot.
It starts whichever shot D_80164680 has selected for a camera, dispatching
to the per-shot setup that teleports the camera to the shot's opening
position, which is why the cut detection lives there.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Apply fix to freecam
Added FrameInterpolation_DontInterpolateCamera calls to improve camera behavior when changing target players.
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: MegaMech <MegaMech@users.noreply.github.com>
The gradient quad's projection path does not preserve the outward
rounding of the Rect edge getters, which can leave the last window
column unpainted at some aspect ratios (visible as a black strip at the
screen edge that only sky sprites drew into). Overshoot the quad a few
virtual pixels past both edges; the excess clips at the window.
Co-authored-by: MegaMech <MegaMech@users.noreply.github.com>
Pressing start on the splash screen in the last moments before the demo
timeout could play the enter chime and then drop into the demo reel with
no music: the attract timer (gMenuTimingCounter >= 0x12D) fired while the
press-start fade was in flight and overwrote gMenuFadeType to the demo
value, so the fade completed as a demo entry. Vanilla bug; roughly a
0.7-second window every attract cycle.
Only arm the demo when no fade is in flight. A natural timeout (idle, no
fade running) behaves exactly as before.
Play-verified: start pressed repeatedly around the timeout boundary always
lands in the main menu with music; the demo reel still plays when idle.
Normal quits ran the full static-destructor chain, where destruction order is
unspecified and something logs through spdlog after its statics are destroyed,
intermittently segfaulting on exit (same class as upstream issue #689). All
user-visible state (config, saves) is already persisted by GameEngine::Destroy,
so end the process with _Exit like the extraction error paths already do.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: MegaMech <MegaMech@users.noreply.github.com>
* Make the reset button reliable from any screen
Pressing reset repeatedly near app start could do nothing, fade the music
with no reset, or bounce the press-start screen back to itself. Three
defects in the old handler:
- It ran from the ImGui widget, racing the menu state machine; a press
landing mid-fade was re-advanced by the in-flight transition (the
press-start loop).
- It always wrote gGamestateNext = MAIN_MENU_FROM_QUIT; once the game was
already in that state a repeat write is swallowed by the != guard in
main.c, so nothing happened.
- CM_ResetAudio ran unconditionally, so the music faded even when the
reset was swallowed.
The widget now only sets an atomic request flag; ApplyPendingReset (top of
push_frame, on the game loop) performs the reset. It alternates between
the two identical FROM_QUIT gamestates so every press trips the gamestate
switch, and re-enters the menus through the intro's own transition
protocol (FADE_MODE_LOGO -> setup_menus rebuild + fresh fade-in), which
replaces any in-flight transition. Audio only fades when a reset actually
executes. The dead gSkipIntro switch in the old handler (an unconditional
override below it always won) is gone; behavior is unchanged: reset lands
on the logo intro, or the start menu in debug mode.
Play-verified: hammering reset during the splash screens restarts the
logo every press; reset mid-fade after press-start no longer loops back;
resets from the main menu and mid-race work as before.
* Honor gSkipIntro when picking the post-reset screen
Review feedback on #719: restore the gSkipIntro switch from the old
handler instead of hard-coding the logo intro, keeping the debug-mode
override on top (no else), matching the boot-time logic in main().
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: MegaMech <MegaMech@users.noreply.github.com>
* some start of refactor
* Update SetFlags.cmake
* Update SetCmakeVar.cmake
* Update SetFlags.cmake
* Fix error int-convertion
* more refactor
* clean up include and source file
* fix link of lib
* fix a warning
* fix include in src/actors
* fix include in src/debug
* fix include in src/ending
* fix include in src/engine/actors
* fix include in src/engine/cameras
* fix include in src/engine/editor
* fix include in src/engine/objects
* fix include in src/engine/tracks
* fix include in src/port/ui
* fix include in src/racing
* fix include in src/engine/vehicles
* fix include in subfolder of src/engine
* fix include in src/engine
* fix include in src/enhancements
* fix include in src
* fix switch
* invert common and findlib
* Update SetFlags.cmake
* clean up some workflow
* some splification
* Update build.sh
* Update Game.h
* add header back
* Delete test_check.cmake
* continue
* Update common.cmake
The PR-validation build-docker-x86 job registers a QEMU binfmt handler
for linux/386 before building. i386 containers run natively on the
amd64 runners, but the explicit registration routes every binary in the
container through the qemu-i386 emulator, turning a ~15 minute build
into ~170 minutes. main.yml's build-linux-x86-docker job is identical
except it never installs QEMU, and it completes in 13-18 minutes.
Dropping the setup-qemu step makes the PR job match main.yml; the
--platform linux/386 image and build steps are unchanged.
* Fix widescreen letterbox/divider left-edge clipping on ARM64
The race-intro letterbox bars (draw_box_fill_wide) and the splitscreen
divider lines fed the float OTRGetDimensionFromLeftEdge result into
gDPFillWideRectangle, whose _SHIFTL packing casts float->unsigned.
Converting a negative float to unsigned is UB: x86 wraps (and the
wide-rect handler's sign extension recovers the value, so the bug is
invisible there), but ARM64 fcvtzu saturates negatives to zero — so on
Apple Silicon the fills started at the 4:3 left edge instead of the
true left edge, leaving a strip of sky visible left of the intro bars
in widescreen. Use the integer OTRGetRectDimensionFrom*Edge getters,
matching the sibling draw_box_wide helpers.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Shorten the fix comment
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* macOS: sharp ImGui menu text on Retina at every menu scale
On a HiDPI display the ImGui overlay renders into a 2x framebuffer, but
the glyph atlas is rasterized at the logical point size and stretched up
by DisplayFramebufferScale, so all menu text looks fuzzy.
Set ImFontConfig::RasterizerDensity on the game fonts and the merged
FontAwesome icons: glyphs rasterize at higher resolution without
changing logical size or layout. Baked at retinaScale (2.0) times the
Menu Scale slider's maximum (2.0) so the runtime FontGlobalScale only
ever downsamples a high-res atlas instead of stretching a low-res one,
keeping text crisp at every Menu Scale setting. Standard-DPI displays
just get a supersampled atlas (identical layout, slightly sharper).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Shorten the RasterizerDensity comment
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* Fix macOS arm64 build: fmt consteval error in the TorchExternal sub-build
Torch's pinned spdlog bundles an fmt whose consteval format-string
checking fails to compile under newer AppleClang (Xcode 16+), breaking
the build-macos-arm64 CI job (the intel runner's older Xcode doesn't hit
it):
error: call to consteval function 'fmt::basic_format_string<...>' is
not a constant expression
Define FMT_CONSTEVAL as empty inside the Torch sub-build, falling back to
fmt's pre-C++20 constexpr checking. Injected via CMAKE_PROJECT_INCLUDE
because Torch's CMakeLists overwrites CMAKE_CXX_FLAGS, so plain flag
injection through CMAKE_ARGS is discarded. Scoped to AppleClang; no other
platform or compiler is affected, and the Torch pin is unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Also neutralize FMT_CONSTEVAL for the game build (vcpkg spdlog/fmt)
With the TorchExternal fix in place, CI reaches the game build and hits
the same consteval error again, this time from the vcpkg-provided
spdlog/fmt headers (SPDLOG_FMT_EXTERNAL) under the runner's Xcode 26.5.
Apply the same AppleClang-scoped FMT_CONSTEVAL= define at the project
level so both layers compile.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Pin vcpkg fmt to 10.2.1 (+ spdlog 1.14.1): fmt 11.0.2 can't compile on new AppleClang
The baseline's fmt 11.0.2 both fails to compile under newer AppleClang
(consteval format-string checking) and removed the #ifndef guard around
FMT_CONSTEVAL, so the AppleClang-scoped define from the previous commit
lands on the compile line but gets clobbered by fmt's own definition
(FMT_USE_CONSTEVAL is likewise unguarded in that version). No newer fmt
exists in the pinned baseline.
Override fmt to 10.2.1, which keeps the #ifndef guard, making the
existing define effective; spdlog moves to the matching 1.14.1 (1.15.x
requires fmt >= 11 headers).
Verified locally against the exact CI setup (vcpkg at baseline
2e58bb35ff, vcpkg toolchain file, Ninja): the previous failure reproduces
without this change and the full game builds cleanly with it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Add TODO markers for removing the fmt consteval workarounds
Requested in PR #712 review: mark all three workaround sites (project-level
define, Torch sub-build include, vcpkg fmt/spdlog pins) so they can be found
and removed together once the Torch pin is bumped past its spdlog/fmt update.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: siliconports <aguthmann10@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
InitModsSystem() runs before the game world is set up. Its bail-out paths (no
O2R + user declines generation, missing mods.toml, cyclic/outdated mod deps,
and GenAssetFile's no-ROM / unsupported-ROM cases) call exit(), which runs the
global `static World sWorldInstance` destructor -> World::CleanWorld() ->
dereferences Sky::Instance and other singletons that are still null this early,
segfaulting. The most visible case: declining the first-run "Generate one now?"
prompt pops a crash report instead of quitting cleanly.
Use _Exit() on these pre-initialization bail-outs so no static destructors run.
Co-authored-by: quarrel07 <paeans-toggle-2e@icloud.com>
Co-authored-by: coco875 <59367621+coco875@users.noreply.github.com>
The bundle version strings were left at 0.1.0 while the project is at 1.0.0
(project(Spaghettify VERSION 1.0.0)), so the macOS .app and cpack bundle report
the wrong version in Finder/Get Info. Match them to the project version.
Co-authored-by: quarrel07 <paeans-toggle-2e@icloud.com>
* Remove duplicate Switch::Init(PostInit) call.
It was called multiple times, causing multiple applet hooks (that all point to the same callback address) to be registered. For some reason, the OS started spamming us with FocusUpdate events via that hook because of that.
* Hide fullscreen and app data directory button on Switch
* merge upstream commit to fix some bug
* fix merge
* add a local user for the merge
* Update main.yml
* revert main.yml
* fix windows CI
* fix switch build
* fix windows and try a fix for switch
* fix windows build
* Force type correctness when calculating collision hashes
* Fix more incorrect hash calculations.
* fix an error
---------
Co-authored-by: coco875 <59367621+coco875@users.noreply.github.com>
* Enable MK64 build option for torch
* Fix HMAS type error (present on arm64)
* Align memory pool and fix empty macro
* Experimental: Add 4096 memory alignment
* Add alignment for ALIGNED8 macro
* Use memset over deprecated bzero
* Ensure OPENGLES flag can be used in CMakeLists.txt
* Diagnostic: align ship2_window_i8 to rule out odd-alignment crash
---------
Co-authored-by: MegaMech <MegaMech@users.noreply.github.com>
macOS uses COREAUDIO as the default audio backend, but the
combobox display map in MenuTypes.h only contained SDL and
WASAPI. This causes an unordered_map::at crash on first
frame draw when the Audio API dropdown tries to render.
Fixes the menu crash portion of #681.
Kenix3/libultraship#972 changed the OpenGL backend to load a single
combined default.shader.glsl instead of separate .fs and .vs files.
The assets were never updated to match, breaking the OpenGL renderer.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>