From 5395eb1b53e2f3175030c5db67ab3f8c30a7c18a Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sat, 28 Feb 2026 13:16:02 -0700 Subject: [PATCH 1/3] Some TARGET_PC fixes --- include/dolphin/os.h | 1 + src/JSystem/JUtility/JUTException.cpp | 4 +-- src/SSystem/SComponent/c_cc_d.cpp | 1 + src/SSystem/SComponent/c_cc_s.cpp | 3 +- src/d/actor/d_a_npc_bouS.cpp | 52 +++++++++++++-------------- src/d/actor/d_a_npc_theB.cpp | 52 +++++++++++++-------------- src/d/actor/d_a_obj_gb.cpp | 8 +++++ src/d/actor/d_a_obj_tp.cpp | 8 +++++ src/d/d_camera.cpp | 6 ++-- src/d/d_menu_calibration.cpp | 4 +++ src/dusk/stubs.cpp | 6 ++++ 11 files changed, 87 insertions(+), 58 deletions(-) diff --git a/include/dolphin/os.h b/include/dolphin/os.h index ef23b716ff..de27e1390e 100644 --- a/include/dolphin/os.h +++ b/include/dolphin/os.h @@ -2,6 +2,7 @@ #define _DOLPHIN_OS_H_ #include +#include #ifdef __REVOLUTION_SDK__ #include diff --git a/src/JSystem/JUtility/JUTException.cpp b/src/JSystem/JUtility/JUTException.cpp index d8930a478d..a0e97736f7 100644 --- a/src/JSystem/JUtility/JUTException.cpp +++ b/src/JSystem/JUtility/JUTException.cpp @@ -209,9 +209,9 @@ void JUTException::setFPException(u32 fpscr_enable_bits) { #define __signbit(x) ((*(unsigned char*)&(x)) & 0x80) void JUTException::showFloatSub(int index, f32 value) { - if (isnan(value)) { + if (std::isnan(value)) { sConsole->print_f("F%02d: Nan ", index); - } else if (isinf(value)) { + } else if (std::isinf(value)) { if (__signbit(value)) { sConsole->print_f("F%02d:+Inf ", index); } else { diff --git a/src/SSystem/SComponent/c_cc_d.cpp b/src/SSystem/SComponent/c_cc_d.cpp index 7c57b18e0e..5326338602 100644 --- a/src/SSystem/SComponent/c_cc_d.cpp +++ b/src/SSystem/SComponent/c_cc_d.cpp @@ -5,6 +5,7 @@ #include "SSystem/SComponent/c_cc_d.h" #include "JSystem/JUtility/JUTAssert.h" +#include #define CHECK_FLOAT_RANGE(line, x) JUT_ASSERT(line, -1.0e32f < x && x < 1.0e32f); diff --git a/src/SSystem/SComponent/c_cc_s.cpp b/src/SSystem/SComponent/c_cc_s.cpp index 5fdd9ea1f8..2690d49dbc 100644 --- a/src/SSystem/SComponent/c_cc_s.cpp +++ b/src/SSystem/SComponent/c_cc_s.cpp @@ -5,8 +5,9 @@ #include "SSystem/SComponent/c_cc_s.h" #include "JSystem/JUtility/JUTAssert.h" +#include -#define CHECK_FLOAT_CLASS(line, x) JUT_ASSERT(line, !isnan(x)); +#define CHECK_FLOAT_CLASS(line, x) JUT_ASSERT(line, !std::isnan(x)); #define CHECK_FLOAT_RANGE(line, x) JUT_ASSERT(line, -1.0e32f < x && x < 1.0e32f); cCcS::cCcS() {} diff --git a/src/d/actor/d_a_npc_bouS.cpp b/src/d/actor/d_a_npc_bouS.cpp index 991eb7ce85..8d392b0bd1 100644 --- a/src/d/actor/d_a_npc_bouS.cpp +++ b/src/d/actor/d_a_npc_bouS.cpp @@ -1360,22 +1360,22 @@ int daNpcBouS_c::EvCut_BousIntroSumo1(int i_staffId) { if (eventManager.getIsAddvance(i_staffId)) { switch (*cutName) { - case MULTI_CHAR('0x0001'): + case MULTI_CHAR('0001'): setLookMode(LOOK_PLAYER_TALK); mActorMngrs[0].entry(daPy_getPlayerActorClass()); break; - case MULTI_CHAR('0x0002'): - case MULTI_CHAR('0x0003'): - case MULTI_CHAR('0x0005'): - case MULTI_CHAR('0x0006'): - case MULTI_CHAR('0x0007'): - case MULTI_CHAR('0x0008'): - case MULTI_CHAR('0x0009'): + case MULTI_CHAR('0002'): + case MULTI_CHAR('0003'): + case MULTI_CHAR('0005'): + case MULTI_CHAR('0006'): + case MULTI_CHAR('0007'): + case MULTI_CHAR('0008'): + case MULTI_CHAR('0009'): initTalk(9, NULL); break; - case MULTI_CHAR('0x0004'): + case MULTI_CHAR('0004'): setExpressionAnm(ANM_FH_TALK_B, true); break; @@ -1396,17 +1396,17 @@ int daNpcBouS_c::EvCut_BousIntroSumo1(int i_staffId) { } switch (*cutName) { - case MULTI_CHAR('0x0001'): - case MULTI_CHAR('0x0004'): + case MULTI_CHAR('0001'): + case MULTI_CHAR('0004'): return 1; - case MULTI_CHAR('0x0002'): - case MULTI_CHAR('0x0003'): - case MULTI_CHAR('0x0005'): - case MULTI_CHAR('0x0006'): - case MULTI_CHAR('0x0007'): - case MULTI_CHAR('0x0008'): - case MULTI_CHAR('0x0009'): + case MULTI_CHAR('0002'): + case MULTI_CHAR('0003'): + case MULTI_CHAR('0005'): + case MULTI_CHAR('0006'): + case MULTI_CHAR('0007'): + case MULTI_CHAR('0008'): + case MULTI_CHAR('0009'): if (talkProc(NULL, TRUE, NULL)) { s32 choiceNo = mFlow.getChoiceNo(); OS_REPORT("二択分岐 %s\n", choiceNo == 0 ? "はい" : "いいえ"); @@ -1434,7 +1434,7 @@ int daNpcBouS_c::EvCut_BousIntroSumo2(int i_staffId) { if (eventManager.getIsAddvance(i_staffId)) { switch (*cutName) { - case MULTI_CHAR('0x0001'): + case MULTI_CHAR('0001'): initTalk(9, NULL); setLookMode(LOOK_PLAYER_TALK); mActorMngrs[0].entry(daPy_getPlayerActorClass()); @@ -1456,7 +1456,7 @@ int daNpcBouS_c::EvCut_BousIntroSumo2(int i_staffId) { } switch (*cutName) { - case MULTI_CHAR('0x0001'): + case MULTI_CHAR('0001'): if (mCurAngle.y == fopAcM_searchPlayerAngleY(this)) { if (talkProc(NULL, TRUE, NULL)) { int choiceNo = mFlow.getChoiceNo(); @@ -1489,15 +1489,15 @@ int daNpcBouS_c::EvCut_BousIntroSumo3(int i_staffId) { if (eventManager.getIsAddvance(i_staffId)) { switch (*cutName) { - case MULTI_CHAR('0x0001'): + case MULTI_CHAR('0001'): setLookMode(LOOK_PLAYER_TALK); mActorMngrs[0].entry(daPy_getPlayerActorClass()); break; - case MULTI_CHAR('0x0003'): + case MULTI_CHAR('0003'): setMotion(MOT_WALK, -1.0f, 0); // fallthrough - case MULTI_CHAR('0x0002'): + case MULTI_CHAR('0002'): setAngle(-0x2AAA); initTalk(9, NULL); break; @@ -1521,16 +1521,16 @@ int daNpcBouS_c::EvCut_BousIntroSumo3(int i_staffId) { } switch (*cutName) { - case MULTI_CHAR('0x0001'): + case MULTI_CHAR('0001'): return 1; - case MULTI_CHAR('0x0002'): + case MULTI_CHAR('0002'): if (talkProc(NULL, TRUE, NULL)) { return 1; } break; - case MULTI_CHAR('0x0003'): { + case MULTI_CHAR('0003'): { cXyz* pos = dComIfGp_evmng_getMyXyzP(i_staffId, "pos"); if (pos != NULL) { if (cLib_chaseAngleS(&shape_angle.y, cLib_targetAngleY(¤t.pos, pos), 0x100)) { diff --git a/src/d/actor/d_a_npc_theB.cpp b/src/d/actor/d_a_npc_theB.cpp index 3a01c9bd7c..d6bb93c6d0 100644 --- a/src/d/actor/d_a_npc_theB.cpp +++ b/src/d/actor/d_a_npc_theB.cpp @@ -1176,10 +1176,10 @@ int daNpcTheB_c::EvCut_PersonalCombatIntro(int i_staffId) { if (eventManager.getIsAddvance(i_staffId)) { switch (*cutName) { - case MULTI_CHAR('0x0001'): + case MULTI_CHAR('0001'): break; - case MULTI_CHAR('0x0002'): + case MULTI_CHAR('0002'): initTalk(0x16, NULL); setLookMode(LOOK_PLAYER); mActorMngrs[0].entry(daPy_getPlayerActorClass()); @@ -1204,10 +1204,10 @@ int daNpcTheB_c::EvCut_PersonalCombatIntro(int i_staffId) { } switch (*cutName) { - case MULTI_CHAR('0x0001'): + case MULTI_CHAR('0001'): return 1; - case MULTI_CHAR('0x0002'): + case MULTI_CHAR('0002'): if (talkProc(NULL, TRUE, NULL)) { dComIfGs_onSaveDunSwitch(52); dComIfGs_onSaveDunSwitch(53); @@ -1229,7 +1229,7 @@ int daNpcTheB_c::EvCut_PersonalCombatRevenge(int i_staffId) { if (eventManager.getIsAddvance(i_staffId)) { switch (*cutName) { - case MULTI_CHAR('0x0001'): { + case MULTI_CHAR('0001'): { fopAc_ac_c* actor_p = getEvtAreaTagP(5, 0); cXyz* pos = dComIfGp_evmng_getMyXyzP(i_staffId, "pos"); int* angle = dComIfGp_evmng_getMyIntegerP(i_staffId, "angle"); @@ -1248,13 +1248,13 @@ int daNpcTheB_c::EvCut_PersonalCombatRevenge(int i_staffId) { break; } - case MULTI_CHAR('0x0002'): + case MULTI_CHAR('0002'): initTalk(0x17, NULL); setLookMode(LOOK_PLAYER); mActorMngrs[0].entry(daPy_getPlayerActorClass()); break; - case MULTI_CHAR('0x0003'): + case MULTI_CHAR('0003'): break; default: @@ -1282,19 +1282,19 @@ int daNpcTheB_c::EvCut_PersonalCombatRevenge(int i_staffId) { } switch (*cutName) { - case MULTI_CHAR('0x0001'): + case MULTI_CHAR('0001'): if (getCoachSpeed() == 0.0f) { return 1; } break; - case MULTI_CHAR('0x0002'): + case MULTI_CHAR('0002'): if (talkProc(NULL, TRUE, NULL)) { return 1; } break; - case MULTI_CHAR('0x0003'): + case MULTI_CHAR('0003'): return 1; default: @@ -1411,7 +1411,7 @@ int daNpcTheB_c::EvCut_AnnulationFieldRace(int i_staffId) { if (eventManager.getIsAddvance(i_staffId)) { switch (*cutName) { - case MULTI_CHAR('0x0001'): + case MULTI_CHAR('0001'): if (startAndGoal_p != NULL) { startAndGoal_p->readyStartTimer(); } @@ -1424,7 +1424,7 @@ int daNpcTheB_c::EvCut_AnnulationFieldRace(int i_staffId) { } switch (*cutName) { - case MULTI_CHAR('0x0001'): + case MULTI_CHAR('0001'): if (startAndGoal_p != NULL && startAndGoal_p->isStartCheck()) { return 1; } @@ -1444,15 +1444,15 @@ int daNpcTheB_c::EvCut_TheBHint(int i_staffId) { if (eventManager.getIsAddvance(i_staffId)) { switch (*cutName) { - case MULTI_CHAR('0x0001'): + case MULTI_CHAR('0001'): setMotionAnm(ANM_SIT, 0.0f); break; - case MULTI_CHAR('0x0002'): + case MULTI_CHAR('0002'): initTalk(mHintMsgNo, NULL); break; - case MULTI_CHAR('0x0003'): { + case MULTI_CHAR('0003'): { cXyz pos; csXyz angle; daNpcF_getPlayerInfoFromPlayerList(field_0xe04, mRoomNo, pos, angle); @@ -1479,11 +1479,11 @@ int daNpcTheB_c::EvCut_TheBHint(int i_staffId) { } switch (*cutName) { - case MULTI_CHAR('0x0001'): - case MULTI_CHAR('0x0003'): + case MULTI_CHAR('0001'): + case MULTI_CHAR('0003'): return 1; - case MULTI_CHAR('0x0002'): + case MULTI_CHAR('0002'): if (talkProc(NULL, TRUE, NULL)) { mHintEvtFlag = 0; return 1; @@ -1504,22 +1504,22 @@ int daNpcTheB_c::EvCut_CoachGuardGameOver(int i_staffId) { if (eventManager.getIsAddvance(i_staffId)) { switch (*cutName) { - case MULTI_CHAR('0x0001'): + case MULTI_CHAR('0001'): Z2GetAudioMgr()->bgmStart(Z2BGM_GAME_OVER, 0, 0); break; - case MULTI_CHAR('0x0002'): { + case MULTI_CHAR('0002'): { daNpcCoach_c* coach_p = (daNpcCoach_c*)fopAcM_SearchByID(parentActorID); cXyz pos(0.0f, -30000.0f, 0.0f); coach_p->setPosAngle(pos, shape_angle); break; } - case MULTI_CHAR('0x0003'): + case MULTI_CHAR('0003'): ((daCoach2D_c*)fpcM_SearchByName(PROC_COACH2D))->hide(); break; - case MULTI_CHAR('0x0004'): + case MULTI_CHAR('0004'): break; default: @@ -1529,12 +1529,12 @@ int daNpcTheB_c::EvCut_CoachGuardGameOver(int i_staffId) { } switch (*cutName) { - case MULTI_CHAR('0x0001'): - case MULTI_CHAR('0x0002'): - case MULTI_CHAR('0x0003'): + case MULTI_CHAR('0001'): + case MULTI_CHAR('0002'): + case MULTI_CHAR('0003'): return 1; - case MULTI_CHAR('0x0004'): + case MULTI_CHAR('0004'): daPy_getPlayerActorClass()->onForceGameOver(); return 1; diff --git a/src/d/actor/d_a_obj_gb.cpp b/src/d/actor/d_a_obj_gb.cpp index 238099a0f6..3cea630896 100644 --- a/src/d/actor/d_a_obj_gb.cpp +++ b/src/d/actor/d_a_obj_gb.cpp @@ -110,7 +110,11 @@ static int bmd[2] = { 6, 7, }; +#ifdef TARGET_PC +static int brk_res[2] = { +#else static int brk[2] = { +#endif 10, 11, }; @@ -144,7 +148,11 @@ static int useHeapInit(fopAc_ac_c* actor) { return 0; } J3DAnmTevRegKey* anmTevKey = (J3DAnmTevRegKey*)dComIfG_getObjectRes( +#ifdef TARGET_PC + "Obj_gb", brk_res[i_this->field_0x57c]); +#else "Obj_gb", brk[i_this->field_0x57c]); +#endif if (i_this->mBrk->init(i_this->mModel->getModelData(), anmTevKey, 1, 2, 0.0f, 0, -1) == 0) { return 0; } diff --git a/src/d/actor/d_a_obj_tp.cpp b/src/d/actor/d_a_obj_tp.cpp index 4a8eccd9da..86b21b28b8 100644 --- a/src/d/actor/d_a_obj_tp.cpp +++ b/src/d/actor/d_a_obj_tp.cpp @@ -292,7 +292,11 @@ static int bmd[2] = { 0x11, 0x12, }; +#ifdef TARGET_PC +static int brk_res[2] = { +#else static int brk[2] = { +#endif 0x17, 0x18, }; @@ -337,7 +341,11 @@ static int useHeapInit(fopAc_ac_c* i_this) { if (tp->mBrk == NULL) { return 0; } +#ifdef TARGET_PC + J3DAnmTevRegKey* regKey = (J3DAnmTevRegKey*)dComIfG_getObjectRes("Obj_tp", brk_res[tp->field_0x594]); +#else J3DAnmTevRegKey* regKey = (J3DAnmTevRegKey*)dComIfG_getObjectRes("Obj_tp", brk[tp->field_0x594]); +#endif J3DModelData* modelData = tp->mMorf->getModel()->getModelData(); if (!tp->mBrk->init( modelData, diff --git a/src/d/d_camera.cpp b/src/d/d_camera.cpp index cd2c187a20..bff30461ab 100644 --- a/src/d/d_camera.cpp +++ b/src/d/d_camera.cpp @@ -10842,15 +10842,15 @@ static void store(camera_process_class* i_camera) { error = true; OS_REPORT("camera: ERROR: bad direction !!\n"); } - if (fovy < 0.0f || isnan(fovy)) { + if (fovy < 0.0f || std::isnan(fovy)) { error = true; OS_REPORT("camera: ERROR: bad fovy !!\n"); } - if (isnan(eye.x) || isnan(eye.y) || isnan(eye.z)) { + if (std::isnan(eye.x) || std::isnan(eye.y) || std::isnan(eye.z)) { error = true; OS_REPORT("camera: ERROR: bad eye !!\n"); } - if (isnan(center.x) || isnan(center.y) || isnan(center.z)) { + if (std::isnan(center.x) || std::isnan(center.y) || std::isnan(center.z)) { error = true; OS_REPORT("camera: ERROR: bad eye !!\n"); } diff --git a/src/d/d_menu_calibration.cpp b/src/d/d_menu_calibration.cpp index 72ec058eec..2db4e50948 100644 --- a/src/d/d_menu_calibration.cpp +++ b/src/d/d_menu_calibration.cpp @@ -21,7 +21,11 @@ public: virtual void virt_func_0() = 0; }; class dummy_child_class : dummy_abstract_class { +#ifdef TARGET_PC + virtual void virt_func_0() {} +#else virtual void virt_func_0(); +#endif }; static dummy_child_class dummy() { dummy_child_class temp; diff --git a/src/dusk/stubs.cpp b/src/dusk/stubs.cpp index 5fd5c376fc..4520362881 100644 --- a/src/dusk/stubs.cpp +++ b/src/dusk/stubs.cpp @@ -1864,3 +1864,9 @@ u32 JHICommBufReader::Header::getReadableSize() const { puts("JHICommBufReader::Header::getReadableSize is a stub"); return 0; } + +#pragma mark Decomp artifacts +void stripFloat(f32) {} +void stripDouble(f64) {} +int getStripInt() { return 0; } +void F(f32*) {} From 6340087698ecb898c4a67a6a31cf5120b6a2521a Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sat, 28 Feb 2026 13:16:20 -0700 Subject: [PATCH 2/3] Simplify CMake config for Linux --- CMakeLists.txt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index da6bc210cc..41f61c8df9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,7 @@ endif () set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) add_subdirectory(extern/aurora EXCLUDE_FROM_ALL) @@ -15,11 +16,7 @@ option(DUSK_BUILD_WARNINGS "If off, compiler warnings will be suppressed") if (CMAKE_SYSTEM_NAME STREQUAL Linux) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unknown-pragmas -Wno-unused-variable -Wno-unused-parameter") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wno-register -fPIC") - set(CMAKE_PREFIX_PATH /usr) - set(CMAKE_LIBRARY_ARCHITECTURE x86_64-linux-gnu) - set(CMAKE_LIBRARY_PATH "/usr/lib64" "/usr/lib/x86_64-linux-gnu" CACHE PATH "") - set(CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX 64) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-register") set(CMAKE_INSTALL_RPATH "$ORIGIN") set(CMAKE_BUILD_RPATH "$ORIGIN") elseif (APPLE) From f38dcf3aef63a78c747edcbb071971dd785e827d Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sat, 28 Feb 2026 13:16:42 -0700 Subject: [PATCH 3/3] Use `tls_model("global-dynamic")` for JKRHeap on GCC --- src/JSystem/JKernel/JKRHeap.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/JSystem/JKernel/JKRHeap.cpp b/src/JSystem/JKernel/JKRHeap.cpp index 6b9ec1e685..606ff3def9 100644 --- a/src/JSystem/JKernel/JKRHeap.cpp +++ b/src/JSystem/JKernel/JKRHeap.cpp @@ -31,7 +31,14 @@ JKRHeap* JKRHeap::sSystemHeap; #if TARGET_PC // JSystem normally has a thread switch callback to track the correct heap. // We can't do this as we're (currently) using true OS threads. So use a true thread local. -static thread_local JKRHeap* sCurrentHeap; +// On Linux/GCC, thread_local in a shared library requires global-dynamic TLS model +// (the default local-exec is incompatible with -fPIC). MSVC and macOS/Clang handle this automatically. +#if defined(__GNUC__) && !defined(__clang__) && !defined(_MSC_VER) +#define TLS_GLOBAL_DYNAMIC __attribute__((tls_model("global-dynamic"))) +#else +#define TLS_GLOBAL_DYNAMIC +#endif +static thread_local TLS_GLOBAL_DYNAMIC JKRHeap* sCurrentHeap; #else JKRHeap* JKRHeap::sCurrentHeap; #endif