From 1e65843326ba2bd42858ac66ef4c849745b68979 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Mon, 19 May 2025 03:20:23 -0300 Subject: [PATCH 01/28] fix performance issue for scrolling custom HD textures --- src/engine/fox_std_lib.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/engine/fox_std_lib.c b/src/engine/fox_std_lib.c index 47be8b2a..a8f8de36 100644 --- a/src/engine/fox_std_lib.c +++ b/src/engine/fox_std_lib.c @@ -42,6 +42,8 @@ void Lib_Texture_Scroll(u16* texture, s32 width, s32 height, u8 mode) { width = newWidth; height = newHeight; + scale = 1; // TODO: a higher scale causes performance issues for large textures ? + for(s32 i = 0; i < (s32) scale; i++){ switch (mode) { case 0: From ca1a5dd510e3ef570e69a25251015a3ad8ab66c7 Mon Sep 17 00:00:00 2001 From: tortugaveloz Date: Tue, 20 May 2025 22:58:35 +0200 Subject: [PATCH 02/28] Additional 5ch options (#196) * Added angle selector for surround channels, subwoofer threshold and rear music volume slider. * Change comment. * Integrate options in game. * Added reset button for positions. * Added option to show / hide menu for 5.1. * Added mfpu=neon option to aarch64. --------- Co-authored-by: Sonic Dreamcaster --- CMakeLists.txt | 2 + libultraship | 2 +- src/audio/audio_playback.c | 20 +++--- src/audio/audio_synthesis.c | 9 +-- src/audio/mixer.c | 6 +- src/audio/mixer.h | 7 +- src/port/ui/ImguiUI.cpp | 128 ++++++++++++++++++++++++++++++++++++ 7 files changed, 152 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 171e542b..35f8d01e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -574,6 +574,8 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang") else() if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") set(CPU_OPTION -msse2 -mfpmath=sse) + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64") + set(CPU_OPTION -mfpu=neon) endif() target_compile_options(${PROJECT_NAME} PRIVATE diff --git a/libultraship b/libultraship index a8cddd2f..dda07c8a 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit a8cddd2f8991c9d50783db4de855c98a392f4ac9 +Subproject commit dda07c8ac6033ff98d37a05bc28406440c7769e4 diff --git a/src/audio/audio_playback.c b/src/audio/audio_playback.c index be9dfbcd..976d9f81 100644 --- a/src/audio/audio_playback.c +++ b/src/audio/audio_playback.c @@ -144,17 +144,13 @@ void Audio_InitNoteSub(Note* note, NoteAttributes* noteAttr) { panVolumeCenter = 1.0f; } else if (stereo.s.is_sfx) { // SFX - float pan_angle = (float)(pan + 64) / 128 * 2 * M_PI; + float pan_angle = ((float) pan) / 128 * 2 * M_PI; // Speaker angles in radians - const float front_left = -0.5236; - const float front_right = 0.5236; - const float rear_left = -1.92; - const float rear_right = 1.92; - - // Normalize pan_angle to [0, 2π] - pan_angle = fmodf(pan_angle, 2 * M_PI); - if (pan_angle < 0) pan_angle += 2 * M_PI; + const float front_left = (CVarGetInteger("gPositionFrontLeft", 240) - 90) * (M_PI / 180.0f); + const float front_right = (CVarGetInteger("gPositionFrontRight", 300) - 90) * (M_PI / 180.0f); + const float rear_left = (CVarGetInteger("gPositionRearLeft", 160) - 90) * (M_PI / 180.0f); + const float rear_right = (CVarGetInteger("gPositionRearRight", 20) - 90) * (M_PI / 180.0f); // Calculate volumes using cosine panning law panVolumeLeft = fmaxf(0, cosf(pan_angle - front_left)); // Front Left @@ -164,8 +160,10 @@ void Audio_InitNoteSub(Note* note, NoteAttributes* noteAttr) { } else { // MUSIC panVolumeLeft = gStereoPanVolume[pan]; panVolumeRight = gStereoPanVolume[ARRAY_COUNT(gStereoPanVolume) - 1 - pan]; - panVolumeRearLeft = gStereoPanVolume[pan]; - panVolumeRearRight = gStereoPanVolume[ARRAY_COUNT(gStereoPanVolume) - 1 - pan]; + + f32 rearMusicVolume = CVarGetFloat("gVolumeRearMusic", 1.0f); + panVolumeRearLeft = gStereoPanVolume[pan] * rearMusicVolume; + panVolumeRearRight = gStereoPanVolume[ARRAY_COUNT(gStereoPanVolume) - 1 - pan] * rearMusicVolume; } } diff --git a/src/audio/audio_synthesis.c b/src/audio/audio_synthesis.c index 84d894c5..17917d53 100644 --- a/src/audio/audio_synthesis.c +++ b/src/audio/audio_synthesis.c @@ -1368,6 +1368,7 @@ Acmd* AudioSynth_ProcessEnvelope(Acmd* aList, NoteSubEu* noteSub, NoteSynthesisS synthState->curVolLfe = curVolLfe + (rampLfe * aiBufLenSmall); synthState->curVolRLeft = curVolRLeft + (rampRLeft * aiBufLenSmall); synthState->curVolRRight = curVolRRight + (rampRRight * aiBufLenSmall); + uint32_t cutoffFreqLfe = CVarGetInteger("gSubwooferThreshold", 80); if (noteSub->bitField0.usesHeadsetPanEffects) { int32_t num_audio_channels = 2; @@ -1378,24 +1379,24 @@ Acmd* AudioSynth_ProcessEnvelope(Acmd* aList, NoteSubEu* noteSub, NoteSynthesisS switch (delaySide) { case HAAS_EFFECT_DELAY_LEFT: aEnvMixer(aList++, dmemSrc, aiBufLen, ((sourceReverbVol & 0x80) >> 7), - noteSub->bitField0.stereoStrongRight, noteSub->bitField0.stereoStrongLeft, (DMEM_WET_LEFT_CH << 16) | DMEM_LEFT_CH, DMEM_HAAS_TEMP << 16, num_audio_channels); + noteSub->bitField0.stereoStrongRight, noteSub->bitField0.stereoStrongLeft, (DMEM_WET_LEFT_CH << 16) | DMEM_LEFT_CH, DMEM_HAAS_TEMP << 16, num_audio_channels, cutoffFreqLfe); break; case HAAS_EFFECT_DELAY_RIGHT: aEnvMixer(aList++, dmemSrc, aiBufLen, ((sourceReverbVol & 0x80) >> 7), - noteSub->bitField0.stereoStrongRight, noteSub->bitField0.stereoStrongLeft, (DMEM_WET_LEFT_CH << 16) | DMEM_LEFT_CH, DMEM_HAAS_TEMP, num_audio_channels); + noteSub->bitField0.stereoStrongRight, noteSub->bitField0.stereoStrongLeft, (DMEM_WET_LEFT_CH << 16) | DMEM_LEFT_CH, DMEM_HAAS_TEMP, num_audio_channels, cutoffFreqLfe); break; default: // HAAS_EFFECT_DELAY_NONE aEnvMixer(aList++, dmemSrc, aiBufLen, ((sourceReverbVol & 0x80) >> 7), - noteSub->bitField0.stereoStrongRight, noteSub->bitField0.stereoStrongLeft, (DMEM_WET_LEFT_CH << 16) | DMEM_LEFT_CH, 0, num_audio_channels); + noteSub->bitField0.stereoStrongRight, noteSub->bitField0.stereoStrongLeft, (DMEM_WET_LEFT_CH << 16) | DMEM_LEFT_CH, 0, num_audio_channels, cutoffFreqLfe); break; } } else { aEnvSetup1(aList++, (sourceReverbVol & 0x7F), rampReverb, rampLeft, rampRight, rampCenter, rampLfe, rampRLeft, rampRRight); aEnvSetup2(aList++, curVolLeft, curVolRight, curVolCenter, curVolLfe, curVolRLeft, curVolRRight); aEnvMixer(aList++, dmemSrc, aiBufLen, ((sourceReverbVol & 0x80) >> 7), - noteSub->bitField0.stereoStrongRight, noteSub->bitField0.stereoStrongLeft, (DMEM_WET_LEFT_CH << 16) | DMEM_LEFT_CH, 0, GetNumAudioChannels()); + noteSub->bitField0.stereoStrongRight, noteSub->bitField0.stereoStrongLeft, (DMEM_WET_LEFT_CH << 16) | DMEM_LEFT_CH, 0, GetNumAudioChannels(), cutoffFreqLfe); } return aList; diff --git a/src/audio/mixer.c b/src/audio/mixer.c index c2f9f3ea..d3c5a4d7 100644 --- a/src/audio/mixer.c +++ b/src/audio/mixer.c @@ -77,7 +77,6 @@ static __m128i m256i_clamp_to_m128i(m256i a) { #define BUF_S16(a) (int16_t*) BUF_U8(a) #define SAMPLE_RATE 32000 // Adjusted to match the actual sample rate of 32 kHz -#define CUTOFF_FREQ_LFE 80 // Cutoff frequency of 80 Hz static struct { uint16_t in; @@ -645,7 +644,8 @@ void aEnvSetup2Impl(uint16_t initial_vol_left, uint16_t initial_vol_right, int16 void aEnvMixerImpl(uint16_t in_addr, uint16_t n_samples, bool swap_reverb, bool neg_left, bool neg_right, - uint32_t wet_dry_addr, uint32_t haas_temp_addr, uint32_t num_channels) + uint32_t wet_dry_addr, uint32_t haas_temp_addr, uint32_t num_channels, + uint32_t cutoff_freq_lfe) { // Note: max number of samples is 192 (192 * 2 = 384 bytes = 0x180) int max_num_samples = 192; @@ -675,7 +675,7 @@ void aEnvMixerImpl(uint16_t in_addr, uint16_t n_samples, bool swap_reverb, if (num_channels == 6) { // Calculate the filter coefficient - float RC = 1.f / (2 * M_PI * CUTOFF_FREQ_LFE); + float RC = 1.f / (2 * M_PI * cutoff_freq_lfe); float dt = 1.f / SAMPLE_RATE; float alpha = dt / (RC + dt); diff --git a/src/audio/mixer.h b/src/audio/mixer.h index 64c2221c..52cafd98 100644 --- a/src/audio/mixer.h +++ b/src/audio/mixer.h @@ -47,7 +47,8 @@ void aEnvSetup1Impl(uint8_t initial_vol_wet, uint16_t rate_wet, uint16_t rate_le void aEnvSetup2Impl(uint16_t initial_vol_left, uint16_t initial_vol_right, int16_t initial_vol_center, int16_t initial_vol_lfe, int16_t initial_vol_rear_left, int16_t initial_vol_rear_right); void aEnvMixerImpl(uint16_t in_addr, uint16_t n_samples, bool swap_reverb, bool neg_left, - bool neg_right, uint32_t wet_dry_addr, uint32_t haas_temp_addr, uint32_t num_channels); + bool neg_right, uint32_t wet_dry_addr, uint32_t haas_temp_addr, uint32_t num_channels, + uint32_t cutoff_freq_lfe); void aMixImpl(uint16_t count, int16_t gain, uint16_t in_addr, uint16_t out_addr); void aS8DecImpl(uint8_t flags, ADPCM_STATE state); void aAddMixerImpl(uint16_t count, uint16_t in_addr, uint16_t out_addr); @@ -76,8 +77,8 @@ void aUnkCmd19Impl(uint8_t f, uint16_t count, uint16_t out_addr, uint16_t in_add aEnvSetup1Impl(initialVolReverb, rampReverb, rampLeft, rampRight, rampCenter, rampLfe, rampRLeft, rampRRight) #define aEnvSetup2(pkt, initialVolLeft, initialVolRight, initialVolCenter, initialVolLfe, initialVolRLeft, initialVolRRight) \ aEnvSetup2Impl(initialVolLeft, initialVolRight, initialVolCenter, initialVolLfe, initialVolRLeft, initialVolRRight) -#define aEnvMixer(pkt, inAddr, nSamples, swapReverb, negLeft, negRight, wetDryAddr, haasTempAddr, numChannels) \ - aEnvMixerImpl(inAddr, nSamples, swapReverb, negLeft, negRight, wetDryAddr, haasTempAddr, numChannels) +#define aEnvMixer(pkt, inAddr, nSamples, swapReverb, negLeft, negRight, wetDryAddr, haasTempAddr, numChannels, cutoffFreqLfe) \ + aEnvMixerImpl(inAddr, nSamples, swapReverb, negLeft, negRight, wetDryAddr, haasTempAddr, numChannels, cutoffFreqLfe) #define aMix(pkt, c, g, i, o) aMixImpl(c, g, i, o) #define aS8Dec(pkt, f, s) aS8DecImpl(f, s) #define aAddMixer(pkt, s, d, c) aAddMixerImpl(s, d, c) diff --git a/src/port/ui/ImguiUI.cpp b/src/port/ui/ImguiUI.cpp index 615a07d0..1987efd7 100644 --- a/src/port/ui/ImguiUI.cpp +++ b/src/port/ui/ImguiUI.cpp @@ -116,6 +116,117 @@ static const char* voiceLangs[] = { "Original", /*"Japanese",*/ "Lylat" }; +void DrawSpeakerPositionEditor() { + static ImVec2 lastCanvasPos; + ImGui::Text("Speaker Position Editor"); + ImVec2 canvasSize = ImVec2(200, 200); // Static canvas size + ImVec2 canvasPos = ImGui::GetCursorScreenPos(); + ImVec2 center = ImVec2(canvasPos.x + canvasSize.x / 2, canvasPos.y + canvasSize.y / 2); + + // Speaker positions + static ImVec2 speakerPositions[4]; + static bool initialized = false; + static float radius = 80.0f; + + // Reset positions if canvas position changed (window resized/moved) + if (!initialized || (lastCanvasPos.x != canvasPos.x || lastCanvasPos.y != canvasPos.y)) { + const char* cvarNames[4] = { "gPositionFrontLeft", "gPositionFrontRight", "gPositionRearLeft", "gPositionRearRight" }; + float angles[4] = { 240.f, 300.f, 160.f, 20.f }; // Default angles + + for (int i = 0; i < 4; i++) { + int savedAngle = CVarGetInteger(cvarNames[i], -1); + if (savedAngle != -1) { + angles[i] = static_cast(savedAngle); + } + + float rad = angles[i] * (M_PI / 180.0f); + speakerPositions[i] = ImVec2(center.x + radius * cosf(rad), center.y + radius * sinf(rad)); + } + initialized = true; + lastCanvasPos = canvasPos; + } + + // Draw canvas + ImDrawList* drawList = ImGui::GetWindowDrawList(); + drawList->AddRectFilled(canvasPos, ImVec2(canvasPos.x + canvasSize.x, canvasPos.y + canvasSize.y), IM_COL32(26, 26, 26, 255)); + drawList->AddCircleFilled(center, 5.0f, IM_COL32(255, 255, 255, 255)); // Central person + + // Draw circle line for speaker positions + drawList->AddCircle(center, radius, IM_COL32(163, 163, 163, 255), 100); + + // Add markers at 0, 22.5, 45, etc. + for (float angle = 0; angle < 360; angle += 22.5f) { + float rad = angle * (M_PI / 180.0f); + ImVec2 markerStart = ImVec2(center.x + (radius - 5) * cosf(rad), center.y + (radius - 5) * sinf(rad)); + ImVec2 markerEnd = ImVec2(center.x + radius * cosf(rad), center.y + radius * sinf(rad)); + drawList->AddLine(markerStart, markerEnd, IM_COL32(163, 163, 163, 255)); + } + + const char* speakerLabels[4] = { "L", "R", "RL", "RR" }; + const char* cvarNames[4] = { "gPositionFrontLeft", "gPositionFrontRight", "gPositionRearLeft", "gPositionRearRight" }; + + const float snapThreshold = 2.5f; // Degrees within which snapping occurs + + for (int i = 0; i < 4; i++) { + // Draw speaker as a darker blue circle + drawList->AddCircleFilled(speakerPositions[i], 10.0f, IM_COL32(34, 52, 78, 255)); // Dark blue color + drawList->AddText(ImVec2(speakerPositions[i].x - 6, speakerPositions[i].y - 6), IM_COL32(255, 255, 255, 255), speakerLabels[i]); + + // Handle dragging + ImGui::SetCursorScreenPos(ImVec2(speakerPositions[i].x - 10, speakerPositions[i].y - 10)); + ImGui::InvisibleButton(speakerLabels[i], ImVec2(20, 20)); + if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left)) { + ImVec2 mouseDelta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Left); + ImVec2 newPos = ImVec2(speakerPositions[i].x + mouseDelta.x, speakerPositions[i].y + mouseDelta.y); + + // Constrain position to the circle + ImVec2 direction = ImVec2(newPos.x - center.x, newPos.y - center.y); + float length = sqrtf(direction.x * direction.x + direction.y * direction.y); + ImVec2 constrainedPos = ImVec2(center.x + (direction.x / length) * radius, center.y + (direction.y / length) * radius); + + // Calculate angle of the constrained position + float angle = atan2f(constrainedPos.y - center.y, constrainedPos.x - center.x) * (180.0f / M_PI); + if (angle < 0) angle += 360.0f; + + // Snap to the nearest 22.5-degree marker if within the snap threshold + float snappedAngle = roundf(angle / 22.5f) * 22.5f; + if (fabsf(snappedAngle - angle) <= snapThreshold) { + float rad = snappedAngle * (M_PI / 180.0f); + constrainedPos = ImVec2(center.x + radius * cosf(rad), center.y + radius * sinf(rad)); + } + + speakerPositions[i] = constrainedPos; + ImGui::ResetMouseDragDelta(); + + // Save the updated angle to CVar after dragging + float updatedAngle = atan2f(speakerPositions[i].y - center.y, speakerPositions[i].x - center.x) * (180.0f / M_PI); + if (updatedAngle < 0) updatedAngle += 360.0f; + CVarSetInteger(cvarNames[i], static_cast(updatedAngle)); + Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame(); // Mark for saving + } + + // Calculate angle and save to CVar + float angle = atan2f(speakerPositions[i].y - center.y, speakerPositions[i].x - center.x) * (180.0f / M_PI); + if (angle < 0) angle += 360.0f; + CVarSetInteger(cvarNames[i], static_cast(angle)); + } + + // Reset cursor position for button placement + ImGui::SetCursorScreenPos(ImVec2(canvasPos.x, canvasPos.y + canvasSize.y + 10)); + if (ImGui::Button("Reset Positions")) { + float defaultAngles[4] = { 240.f, 300.f, 160.f, 20.f }; + for (int i = 0; i < 4; i++) { + float rad = defaultAngles[i] * (M_PI / 180.0f); + speakerPositions[i] = ImVec2(center.x + radius * cosf(rad), center.y + radius * sinf(rad)); + CVarSetInteger(cvarNames[i], static_cast(defaultAngles[i])); + } + Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame(); + } + + // Reset cursor position to ensure canvas size remains static + ImGui::SetCursorScreenPos(ImVec2(canvasPos.x, canvasPos.y + canvasSize.y + 10)); +} + void DrawSettingsMenu(){ if(UIWidgets::BeginMenu("Settings")){ if (UIWidgets::BeginMenu("Audio")) { @@ -173,6 +284,23 @@ void DrawSettingsMenu(){ } UIWidgets::PaddedEnhancementCheckbox("Surround 5.1 (Needs reload)", "gAudioChannelsSetting", 1, 0); + + if (CVarGetInteger("gAudioChannelsSetting", 0) == 1) { + // Subwoofer threshold + UIWidgets::CVarSliderInt("Subwoofer threshold (Hz)", "gSubwooferThreshold", 10u, 1000u, 80u, { + .tooltip = "The threshold for the subwoofer to be activated. Any sound under this frequency will be played on the subwoofer.", + .format = "%d", + }); + + // Rear music volume slider + UIWidgets::CVarSliderFloat("Rear music volume", "gVolumeRearMusic", 0.0f, 1.0f, 1.0f, { + .format = "%.0f%%", + .isPercentage = true, + }); + + // Configurable positioning of speakers + DrawSpeakerPositionEditor(); + } ImGui::EndMenu(); } From 99b18fa2a354f355b7a46d95b72ebe28c6d349c8 Mon Sep 17 00:00:00 2001 From: Alejandro Asenjo Nitti <96613413+sonicdcer@users.noreply.github.com> Date: Fri, 23 May 2025 17:21:30 -0300 Subject: [PATCH 03/28] Update Torch (#199) * update Torch * update LUS * update Torch * try f75facb20883570ed091e8ae733ec0539f606e57 --- libultraship | 2 +- tools/Torch | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libultraship b/libultraship index dda07c8a..45c4f8d6 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit dda07c8ac6033ff98d37a05bc28406440c7769e4 +Subproject commit 45c4f8d6c19c6176f5e0918917c655ea09ecc212 diff --git a/tools/Torch b/tools/Torch index 9c460ea5..f75facb2 160000 --- a/tools/Torch +++ b/tools/Torch @@ -1 +1 @@ -Subproject commit 9c460ea54312e9cefabf155e3b83021c01862843 +Subproject commit f75facb20883570ed091e8ae733ec0539f606e57 From 51ae77d3d58f631886d0cd1b757b9d95e0afcae0 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Fri, 23 May 2025 17:58:34 -0300 Subject: [PATCH 04/28] update metal shader --- port/shaders/metal/default.shader.metal | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/port/shaders/metal/default.shader.metal b/port/shaders/metal/default.shader.metal index 63d89fd3..a771ba10 100644 --- a/port/shaders/metal/default.shader.metal +++ b/port/shaders/metal/default.shader.metal @@ -147,17 +147,6 @@ float random(float3 value) { return fract(sin(random) * 143758.5453); } -float4 fromLinear(float4 linearRGB) { - float3 threshold = float3(0.0031308); - float3 gamma = float3(1.0 / 2.4); - float3 scale = float3(12.92); - float3 offset = float3(1.055); - float3 subtract = float3(0.055); - float3 higher = offset * fast::pow(linearRGB.xyz, gamma) - subtract; - float3 lower = linearRGB.xyz * scale; - return float4(select(higher, lower, linearRGB.xyz < threshold), linearRGB.w); -} - fragment float4 fragmentShader(ProjectedVertex in [[stage_in]], constant FrameUniforms &frameUniforms [[buffer(0)]] @if(o_textures[0]) , texture2d uTex0 [[texture(0)]], sampler uTex0Smplr [[sampler(0)]] @@ -288,8 +277,8 @@ fragment float4 fragmentShader(ProjectedVertex in [[stage_in]], constant FrameUn @if(o_invisible) texel.w = 0.0; @end - return fromLinear(texel); + return texel; @else - return fromLinear(float4(texel, 1.0)); + return float4(texel, 1.0); @end } \ No newline at end of file From f22f8c193545ef7963d6bd16a14325aa964f7e44 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Fri, 23 May 2025 18:02:11 -0300 Subject: [PATCH 05/28] roll back shader update --- port/shaders/metal/default.shader.metal | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/port/shaders/metal/default.shader.metal b/port/shaders/metal/default.shader.metal index a771ba10..63d89fd3 100644 --- a/port/shaders/metal/default.shader.metal +++ b/port/shaders/metal/default.shader.metal @@ -147,6 +147,17 @@ float random(float3 value) { return fract(sin(random) * 143758.5453); } +float4 fromLinear(float4 linearRGB) { + float3 threshold = float3(0.0031308); + float3 gamma = float3(1.0 / 2.4); + float3 scale = float3(12.92); + float3 offset = float3(1.055); + float3 subtract = float3(0.055); + float3 higher = offset * fast::pow(linearRGB.xyz, gamma) - subtract; + float3 lower = linearRGB.xyz * scale; + return float4(select(higher, lower, linearRGB.xyz < threshold), linearRGB.w); +} + fragment float4 fragmentShader(ProjectedVertex in [[stage_in]], constant FrameUniforms &frameUniforms [[buffer(0)]] @if(o_textures[0]) , texture2d uTex0 [[texture(0)]], sampler uTex0Smplr [[sampler(0)]] @@ -277,8 +288,8 @@ fragment float4 fragmentShader(ProjectedVertex in [[stage_in]], constant FrameUn @if(o_invisible) texel.w = 0.0; @end - return texel; + return fromLinear(texel); @else - return float4(texel, 1.0); + return fromLinear(float4(texel, 1.0)); @end } \ No newline at end of file From f5c813d97655456fea9250e6b097e5c438dae3d8 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Fri, 23 May 2025 18:57:39 -0300 Subject: [PATCH 06/28] Skip interpolation on Effects 374 and 382 --- src/engine/fox_effect.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/engine/fox_effect.c b/src/engine/fox_effect.c index 010d8bab..6cb1391c 100644 --- a/src/engine/fox_effect.c +++ b/src/engine/fox_effect.c @@ -218,6 +218,9 @@ void Effect_Effect372_Draw(Effect372* this) { } void Effect_Effect382_Draw(Effect382* this) { + // @port Skip interpolation + FrameInterpolation_ShouldInterpolateFrame(false); + RCP_SetupDL_49(); gDPSetPrimColor(gMasterDisp++, 0, 0, 255, 255, 255, this->unk_44); gDPSetEnvColor(gMasterDisp++, 255, 255, 255, this->unk_44); @@ -225,6 +228,10 @@ void Effect_Effect382_Draw(Effect382* this) { Matrix_Translate(gGfxMatrix, 0.0f, 20.0f, 0.0f, MTXF_APPLY); Matrix_SetGfxMtx(&gMasterDisp); gSPDisplayList(gMasterDisp++, D_ZO_6024220); + + // @port renable interpolation + FrameInterpolation_ShouldInterpolateFrame(true); + RCP_SetupDL(&gMasterDisp, SETUPDL_64); } @@ -2276,11 +2283,18 @@ void Effect_Effect374_Draw(Effect374* this) { break; case 1: + // @port Skip interpolation + FrameInterpolation_ShouldInterpolateFrame(false); + Matrix_Scale(gGfxMatrix, this->scale1, this->scale2, 2.5f, MTXF_APPLY); Matrix_SetGfxMtx(&gMasterDisp); RCP_SetupDL_40(); gSPClearGeometryMode(gMasterDisp++, G_CULL_BACK); gSPDisplayList(gMasterDisp++, D_ENMY_PLANET_4008F70); + + // @port renable interpolation + FrameInterpolation_ShouldInterpolateFrame(true); + RCP_SetupDL(&gMasterDisp, SETUPDL_64); break; } From a61e0dd9e9ee7d998c019f3d3110b44c7de648e2 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sat, 24 May 2025 04:08:44 -0300 Subject: [PATCH 07/28] Fix ending not playing after first playthrough --- src/overlays/ovl_ending/fox_end1.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/overlays/ovl_ending/fox_end1.c b/src/overlays/ovl_ending/fox_end1.c index c07432a8..5c3fbcdb 100644 --- a/src/overlays/ovl_ending/fox_end1.c +++ b/src/overlays/ovl_ending/fox_end1.c @@ -1027,9 +1027,8 @@ void Ending_8018A8FC(void) { void Ending_Main(void) { gCsFrameCount++; gGameFrameCount++; - switch (D_ending_80196D00) { - case 0: + case 0: // Ending Init gRadioState = 0; gGameFrameCount = 0; gSceneSetup = 0; @@ -1037,6 +1036,12 @@ void Ending_Main(void) { gCsCamAtX = gCsCamAtY = 0.0f; gCsCamAtZ = -100.0f; D_ending_80196D00 = 1; + + // @port Bugfix: + // In the original game, this variable is set zero when the overlay is reloaded. + // Since we don't use overlays, the absence of this counter reset causes the ending not to play + // after a the first playthrough. + D_ending_80192E70 = 0; break; case 1: From 99288aaf57d7779f3bc66e6be03575847e8825da Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sat, 24 May 2025 18:28:43 -0300 Subject: [PATCH 08/28] better fix for the ending --- src/overlays/ovl_ending/fox_end1.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/overlays/ovl_ending/fox_end1.c b/src/overlays/ovl_ending/fox_end1.c index 5c3fbcdb..efdf3076 100644 --- a/src/overlays/ovl_ending/fox_end1.c +++ b/src/overlays/ovl_ending/fox_end1.c @@ -48,6 +48,25 @@ bool D_ending_80198584; s32 D_ending_80198588; s32 D_ending_8019858C; +void Ending_Port_InitOverlay(void) { + D_ending_80192E70 = 0; // ending sequence frame counter + D_ending_80196D04 = 0; // ending text frame counter + memset(D_ending_80196D08, 0, sizeof(D_ending_80196D08)); + D_ending_80196F88 = 0; + D_ending_80196F8C = 0; + D_ending_80196F90 = 0; + D_ending_80196F94 = 0; + D_ending_80196F98 = 0; + D_ending_80196F9C = 0.0f; + memset(D_ending_80196FA0, 0, sizeof(D_ending_80196FA0)); + memset(D_ending_80197900, 0, sizeof(D_ending_80197900)); + memset(D_ending_80198260, 0, sizeof(D_ending_80198260)); + D_ending_80198580 = 0.0f; + D_ending_80198584 = false; + D_ending_80198588 = 0; + D_ending_8019858C = 0; +} + const char str1[] = "fogR= %d, fogG= %d, fogB= %d\n"; const char str2[] = "ligR= %d, ligG= %d, ligB= %d\n"; const char str3[] = "kanR= %d, kanG= %d, kanB= %d\n"; @@ -1038,10 +1057,10 @@ void Ending_Main(void) { D_ending_80196D00 = 1; // @port Bugfix: - // In the original game, this variable is set zero when the overlay is reloaded. - // Since we don't use overlays, the absence of this counter reset causes the ending not to play - // after a the first playthrough. - D_ending_80192E70 = 0; + // In the original game, these variables are set to zero when the overlay is reloaded. + // Since we don't use overlays, the absence of this initializer causes the ending not to play + // as it should after a the first playthrough. + Ending_Port_InitOverlay(); break; case 1: From f6c5d7ee52628700f4fe539a9bca601f91e8cbf9 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sat, 24 May 2025 18:48:32 -0300 Subject: [PATCH 09/28] TODO comment --- src/engine/fox_load.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/fox_load.c b/src/engine/fox_load.c index f740a0e2..9ba73553 100644 --- a/src/engine/fox_load.c +++ b/src/engine/fox_load.c @@ -34,6 +34,7 @@ void Load_RomFile(void* vRomAddress, void* dest, ptrdiff_t size) { u8 Load_SceneFiles(Scene* scene) { #if 1 + // TODO: BUG! sCurrentScene and scene never change so this will never be true. bool hasSceneChanged = memcmp(&sCurrentScene, scene, sizeof(Scene)) != 0; sCurrentScene = *scene; return hasSceneChanged; From ffe5d9f420e3d5fc8486910c498773d58d97fe4a Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sat, 24 May 2025 18:49:54 -0300 Subject: [PATCH 10/28] fix versus audio issue --- src/engine/fox_versus.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/engine/fox_versus.c b/src/engine/fox_versus.c index fb56a60e..2bba4e29 100644 --- a/src/engine/fox_versus.c +++ b/src/engine/fox_versus.c @@ -97,7 +97,7 @@ void func_versus_800BC9DC(f32 xPos, f32 yPos, f32 scale, s32 yScale) { s32 D_800D4AB0[] = { 40, 64, 64 }; Lib_TextureRect_CI8(&gMasterDisp, D_800D4ABC[yScale], D_800D4AA4[yScale], D_800D4AB0[yScale], 40, xPos, yPos, scale, - scale); + scale); } void func_versus_800BCB44(f32 xPos, f32 yPos, f32 scale) { @@ -110,7 +110,7 @@ void func_versus_800BCC48(f32 xPos, f32 yPos, f32 xScale, f32 yScale, s32 arg4) s32 D_800D4AE8[] = { 104, 152, 168, 152 }; Lib_TextureRect_CI8(&gMasterDisp, D_800D4AD8[arg4], D_800D4AC8[arg4], D_800D4AE8[arg4], 25, xPos, yPos, xScale, - yScale); + yScale); } void func_versus_800BCE24(f32 xPos, f32 yPos, f32 xScale, f32 yScale) { @@ -168,8 +168,7 @@ void func_versus_800BD350(f32 xPos, f32 yPos) { } void func_versus_800BD3A8(f32 xPos, f32 yPos) { - Lib_TextureRect_CI4(&gMasterDisp, aVsHandicapFrameTex, aVsHandicapFrameTLUT, 80, 71, xPos, yPos, 1.0f, - 1.0f); + Lib_TextureRect_CI4(&gMasterDisp, aVsHandicapFrameTex, aVsHandicapFrameTLUT, 80, 71, xPos, yPos, 1.0f, 1.0f); } void func_versus_800BD4D4(f32 xPos, f32 yPos, s32 arg2) { @@ -1262,6 +1261,9 @@ s32 func_versus_800C1138(s32 max, s32 arg1) { void Versus_InitMatch(void) { s32 i; + // Until Load_SceneFiles gets fixed, this fixes most of the audio issues in versus + AUDIO_SET_SPEC_ALT(SFXCHAN_3, AUDIOSPEC_16); + for (i = 0, sVsPlayerCount = 0; i < 4; i++) { if (!gPlayerInactive[i]) { sVsPlayerCount++; From 1e664de67757459a696ab58068db289dbc74cb98 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sat, 24 May 2025 19:40:29 -0300 Subject: [PATCH 11/28] Skip credits by pressing the start button if it was seen at least once. --- src/overlays/ovl_ending/fox_end1.c | 12 ++++++++++++ src/overlays/ovl_ending/fox_end2.c | 10 +++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/overlays/ovl_ending/fox_end1.c b/src/overlays/ovl_ending/fox_end1.c index efdf3076..79223f92 100644 --- a/src/overlays/ovl_ending/fox_end1.c +++ b/src/overlays/ovl_ending/fox_end1.c @@ -1046,6 +1046,18 @@ void Ending_8018A8FC(void) { void Ending_Main(void) { gCsFrameCount++; gGameFrameCount++; + + if (gSaveFile.save.data.padEE[0] == 1) { + gControllerLock = 0; + if (gControllerPress[0].button & START_BUTTON) { + D_ending_80196D00 = 7; + D_ending_80196D04 = 7200; + D_ending_80192E70 = 7200; + } + } else { + gControllerLock = 10000; + } + switch (D_ending_80196D00) { case 0: // Ending Init gRadioState = 0; diff --git a/src/overlays/ovl_ending/fox_end2.c b/src/overlays/ovl_ending/fox_end2.c index bd32bfde..43d88173 100644 --- a/src/overlays/ovl_ending/fox_end2.c +++ b/src/overlays/ovl_ending/fox_end2.c @@ -820,6 +820,10 @@ void Ending_80191234(u32 arg0, AssetInfo* asset) { gBgColor = 0; gStarCount = 0; gControllerLock = 10; + + // @port: Ending seen at least once. + gSaveFile.save.data.padEE[0] = 1; + Save_Write(); } void Ending_80191294(u32 arg0, AssetInfo* asset) { @@ -1083,7 +1087,11 @@ void Ending_801924EC(u32 arg0) { } void Ending_801926D4(void) { - gControllerLock = 10000; + if (gSaveFile.save.data.padEE[0] == 1) { + gControllerLock = 0; + } else { + gControllerLock = 10000; + } Matrix_Push(&gGfxMatrix); From eb1418cfc988c8101230461e2b3223bbf799e26f Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sat, 24 May 2025 19:43:21 -0300 Subject: [PATCH 12/28] fix UB --- src/overlays/ovl_menu/fox_option.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/overlays/ovl_menu/fox_option.c b/src/overlays/ovl_menu/fox_option.c index e44ede97..4216d32f 100644 --- a/src/overlays/ovl_menu/fox_option.c +++ b/src/overlays/ovl_menu/fox_option.c @@ -1959,7 +1959,7 @@ void Option_Data_Select(void) { } void Option_Data_Draw(void) { - s32 i; + s32 i = 0; s32 sp7C[2]; s32 mask[2]; static f32 D_menu_801AF084[2] = { 172.0f, 76.0f }; @@ -1974,8 +1974,7 @@ void Option_Data_Draw(void) { gDPSetPrimColor(gMasterDisp++, 0, 0, 255, 255, 255, 255); - Lib_TextureRect_IA8(&gMasterDisp, D_OPT_80084B0, 176, 13, D_menu_801AF094[0], D_menu_801AF0AC[0] + (4.0f * i), 1.0f, - 1.0f); + Lib_TextureRect_IA8(&gMasterDisp, D_OPT_80084B0, 176, 13, D_menu_801AF094[0], D_menu_801AF0AC[0], 1.0f, 1.0f); if (D_menu_801B91CC < 2) { Lib_TextureRect_IA8_MirX(&gMasterDisp, aArrowTex, 8, 8, D_menu_801AF084[D_menu_801B91C0], 140.0f, 1.0f, 1.0f); @@ -2250,7 +2249,7 @@ void Option_80197914(void) { // @port: Tag the transform. FrameInterpolation_RecordOpenChild("RANKING_BORDERS", i); - Matrix_Translate(gGfxMatrix, vec1->x, vec1->y, -500.0f, MTXF_APPLY); + Matrix_Translate(gGfxMatrix, vec1->x, vec1->y, -500.0f, MTXF_APPLY); // @port: Increase the scale by 2.5f to compensate for missing borders Matrix_Scale(gGfxMatrix, vec2->x * 4, vec2->y + 2.5f, 1.0f, MTXF_APPLY); From ee803d4f3e5590e64bca7a8385c0157dd3819239 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sat, 24 May 2025 19:47:59 -0300 Subject: [PATCH 13/28] segataSanshiroTimer comment --- src/overlays/ovl_menu/fox_title.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/overlays/ovl_menu/fox_title.c b/src/overlays/ovl_menu/fox_title.c index 5a521c15..216263fe 100644 --- a/src/overlays/ovl_menu/fox_title.c +++ b/src/overlays/ovl_menu/fox_title.c @@ -146,6 +146,8 @@ f32 D_menu_801B9078; f32 D_menu_801B907C; f32 D_menu_801B9080; f32 D_menu_801B9084; + +// @port: Timer for drawing the mirrored Great Fox Deck. s32 segataSanshiroTimer = 0; TitleAnimation sTeamAnim[4] = { From 9bac262183ae4a483945e76b4553ec3c107413af Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sat, 24 May 2025 22:52:05 -0300 Subject: [PATCH 14/28] tag Landmaster thrusters --- src/engine/fox_display.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/engine/fox_display.c b/src/engine/fox_display.c index 0d6e2bad..ffbdcebe 100644 --- a/src/engine/fox_display.c +++ b/src/engine/fox_display.c @@ -432,6 +432,10 @@ void Display_LandmasterThrusters(Player* player) { } Matrix_Push(&gGfxMatrix); + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("Display_LandmasterThrusters_1", player->num); + Matrix_Translate(gGfxMatrix, 20.0f, 30.0f, -10.0f, MTXF_APPLY); if (!gVersusMode) { @@ -447,6 +451,10 @@ void Display_LandmasterThrusters(Player* player) { } else { gSPDisplayList(gMasterDisp++, D_versus_301B6E0); } + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); + Matrix_Pop(&gGfxMatrix); } @@ -461,6 +469,10 @@ void Display_LandmasterThrusters(Player* player) { } Matrix_Push(&gGfxMatrix); + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("Display_LandmasterThrusters_2", player->num); + Matrix_Translate(gGfxMatrix, -20.0f, 30.0f, -10.0f, MTXF_APPLY); if (!gVersusMode) { @@ -476,8 +488,13 @@ void Display_LandmasterThrusters(Player* player) { } else { gSPDisplayList(gMasterDisp++, D_versus_301B6E0); } + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); + Matrix_Pop(&gGfxMatrix); } + Matrix_Pop(&gGfxMatrix); } From 26b3ebe15c764cd6aa9f41b6a23728837809d2c0 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sat, 24 May 2025 22:52:15 -0300 Subject: [PATCH 15/28] tag Effect357 --- src/engine/fox_effect.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/engine/fox_effect.c b/src/engine/fox_effect.c index 6cb1391c..3a7665a5 100644 --- a/src/engine/fox_effect.c +++ b/src/engine/fox_effect.c @@ -753,6 +753,9 @@ void Effect_Effect357_Draw(Effect357* this) { gSPFogPosition(gMasterDisp++, gFogNear, 1005); } + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("Effect357", this->unk_4C | (this->index << 16) & 0x00FF); + Graphics_SetScaleMtx(this->scale2); switch (gCurrentLevel) { @@ -894,6 +897,8 @@ void Effect_Effect357_Draw(Effect357* this) { } break; } + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); RCP_SetupDL(&gMasterDisp, SETUPDL_64); @@ -2294,7 +2299,7 @@ void Effect_Effect374_Draw(Effect374* this) { // @port renable interpolation FrameInterpolation_ShouldInterpolateFrame(true); - + RCP_SetupDL(&gMasterDisp, SETUPDL_64); break; } @@ -3809,7 +3814,7 @@ void Effect_Effect395_Update(Effect395* this) { D_ctx_801779A8[0] = 50.0f; if (this->unk_46 == 10) { gFillScreenRed = gFillScreenGreen = gFillScreenBlue = 255; - if (CVarGetInteger("gDisableGorgonFlash", 0) == 0){ + if (CVarGetInteger("gDisableGorgonFlash", 0) == 0) { gFillScreenAlpha = gFillScreenAlphaTarget = 255; } gFillScreenAlphaTarget = 0; From 7a486493b4eb4c96163864071ba12f1eb7b0fa15 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sat, 24 May 2025 22:52:29 -0300 Subject: [PATCH 16/28] Tag MaBombDrop --- src/overlays/ovl_i5/fox_ma.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/overlays/ovl_i5/fox_ma.c b/src/overlays/ovl_i5/fox_ma.c index 6825f828..0db5a77f 100644 --- a/src/overlays/ovl_i5/fox_ma.c +++ b/src/overlays/ovl_i5/fox_ma.c @@ -5925,11 +5925,17 @@ void Macbeth_MaBombDrop_Draw(MaBombDrop* this) { break; case 1: + // @port Skip interpolation + FrameInterpolation_ShouldInterpolateFrame(false); + Matrix_Scale(gGfxMatrix, this->fwork[0], this->scale, 2.5f, MTXF_APPLY); Matrix_SetGfxMtx(&gMasterDisp); RCP_SetupDL_40(); gSPClearGeometryMode(gMasterDisp++, G_CULL_BACK); gSPDisplayList(gMasterDisp++, D_ENMY_PLANET_4008F70); + + // @port renable interpolation + FrameInterpolation_ShouldInterpolateFrame(true); RCP_SetupDL(&gMasterDisp, SETUPDL_64); break; } @@ -6496,12 +6502,6 @@ f32 D_i5_801BA854[8] = { 1.5f, -1.0f, 0.7f, 0.0f, 0.9f, 0.7f, -1.0f, 1.5f }; f32 D_i5_801BA874[8] = { 200.0f, 300.0f, 400.0f, 0.0f, 500.0f, 100.0f, 120.0f, 100.0f }; f32 D_i5_801BA894[8] = { 200.0f, 250.0f, 220.0f, 0.0f, 200.0f, 230.0f, 220.0f, 350.0f }; - - - - - - void Macbeth_LevelComplete2(Player* player) { s32 i; s32 j; From 923cc7697db34b96d2fca7d47086b0164db032c4 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sat, 24 May 2025 22:52:42 -0300 Subject: [PATCH 17/28] Tag OptionCardFrame --- src/overlays/ovl_menu/fox_option.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/overlays/ovl_menu/fox_option.c b/src/overlays/ovl_menu/fox_option.c index 4216d32f..97fda39b 100644 --- a/src/overlays/ovl_menu/fox_option.c +++ b/src/overlays/ovl_menu/fox_option.c @@ -3491,6 +3491,9 @@ void Option_DrawMenuCard(OptionCardFrame arg0) { Matrix_Push(&gGfxMatrix); + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("MenuCard", (u32) & arg0); + Matrix_Translate(gGfxMatrix, arg0.x, arg0.y, arg0.z, MTXF_APPLY); Matrix_Scale(gGfxMatrix, arg0.xScale, arg0.yScale, 1.0f, MTXF_APPLY); Matrix_RotateX(gGfxMatrix, M_DTOR * 90.0f, MTXF_APPLY); @@ -3501,6 +3504,9 @@ void Option_DrawMenuCard(OptionCardFrame arg0) { Matrix_Pop(&gGfxMatrix); + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); + Lib_InitPerspective(&gMasterDisp); } From ff0f36552cf24b3573a89637da1b5d452dd01083 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sat, 24 May 2025 22:54:49 -0300 Subject: [PATCH 18/28] Render parallelization Enabled by default --- src/port/Engine.cpp | 2 +- src/port/ui/ImguiUI.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp index a2c16ca8..a5340e85 100644 --- a/src/port/Engine.cpp +++ b/src/port/Engine.cpp @@ -522,7 +522,7 @@ void GameEngine::ProcessGfxCommands(Gfx* commands) { if (wnd != nullptr) { wnd->SetTargetFps(fps); - wnd->SetMaximumFrameLatency(CVarGetInteger("gRenderParallelization", 0) ? 2 : 1); + wnd->SetMaximumFrameLatency(CVarGetInteger("gRenderParallelization", 1) ? 2 : 1); } // When the gfx debugger is active, only run with the final mtx diff --git a/src/port/ui/ImguiUI.cpp b/src/port/ui/ImguiUI.cpp index 1987efd7..61c3f7fd 100644 --- a/src/port/ui/ImguiUI.cpp +++ b/src/port/ui/ImguiUI.cpp @@ -449,7 +449,7 @@ void DrawSettingsMenu(){ UIWidgets::Tooltip("Matches interpolation value to the refresh rate of your display."); if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() == Ship::WindowBackend::FAST3D_DXGI_DX11) { - UIWidgets::PaddedEnhancementCheckbox("Render parallelization","gRenderParallelization", true, false); + UIWidgets::PaddedEnhancementCheckbox("Render parallelization","gRenderParallelization", true, false, {}, {}, {}, true); UIWidgets::Tooltip( "This setting allows the CPU to work on one frame while GPU works on the previous frame.\n" "Recommended if you can't reach the FPS you set, despite it being set below your refresh rate " From 1a76f52c40a583cfa5bca01bd792350879e50ddd Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sun, 25 May 2025 00:06:28 -0300 Subject: [PATCH 19/28] update ROM Extraction Message --- src/port/Engine.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp index a5340e85..d2bee9ec 100644 --- a/src/port/Engine.cpp +++ b/src/port/Engine.cpp @@ -88,7 +88,7 @@ GameEngine::GameEngine() { if (std::filesystem::exists(main_path)) { archiveFiles.push_back(main_path); } else { - if (ShowYesNoBox("No O2R Files", "No O2R files found. Generate one now?") == IDYES) { + if (ShowYesNoBox("Starship - Asset Extraction", "Please provide a Starfox 64 ROM.\n\nSupported Versions:\nUS 1.0\nUS 1.1\n\nAssets will be extracted into an O2R file.") == IDYES) { if(!GenAssetFile()){ ShowMessage("Error", "An error occured, no O2R file was generated.\n\nExiting..."); exit(1); @@ -96,7 +96,7 @@ GameEngine::GameEngine() { archiveFiles.push_back(main_path); } - if (ShowYesNoBox("Extraction Complete", "ROM Extracted. Extract another?") == IDYES) { + if (ShowYesNoBox("Extraction Complete", "ROM Extracted. Extract another?\n\n Starship supports JP and EU ROMs for voice replacement.\n Voice replacement ROM assets can also be installed in:\n Settings->Language->Install JP/EU Audio") == IDYES) { if(!GenAssetFile()){ ShowMessage("Error", "An error occured, no O2R file was generated."); } @@ -291,7 +291,7 @@ bool GameEngine::GenAssetFile(bool exitOnFail) { } } - ShowMessage(("Found " + game.value()).c_str(), "The extraction process will now begin.\n\nThis may take a few minutes.", SDL_MESSAGEBOX_INFORMATION); + ShowMessage(("Starship - Extraction - Found " + game.value()).c_str(), "The extraction process will now begin.\n\nThis may take a few minutes.", SDL_MESSAGEBOX_INFORMATION); return extractor->GenerateOTR(); } From 1567f2afcab6fd8a670d3b015d3efa48127ddc01 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sun, 25 May 2025 00:15:10 -0300 Subject: [PATCH 20/28] Update Readme --- README.md | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index b23a60d3..a3c26e9a 100644 --- a/README.md +++ b/README.md @@ -18,27 +18,31 @@ If you're having any trouble after reading through this `README`, feel free ask Starship does not include any copyrighted assets. You are required to provide a supported copy of the game. ### 1. Verify your ROM dump -The supported ROM is the USA 1.1 Rev A version. You can verify you have dumped a supported copy of the game by using the SHA-1 File Checksum Online at https://www.romhacking.net/hash/. The hash for a US 1.1 ROM is SHA-1: 09F0D105F476B00EFA5303A3EBC42E60A7753B7A. +The supported ROMs are US 1.0 and US 1.1 Rev A versions. You can verify you have dumped a supported copy of the game by using the SHA-1 File Checksum Online at https://www.romhacking.net/hash/. + +The SHA-1 hash for a US 1.0 ROM is D8B1088520F7C5F81433292A9258C1184AFA1457. +The SHA-1 hash for a US 1.1 ROM is 09F0D105F476B00EFA5303A3EBC42E60A7753B7A. + +Starship also supports voice language replacement use from both EU (Lylat) and JP (Japanese) when used in conjunction with an US ROM. +Note: JP and EU versions of the game are not supported for the base asset O2R creation, a US ROM must be used for it. ### 2. Verify your ROM is in .z64 format Your ROM needs to be in .z64 format. If it's in .n64 format, use the following to convert it to a .z64: https://hack64.net/tools/swapper.php ### 2. Download Starship from [Releases](https://github.com/HarbourMasters/Starship/releases) -### 3. Generating the O2R from the ROM +### 3. Generating the OTR from the ROM and Play! #### Windows * Extract every file from the zip into a folder of your choosing. -* Copy your ROM to the root of the folder you extracted the zip to. -* Run "generate_o2r.bat" +* Run starship.exe and select your US 1.0 or US 1.1 ROM. + +#### Linux +* Extract every file from the zip into a folder of your choosing. +* Execute starship.appimage. You may have to chmod +x the appimage via terminal. #### MacOS * Extract every file from the zip into a folder of your choosing. -* Copy your ROM to the root of the folder you extracted the zip to. -* Run "generate_o2r.sh" - -### 4. Play! -* Launch `Starship.exe` -Congratulations, you are now sailing with Starship! Have fun! +* Run starship and select your US 1.0 or US 1.1 ROM. # Configuration From bdf39d760a649aac0d9ce46dc9187ea754507fac Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sun, 25 May 2025 00:18:23 -0300 Subject: [PATCH 21/28] readme again --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a3c26e9a..b75e3118 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,8 @@ Starship does not include any copyrighted assets. You are required to provide a ### 1. Verify your ROM dump The supported ROMs are US 1.0 and US 1.1 Rev A versions. You can verify you have dumped a supported copy of the game by using the SHA-1 File Checksum Online at https://www.romhacking.net/hash/. -The SHA-1 hash for a US 1.0 ROM is D8B1088520F7C5F81433292A9258C1184AFA1457. -The SHA-1 hash for a US 1.1 ROM is 09F0D105F476B00EFA5303A3EBC42E60A7753B7A. +* The SHA-1 hash for a US 1.0 ROM is D8B1088520F7C5F81433292A9258C1184AFA1457. +* The SHA-1 hash for a US 1.1 ROM is 09F0D105F476B00EFA5303A3EBC42E60A7753B7A. Starship also supports voice language replacement use from both EU (Lylat) and JP (Japanese) when used in conjunction with an US ROM. Note: JP and EU versions of the game are not supported for the base asset O2R creation, a US ROM must be used for it. From 0b1ba44dddd00cc159f24357f2a703f1c8f7da94 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sun, 25 May 2025 00:18:55 -0300 Subject: [PATCH 22/28] readme again 2 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b75e3118..0f03e781 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ The supported ROMs are US 1.0 and US 1.1 Rev A versions. You can verify you have * The SHA-1 hash for a US 1.1 ROM is 09F0D105F476B00EFA5303A3EBC42E60A7753B7A. Starship also supports voice language replacement use from both EU (Lylat) and JP (Japanese) when used in conjunction with an US ROM. + Note: JP and EU versions of the game are not supported for the base asset O2R creation, a US ROM must be used for it. ### 2. Verify your ROM is in .z64 format From dbdf981a1d5778ce46d671ead0308eba1738f6c3 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sun, 25 May 2025 00:19:54 -0300 Subject: [PATCH 23/28] linux readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0f03e781..a7076a6b 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ Your ROM needs to be in .z64 format. If it's in .n64 format, use the following t #### Linux * Extract every file from the zip into a folder of your choosing. * Execute starship.appimage. You may have to chmod +x the appimage via terminal. +* Select your US 1.0 or US 1.1 ROM. #### MacOS * Extract every file from the zip into a folder of your choosing. From cb19785b51698185a688e17ba1a34c7889195bdb Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sun, 25 May 2025 00:33:23 -0300 Subject: [PATCH 24/28] Barnard --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 35f8d01e..9ba3f194 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ math(EXPR PATCH_INDEX "${PROJECT_VERSION_PATCH}") # Use the patch number to select the correct word list(GET NATO_PHONETIC_ALPHABET ${PATCH_INDEX} PROJECT_PATCH_WORD) -set(PROJECT_BUILD_NAME "Centauri ${PROJECT_PATCH_WORD}" CACHE STRING "" FORCE) +set(PROJECT_BUILD_NAME "Barnard ${PROJECT_PATCH_WORD}" CACHE STRING "" FORCE) set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "" FORCE) if(APPLE) From d3289f735266d6679521f2e79cd257ece94b7a89 Mon Sep 17 00:00:00 2001 From: sitton76 <58642183+sitton76@users.noreply.github.com> Date: Sun, 25 May 2025 01:12:24 -0500 Subject: [PATCH 25/28] JP/EU ROM selection closes game if no ROM selected. (#201) * Added else state to close the game if no rom is found when attempting to extact EU/JP assets. * Did it properly(confirmed on Linux) --- src/port/ui/ImguiUI.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/port/ui/ImguiUI.cpp b/src/port/ui/ImguiUI.cpp index 61c3f7fd..be909fc6 100644 --- a/src/port/ui/ImguiUI.cpp +++ b/src/port/ui/ImguiUI.cpp @@ -320,10 +320,10 @@ void DrawSettingsMenu(){ }; } else { if (UIWidgets::Button("Install JP/EU Audio")) { - if (GameEngine::GenAssetFile()){ + if (GameEngine::GenAssetFile(false)){ GameEngine::ShowMessage("Success", "Audio assets installed. Changes will be applied on the next startup.", SDL_MESSAGEBOX_INFORMATION); - Ship::Context::GetInstance()->GetWindow()->Close(); } + Ship::Context::GetInstance()->GetWindow()->Close(); } } ImGui::EndMenu(); From 0c2752d11a6464f304e3712d2166a0778212aa20 Mon Sep 17 00:00:00 2001 From: Spodi Date: Sun, 25 May 2025 19:15:22 +0200 Subject: [PATCH 26/28] Fix versioning (Bump to Barnard Bravo) (#203) * fix versioning * PROJECT_TEAM "Lywx & YoshiCrystal" only on Switch --- CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ba3f194..37f97a4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.16.0 FATAL_ERROR) # Set the project version and language -project(Starship VERSION 0.1.0 LANGUAGES C CXX ASM) +project(Starship VERSION 2.0.1 LANGUAGES C CXX ASM) include(FetchContent) set(NATO_PHONETIC_ALPHABET @@ -19,6 +19,10 @@ list(GET NATO_PHONETIC_ALPHABET ${PATCH_INDEX} PROJECT_PATCH_WORD) set(PROJECT_BUILD_NAME "Barnard ${PROJECT_PATCH_WORD}" CACHE STRING "" FORCE) set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "" FORCE) +# Set a different team/company for Switch +if (CMAKE_SYSTEM_NAME STREQUAL "NintendoSwitch") + set(PROJECT_TEAM "Lywx & YoshiCrystal" CACHE STRING "" FORCE) +endif() if(APPLE) enable_language(OBJCXX) @@ -30,10 +34,6 @@ set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment ve # Set the C++ standard and enable the MSVC parallel build option set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use") set(CMAKE_C_STANDARD 11 CACHE STRING "The C standard to use") -set(PROJECT_TEAM "Lywx & YoshiCrystal") -set(PROJECT_VERSION_MAJOR 2) -set(PROJECT_VERSION_MINOR 0) -set(PROJECT_VERSION_PATCH 0) #add_compile_options(-fsanitize=address) #add_link_options(-fsanitize=address) From 0d3bc18c72cc8c8e2ebae086757fad5f2fbc4fec Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sun, 25 May 2025 14:16:19 -0300 Subject: [PATCH 27/28] . --- CMakeLists.txt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 37f97a4b..8e51ac34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,11 +18,7 @@ math(EXPR PATCH_INDEX "${PROJECT_VERSION_PATCH}") list(GET NATO_PHONETIC_ALPHABET ${PATCH_INDEX} PROJECT_PATCH_WORD) set(PROJECT_BUILD_NAME "Barnard ${PROJECT_PATCH_WORD}" CACHE STRING "" FORCE) -set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "" FORCE) -# Set a different team/company for Switch -if (CMAKE_SYSTEM_NAME STREQUAL "NintendoSwitch") - set(PROJECT_TEAM "Lywx & YoshiCrystal" CACHE STRING "" FORCE) -endif() +set(PROJECT_TEAM "SonicDcer & Lywx" CACHE STRING "" FORCE) if(APPLE) enable_language(OBJCXX) From 8fffcdb5577a22d5ad4f761bcbdf1ad0468c3450 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Sun, 25 May 2025 15:30:10 -0300 Subject: [PATCH 28/28] add floor interpolation to the ending floor --- src/overlays/ovl_ending/fox_end2.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/overlays/ovl_ending/fox_end2.c b/src/overlays/ovl_ending/fox_end2.c index 43d88173..8ca480af 100644 --- a/src/overlays/ovl_ending/fox_end2.c +++ b/src/overlays/ovl_ending/fox_end2.c @@ -458,8 +458,24 @@ void Ending_8018EDB8(u32 arg0, AssetInfo* asset) { gDPLoadTextureBlock(gMasterDisp++, D_END_700EA38, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 5, 5, G_TX_NOLOD, G_TX_NOLOD); - gDPSetupTile(gMasterDisp++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32, arg0 * 14, 0, G_TX_NOMIRROR | G_TX_WRAP, - G_TX_NOMIRROR | G_TX_WRAP, 5, 5, G_TX_NOLOD, G_TX_NOLOD); + int interpolatedFrames = GameEngine_GetInterpolationFrameCount(); + + float scrollArg = arg0 * 14; + float inc = 14 / (float) interpolatedFrames; + + for (int i = 0; i < interpolatedFrames; i++) { + gDPSetInterpolation(gMasterDisp++, i); + + gDPSetupTile2(gMasterDisp++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32, scrollArg, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, 5, 5, G_TX_NOLOD, G_TX_NOLOD); + + gDPSetTileSizeInterp(gMasterDisp, G_TX_RENDERTILE, scrollArg, 0, 32 << 2, 0); + + gMasterDisp += 3; + + scrollArg += inc; + } + gSPDisplayList(gMasterDisp++, D_END_700E9E0); }