From 5fcf1083d2269cb4b4da079afcd1653421e6fa71 Mon Sep 17 00:00:00 2001 From: Dominic Della Valle Date: Thu, 21 Dec 2023 15:01:56 -0500 Subject: [PATCH 01/68] ci: update GitHub actions `uses` deps to latest --- .github/workflows/c-cpp.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 86fe9c5c6..33c39e5b8 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -26,7 +26,7 @@ jobs: mingw-w64-i686-SDL2 mingw-w64-i686-zlib - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Build pd.exe run: make -f Makefile.port -j - name: Prepare artifact for packaging @@ -36,7 +36,7 @@ jobs: cp /mingw32/bin/{SDL2.dll,zlib1.dll,libgcc_s_dw2-1.dll,libwinpthread-1.dll} bin/ touch bin/data/put_your_rom_here.txt - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: pd-i686-windows path: bin/ @@ -51,7 +51,7 @@ jobs: sudo apt-get update sudo apt-get install git gcc g++ gcc-multilib g++-multilib make libsdl2-dev zlib1g-dev libsdl2-dev:i386 zlib1g-dev:i386 - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Build pd.exe run: make -f Makefile.port TARGET_PLATFORM=i686-linux -j2 - name: Prepare artifact for packaging @@ -60,7 +60,7 @@ jobs: cp build/ntsc-final-port/pd.exe bin/pd touch bin/data/put_your_rom_here.txt - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: pd-i686-linux path: bin/ From 2ef242741966c20e8f71d7d3a33a694ceeb8ff0d Mon Sep 17 00:00:00 2001 From: Dominic Della Valle Date: Thu, 21 Dec 2023 15:02:35 -0500 Subject: [PATCH 02/68] ci: publish builds to a release tag `ci-dev-build` This reserves the tag `ci-dev-build` for use by the CI. --- .github/workflows/c-cpp.yml | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 33c39e5b8..5a940b1a6 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -65,4 +65,25 @@ jobs: name: pd-i686-linux path: bin/ retention-days: 0 - + + publish-latest-build: + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/port' + needs: [build-i686-windows, build-i686-linux] + steps: + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 + with: + path: ci-artifacts + - name: Publish latest dev-build + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + mkdir ci-release + pushd ci-artifacts + tar czf ../ci-release/pd-i686-linux.tar.gz pd-i686-linux + zip -r ../ci-release/pd-i686-windows.zip pd-i686-windows + popd + git tag --force ci-dev-build port + git push --force origin ci-dev-build + gh release upload --clobber ci-dev-build ci-release/* From 1f4d9c8cdca4b9a29af0191b8764d7787a4c1abe Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Sat, 27 Jan 2024 02:51:34 +0100 Subject: [PATCH 03/68] Always hide crosshair when dead Previously, the crosshair would show up during the death animation if Always Show Target is enabled or if aiming just before dying. --- src/game/sight.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/game/sight.c b/src/game/sight.c index fb5f255ae..d8fb87007 100644 --- a/src/game/sight.c +++ b/src/game/sight.c @@ -1536,6 +1536,13 @@ Gfx *sightDraw(Gfx *gdl, bool sighton, s32 sight) sight = SIGHT_DEFAULT; } +#ifndef PLATFORM_N64 + if (g_Vars.currentplayer->bondhealth <= 0.0f) { + // Hide crosshair during death animation + sight = SIGHT_NONE; + } +#endif + sightTick(sighton); switch (sight) { From 02d7efb87fd1e88d0a164a03ea662f8799ce0284 Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Sat, 27 Jan 2024 02:32:09 +0100 Subject: [PATCH 04/68] Add an option to color crosshair according to player health + shield Shield is taken into account and is added to health for the calculation, as the vast majority of damage types are fully blocked by a shield. 3 modes are available: - Off (default) - On (Green): Goes through a red-yellow-green-cyan gradient, closer to vanilla. - On (White): Goes through a red-yellow-white-green gradient, closer to games like Xonotic. When set to either of the On modes, the crosshair color setting is ignored but the crosshair alpha setting is still used. --- port/src/main.c | 1 + port/src/optionsmenu.c | 32 +++++++++++++++++++++++++ src/game/mplayer/mplayer.c | 1 + src/game/sight.c | 48 +++++++++++++++++++++++++++++++++++++- src/include/constants.h | 4 ++++ src/include/types.h | 1 + 6 files changed, 86 insertions(+), 1 deletion(-) diff --git a/port/src/main.c b/port/src/main.c index 10150f7ae..901d2eef4 100644 --- a/port/src/main.c +++ b/port/src/main.c @@ -176,5 +176,6 @@ PD_CONSTRUCTOR static void gameConfigInit(void) configRegisterInt(strFmt("Game.Player%d.ExtendedControls", i), &g_PlayerExtCfg[j].extcontrols, 0, 1); configRegisterUInt(strFmt("Game.Player%d.CrosshairColour", i), &g_PlayerExtCfg[j].crosshaircolour, 0, 0xFFFFFFFF); configRegisterUInt(strFmt("Game.Player%d.CrosshairSize", i), &g_PlayerExtCfg[j].crosshairsize, 0, 4); + configRegisterInt(strFmt("Game.Player%d.CrosshairHealth", i), &g_PlayerExtCfg[j].crosshairhealth, 0, CROSSHAIR_HEALTH_ON_WHITE); } } diff --git a/port/src/optionsmenu.c b/port/src/optionsmenu.c index dd999bee4..e8085b564 100644 --- a/port/src/optionsmenu.c +++ b/port/src/optionsmenu.c @@ -1040,6 +1040,30 @@ static MenuItemHandlerResult menuhandlerCrosshairSize(s32 operation, struct menu return 0; } +static MenuItemHandlerResult menuhandlerCrosshairHealth(s32 operation, struct menuitem *item, union handlerdata *data) +{ + static const char *opts[] = { + "Off", + "On (Green)", + "On (White)" + }; + + switch (operation) { + case MENUOP_GETOPTIONCOUNT: + data->dropdown.value = ARRAYCOUNT(opts); + break; + case MENUOP_GETOPTIONTEXT: + return (intptr_t)opts[data->dropdown.value]; + case MENUOP_SET: + g_PlayerExtCfg[g_ExtMenuPlayer].crosshairhealth = data->dropdown.value; + break; + case MENUOP_GETSELECTEDINDEX: + data->dropdown.value = g_PlayerExtCfg[g_ExtMenuPlayer].crosshairhealth; + } + + return 0; +} + struct menuitem g_ExtendedGameCrosshairColourMenuItems[] = { { MENUITEMTYPE_SLIDER, @@ -1158,6 +1182,14 @@ struct menuitem g_ExtendedGameMenuItems[] = { 0, (void*)&g_ExtendedGameCrosshairColourMenuDialog, }, + { + MENUITEMTYPE_DROPDOWN, + 0, + MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"Crosshair Colour by Health", + 0, + menuhandlerCrosshairHealth, + }, { MENUITEMTYPE_SEPARATOR, 0, diff --git a/src/game/mplayer/mplayer.c b/src/game/mplayer/mplayer.c index 7246a418b..9aca1a2a2 100644 --- a/src/game/mplayer/mplayer.c +++ b/src/game/mplayer/mplayer.c @@ -124,6 +124,7 @@ struct mpweapon g_MpWeapons[NUM_MPWEAPONS] = { .extcontrols = true, \ .crosshaircolour = 0x00ff0028, \ .crosshairsize = 2, \ + .crosshairhealth = CROSSHAIR_HEALTH_OFF, \ } struct extplayerconfig g_PlayerExtCfg[MAX_PLAYERS] = { diff --git a/src/game/sight.c b/src/game/sight.c index fb5f255ae..34d6dac52 100644 --- a/src/game/sight.c +++ b/src/game/sight.c @@ -23,9 +23,55 @@ #include #include "video.h" -#define SIGHT_COLOUR PLAYER_EXTCFG().crosshaircolour +#define SIGHT_COLOUR ((PLAYER_EXTCFG().crosshairhealth >= CROSSHAIR_HEALTH_ON_GREEN) ? sightGetCrosshairHealthColor(g_Vars.currentplayer->bondhealth, g_Vars.currentplayer->prop->chr->cshield * 0.125f) : PLAYER_EXTCFG().crosshaircolour) #define SIGHT_SCALE PLAYER_EXTCFG().crosshairsize +static u32 sightGetCrosshairHealthColor(float health, float shield) +{ + const float ratio = MAX(0.0f, MIN(health + shield, 2.0f)); + + int red = 0; + int green = 0; + int blue = 0; + if (ratio < 0.2f) { + // Red (critical health level) + red = 255; + green = 0; + blue = 0; + } else if (ratio < 0.6f) { + // Red-yellow + red = 255; + green = 255 * ((ratio - 0.2f) / 0.4f); + blue = 0; + } else if (ratio < 1.0f) { + if (PLAYER_EXTCFG().crosshairhealth == CROSSHAIR_HEALTH_ON_GREEN) { + // Yellow-green + red = 255 * ((ratio - 0.6f) / 0.4f); + green = 255; + blue = 0; + } else { + // Yellow-white + red = 255; + green = 255; + blue = 255 * ((ratio - 0.6f) / 0.4f); + } + } else { + if (PLAYER_EXTCFG().crosshairhealth == CROSSHAIR_HEALTH_ON_GREEN) { + // Green-cyan (overheal via shield) + red = 0; + green = 255; + blue = 255 * (ratio - 1.0f); + } else { + // White-green (overheal via shield) + red = 255 * (2.0f - ratio); + green = 255; + blue = 255 * (2.0f - ratio); + } + } + + return (red << 24) + (green << 16) + (blue << 8) + (PLAYER_EXTCFG().crosshaircolour & 0xff); +} + static inline f32 sightGetScaleX(void) { return (videoGetAspect() / SCREEN_ASPECT); diff --git a/src/include/constants.h b/src/include/constants.h index 4c3705b7f..612138bcf 100644 --- a/src/include/constants.h +++ b/src/include/constants.h @@ -4718,6 +4718,10 @@ enum weaponnum { #define CROUCHMODE_TOGGLE 2 // press the crouch buttons to toggle stance #define CROUCHMODE_TOGGLE_ANALOG (CROUCHMODE_ANALOG | CROUCHMODE_TOGGLE) +#define CROSSHAIR_HEALTH_OFF 0 +#define CROSSHAIR_HEALTH_ON_GREEN 1 +#define CROSSHAIR_HEALTH_ON_WHITE 2 + #endif #endif diff --git a/src/include/types.h b/src/include/types.h index 2a0491896..0d772d798 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -6141,6 +6141,7 @@ struct extplayerconfig { s32 extcontrols; u32 crosshaircolour; u32 crosshairsize; + s32 crosshairhealth; }; #endif From 815c75c6a8dbc0e69553cc1d1a76b1fc70728a27 Mon Sep 17 00:00:00 2001 From: Adriano Bini Date: Mon, 29 Jan 2024 17:08:27 -0300 Subject: [PATCH 05/68] Add port-net/netplay build links to default README Some people are not being able to properly download/play because of Github's always defaulting to master's README.MD. This includes netplay links in the master branchg README as well. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d54b38e18..6636217c6 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,9 @@ though you might have to install some additional libraries. Latest [automatic builds](https://github.com/fgsfdsfgs/perfect_dark/actions) for supported platforms: * [i686-windows](https://nightly.link/fgsfdsfgs/perfect_dark/workflows/c-cpp/port/pd-i686-windows.zip) +* [i686-windows (port-net/netplay)](https://nightly.link/fgsfdsfgs/perfect_dark/workflows/c-cpp/port-net/pd-i686-windows.zip) * [i686-linux](https://nightly.link/fgsfdsfgs/perfect_dark/workflows/c-cpp/port/pd-i686-linux.zip) +* [i686-linux (port-net/netplay)](https://nightly.link/fgsfdsfgs/perfect_dark/workflows/c-cpp/port-net/pd-i686-linux.zip) ## Running From 36f8494ebfac04ccbf04ee7a8e7c89e0e600d2dc Mon Sep 17 00:00:00 2001 From: fgsfds Date: Mon, 29 Jan 2024 22:11:34 +0100 Subject: [PATCH 06/68] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6636217c6..3451264ff 100644 --- a/README.md +++ b/README.md @@ -42,9 +42,9 @@ though you might have to install some additional libraries. Latest [automatic builds](https://github.com/fgsfdsfgs/perfect_dark/actions) for supported platforms: * [i686-windows](https://nightly.link/fgsfdsfgs/perfect_dark/workflows/c-cpp/port/pd-i686-windows.zip) -* [i686-windows (port-net/netplay)](https://nightly.link/fgsfdsfgs/perfect_dark/workflows/c-cpp/port-net/pd-i686-windows.zip) * [i686-linux](https://nightly.link/fgsfdsfgs/perfect_dark/workflows/c-cpp/port/pd-i686-linux.zip) -* [i686-linux (port-net/netplay)](https://nightly.link/fgsfdsfgs/perfect_dark/workflows/c-cpp/port-net/pd-i686-linux.zip) + +If you are looking for netplay builds (the `port-net` branch), see [this link](https://github.com/fgsfdsfgs/perfect_dark/blob/port-net/README.md#download). ## Running From 935cd1faa9ab428f5e50dbe9090d06c32922ede8 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sat, 10 Feb 2024 14:07:20 +0100 Subject: [PATCH 07/68] port: gl: dump shader source when compilation fails --- port/fast3d/gfx_opengl.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/port/fast3d/gfx_opengl.cpp b/port/fast3d/gfx_opengl.cpp index 44c420e10..f8569a370 100644 --- a/port/fast3d/gfx_opengl.cpp +++ b/port/fast3d/gfx_opengl.cpp @@ -586,6 +586,7 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &max_length); char error_log[1024]; glGetShaderInfoLog(vertex_shader, max_length, &max_length, &error_log[0]); + sysLogPrintf(LOG_ERROR, "Failed to compile this vertex shader (ID %llx, %x):\n%s", shader_id0, shader_id1, vs_buf); sysFatalError("Vertex shader compilation failed:\n%s", error_log); } @@ -598,6 +599,7 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &max_length); char error_log[1024]; glGetShaderInfoLog(fragment_shader, max_length, &max_length, &error_log[0]); + sysLogPrintf(LOG_ERROR, "Failed to compile this fragment shader (ID %llx, %x):\n%s", shader_id0, shader_id1, fs_buf); sysFatalError("Fragment shader compilation failed:\n%s", error_log); } From fe0d9b3cfdd7acf3e7bfc615d4277f8ddd633c20 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sat, 10 Feb 2024 16:56:54 +0100 Subject: [PATCH 08/68] port: fix blur shader on some older cards --- port/fast3d/gfx_opengl.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/port/fast3d/gfx_opengl.cpp b/port/fast3d/gfx_opengl.cpp index f8569a370..86efd96bc 100644 --- a/port/fast3d/gfx_opengl.cpp +++ b/port/fast3d/gfx_opengl.cpp @@ -397,19 +397,14 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad if (cc_features.opt_blur) { // blur filter, used for menu backgrounds // used to be two for loops from 0 to 4, but apparently intel drivers crashed trying to unroll it + // used to have a const weight array, but apparently drivers for the GT620 don't like const array initializers append_line(fs_buf, &fs_len, R"( - const lowp float blurWeights[16] = float[16]( - 0.009947, 0.009641, 0.008778, 0.007509, - 0.009641, 0.009345, 0.008508, 0.007278, - 0.008778, 0.008508, 0.007747, 0.006626, - 0.007509, 0.007278, 0.006626, 0.005668 - ); lowp vec4 hookTexture2D(in sampler2D t, in vec2 uv, in vec2 tsize) { lowp vec4 cw = vec4(0.0); for (int i = 0; i < 16; ++i) { vec2 xy = vec2(float(i & 3), float(i >> 2)); - vec2 ofs = (vec2(-1.5) + xy) / tsize; - cw += vec4(texture2D(t, uv + ofs).rgb * blurWeights[i], blurWeights[i]); + lowp float w = 0.009947 - length(xy) * 0.001; + cw += vec4(texture2D(t, uv + (vec2(-1.5) + xy) / tsize).rgb * w, w); } return vec4(cw.rgb / cw.a, 1.0); })" From 839143550fb10a35ecabe64b235f6d1cee2cb71a Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 13 Feb 2024 01:16:57 +0100 Subject: [PATCH 09/68] port: fix potential crash in handInflictMeleeDamage pointers can be little endian, so there might be a problem --- src/game/prop.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/game/prop.c b/src/game/prop.c index 786a64db1..92505fa3a 100644 --- a/src/game/prop.c +++ b/src/game/prop.c @@ -1170,7 +1170,11 @@ void handInflictMeleeDamage(s32 handnum, struct gset *gset, bool arg2) bool isglass = false; if (obj && gset->weaponnum != WEAPON_TRANQUILIZER) { - isglass = obj->type == OBJTYPE_GLASS || obj->type == OBJTYPE_TINTEDGLASS; + isglass = +#ifdef AVOID_UB + (prop->type == PROPTYPE_OBJ) && +#endif + (obj->type == OBJTYPE_GLASS || obj->type == OBJTYPE_TINTEDGLASS); } if (arg2) { From d11b5705a2198ed015f067b654101b145b95ec99 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sat, 9 Mar 2024 17:03:06 +0100 Subject: [PATCH 10/68] port: add missing configRegisterUInt decl --- port/include/config.h | 1 + 1 file changed, 1 insertion(+) diff --git a/port/include/config.h b/port/include/config.h index 5bc12cf11..154745454 100644 --- a/port/include/config.h +++ b/port/include/config.h @@ -16,5 +16,6 @@ s32 configSave(const char *fname); // registers a variable in the config file // this should be done before configInit() is called, preferably in a module constructor void configRegisterInt(const char *key, s32 *var, s32 min, s32 max); +void configRegisterUInt(const char* key, u32* var, u32 min, u32 max); void configRegisterFloat(const char *key, f32 *var, f32 min, f32 max); void configRegisterString(const char *key, char *var, u32 maxstr); From 4baae8de0b1f49fde03f9ec3c5ec522965a4efb1 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sat, 9 Mar 2024 17:39:41 +0100 Subject: [PATCH 11/68] port: add extra sleep calls to busy loops; separate sleep into system.c --- port/fast3d/gfx_sdl2.cpp | 55 ++-------------------------------- port/include/system.h | 6 ++++ port/src/main.c | 2 ++ port/src/pdmain.c | 4 +++ port/src/system.c | 64 ++++++++++++++++++++++++++++++++++++++++ src/game/timing.c | 9 ++++++ src/include/constants.h | 2 ++ src/include/data.h | 1 + 8 files changed, 90 insertions(+), 53 deletions(-) diff --git a/port/fast3d/gfx_sdl2.cpp b/port/fast3d/gfx_sdl2.cpp index 8e9dcfaf7..bd6e4def7 100644 --- a/port/fast3d/gfx_sdl2.cpp +++ b/port/fast3d/gfx_sdl2.cpp @@ -9,24 +9,6 @@ #include "gfx_window_manager_api.h" #include "gfx_screen_config.h" -// define a way to yield the cpu when in a busy wait -#ifdef PLATFORM_WIN32 -// winapi provides a yield macro -#include -#define DO_YIELD() YieldProcessor() -#elif defined(PLATFORM_X86) || defined(PLATFORM_X86_64) -// this should work even if the code is not built with SSE enabled, at least on gcc and clang, -// but if it doesn't we'll have to use __builtin_ia32_pause() or something -#include -#define DO_YIELD() _mm_pause() -#elif defined(PLATFORM_ARM) -// same as YieldProcessor() on ARM Windows -#define DO_YIELD() __asm__ volatile("dmb ishst\n\tyield":::"memory") -#else -// fuck it -#define DO_YIELD() do { } while (0) -#endif - static SDL_Window* wnd; static SDL_GLContext ctx; static SDL_Renderer* renderer; @@ -44,28 +26,9 @@ static int target_fps = 120; // above 60 since vsync is enabled by default static uint64_t previous_time; static uint64_t qpc_freq; -#ifdef PLATFORM_WIN32 -// on win32 we use waitable timers instead of nanosleep -typedef HANDLE WINAPI (*CREATEWAITABLETIMEREXAFN)(LPSECURITY_ATTRIBUTES, LPCSTR, DWORD, DWORD); -static HANDLE timer; -static CREATEWAITABLETIMEREXAFN pfnCreateWaitableTimerExA; -#endif - #define FRAME_INTERVAL_US_NUMERATOR 1000000 #define FRAME_INTERVAL_US_DENOMINATOR (target_fps) -static inline void do_sleep(const int64_t left) { -#ifdef PLATFORM_WIN32 - static LARGE_INTEGER li; - li.QuadPart = -left; - SetWaitableTimer(timer, &li, 0, nullptr, nullptr, false); - WaitForSingleObject(timer, INFINITE); -#else - const timespec spec = { 0, left * 100 }; - nanosleep(&spec, nullptr); -#endif -} - static void set_fullscreen(bool on, bool call_callback) { if (fullscreen_state == on) { return; @@ -181,20 +144,6 @@ static void gfx_sdl_init(const char* game_name, const char* gfx_api_name, bool s qpc_freq = SDL_GetPerformanceFrequency(); -#ifdef PLATFORM_WIN32 - // this function is only present on Vista+, so try to import it from kernel32 by hand - pfnCreateWaitableTimerExA = (CREATEWAITABLETIMEREXAFN)GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateWaitableTimerExA"); - if (pfnCreateWaitableTimerExA) { - // function exists, try to create a hires timer - timer = pfnCreateWaitableTimerExA(nullptr, nullptr, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); - } - if (!timer) { - // no function or hires timers not supported, fallback to lower resolution timer - sysLogPrintf(LOG_WARNING, "SDL: hires waitable timers not available"); - timer = CreateWaitableTimerA(nullptr, false, nullptr); - } -#endif - set_maximize_window(start_maximized); set_fullscreen(start_in_fullscreen, false); } @@ -272,11 +221,11 @@ static inline void sync_framerate_with_timer(void) { // We want to exit a bit early, so we can busy-wait the rest to never miss the deadline left -= 15000UL; if (left > 0) { - do_sleep(left); + sysSleep(left); } do { - DO_YIELD(); + sysCpuRelax(); t = qpc_to_100ns(SDL_GetPerformanceCounter()); } while ((int64_t)t < next); diff --git a/port/include/system.h b/port/include/system.h index 94158802a..84d568382 100644 --- a/port/include/system.h +++ b/port/include/system.h @@ -34,6 +34,12 @@ void *sysMemAlloc(const u32 size); void *sysMemZeroAlloc(const u32 size); void sysMemFree(void *ptr); +// hns is specified in 100ns units +void sysSleep(const s64 hns); + +// yield CPU if supported (e.g. during a busy loop) +void sysCpuRelax(void); + void crashInit(void); void crashShutdown(void); diff --git a/port/src/main.c b/port/src/main.c index 901d2eef4..fa39ff518 100644 --- a/port/src/main.c +++ b/port/src/main.c @@ -36,6 +36,7 @@ u32 g_VmNumPageReplaces = 0; u8 g_VmShowStats = 0; s32 g_TickRateDiv = 1; +s32 g_TickExtraSleep = true; s32 g_SkipIntro = false; @@ -160,6 +161,7 @@ PD_CONSTRUCTOR static void gameConfigInit(void) configRegisterInt("Game.CenterHUD", &g_HudCenter, 0, 2); configRegisterFloat("Game.ScreenShakeIntensity", &g_ViShakeIntensityMult, 0.f, 10.f); configRegisterInt("Game.TickRateDivisor", &g_TickRateDiv, 0, 10); + configRegisterInt("Game.ExtraSleep", &g_TickExtraSleep, 0, 1); configRegisterInt("Game.SkipIntro", &g_SkipIntro, 0, 1); configRegisterInt("Game.DisableMpDeathMusic", &g_MusicDisableMpDeath, 0, 1); configRegisterInt("Game.GEMuzzleFlashes", &g_BgunGeMuzzleFlashes, 0, 1); diff --git a/port/src/pdmain.c b/port/src/pdmain.c index 77c031800..2cd9baffb 100644 --- a/port/src/pdmain.c +++ b/port/src/pdmain.c @@ -72,6 +72,7 @@ #include "lib/str.h" #include "data.h" #include "types.h" +#include "system.h" extern u8 *g_MempHeap; extern u32 g_MempHeapSize; @@ -499,6 +500,9 @@ void mainLoop(void) mainTick(); schedEndFrame(&g_Sched); } + if (g_TickExtraSleep) { + sysSleep(EXTRA_SLEEP_TIME); + } } lvStop(); diff --git a/port/src/system.c b/port/src/system.c index 538dd1e87..b3c9948cb 100644 --- a/port/src/system.c +++ b/port/src/system.c @@ -10,6 +10,38 @@ #include "platform.h" #include "system.h" +#ifdef PLATFORM_WIN32 + +#include + +// on win32 we use waitable timers instead of nanosleep +typedef HANDLE WINAPI (*CREATEWAITABLETIMEREXAFN)(LPSECURITY_ATTRIBUTES, LPCSTR, DWORD, DWORD); +static HANDLE timer; +static CREATEWAITABLETIMEREXAFN pfnCreateWaitableTimerExA; + +// winapi also provides a yield macro +#define DO_YIELD() YieldProcessor() + +#else + +#include + +// figure out how to yield +#if defined(PLATFORM_X86) || defined(PLATFORM_X86_64) +// this should work even if the code is not built with SSE enabled, at least on gcc and clang, +// but if it doesn't we'll have to use __builtin_ia32_pause() or something +#include +#define DO_YIELD() _mm_pause() +#elif defined(PLATFORM_ARM) +// same as YieldProcessor() on ARM Windows +#define DO_YIELD() __asm__ volatile("dmb ishst\n\tyield":::"memory") +#else +// fuck it +#define DO_YIELD() do { } while (0) +#endif + +#endif + #define LOG_FNAME "pd.log" #define CRASHLOG_FNAME "pd.crash.log" #define USEC_IN_SEC 1000000ULL @@ -60,6 +92,20 @@ void sysInit(void) const time_t curtime = time(NULL); strftime(timestr, sizeof(timestr), "%d %b %Y %H:%M:%S", localtime(&curtime)); sysLogPrintf(LOG_NOTE, "startup date: %s", timestr); + +#ifdef PLATFORM_WIN32 + // this function is only present on Vista+, so try to import it from kernel32 by hand + pfnCreateWaitableTimerExA = (CREATEWAITABLETIMEREXAFN)GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateWaitableTimerExA"); + if (pfnCreateWaitableTimerExA) { + // function exists, try to create a hires timer + timer = pfnCreateWaitableTimerExA(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); + } + if (!timer) { + // no function or hires timers not supported, fallback to lower resolution timer + sysLogPrintf(LOG_WARNING, "SYS: hires waitable timers not available"); + timer = CreateWaitableTimerA(NULL, FALSE, NULL); + } +#endif } s32 sysArgCheck(const char *arg) @@ -238,3 +284,21 @@ void sysMemFree(void *ptr) { free(ptr); } + +void sysSleep(const s64 hns) +{ +#ifdef PLATFORM_WIN32 + static LARGE_INTEGER li; + li.QuadPart = -hns; + SetWaitableTimer(timer, &li, 0, NULL, NULL, FALSE); + WaitForSingleObject(timer, INFINITE); +#else + const timespec spec = { 0, hns * 100 }; + nanosleep(&spec, NULL); +#endif +} + +void sysCpuRelax(void) +{ + DO_YIELD(); +} diff --git a/src/game/timing.c b/src/game/timing.c index 9a7c8e380..747c7ed24 100644 --- a/src/game/timing.c +++ b/src/game/timing.c @@ -4,6 +4,9 @@ #include "bss.h" #include "data.h" #include "types.h" +#ifndef PLATFORM_N64 +#include "system.h" +#endif void frametimeInit(void) { @@ -41,6 +44,12 @@ void frametimeCalculate(void) diffframe60 = (g_Vars.lostframetime60t + diffframet + CYCLES_PER_FRAME / 2) / CYCLES_PER_FRAME; diffframe240 = (g_Vars.lostframetime240t + diffframet + CYCLES_PER_FRAME / 2 / 4) / (CYCLES_PER_FRAME / 4); + +#ifndef PLATFORM_N64 + if (g_TickExtraSleep) { + sysSleep(EXTRA_SLEEP_TIME); + } +#endif } while (g_Vars.mininc60 && diffframe60 < g_Vars.mininc60); g_Vars.lostframetime60t = g_Vars.lostframetime60t + diffframet - diffframe60 * CYCLES_PER_FRAME; diff --git a/src/include/constants.h b/src/include/constants.h index 612138bcf..cbb8ec344 100644 --- a/src/include/constants.h +++ b/src/include/constants.h @@ -4722,6 +4722,8 @@ enum weaponnum { #define CROSSHAIR_HEALTH_ON_GREEN 1 #define CROSSHAIR_HEALTH_ON_WHITE 2 +#define EXTRA_SLEEP_TIME 1000LL // 100us + #endif #endif diff --git a/src/include/data.h b/src/include/data.h index e513c6f10..c59d6ba99 100644 --- a/src/include/data.h +++ b/src/include/data.h @@ -547,6 +547,7 @@ extern s32 g_BlurFb; extern s32 g_BlurFbCapTimer; extern bool g_BlurFbDirty; extern s32 g_TickRateDiv; +extern s32 g_TickExtraSleep; extern s32 g_MusicDisableMpDeath; extern s32 g_BgunGeMuzzleFlashes; extern s32 g_FileAutoSelect; From 92a9ac43fc9e8bb7c0ba5c0fe5f1260c66ea6d6b Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sat, 9 Mar 2024 17:45:27 +0100 Subject: [PATCH 12/68] port: fix linux build --- port/src/system.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/port/src/system.c b/port/src/system.c index b3c9948cb..e889f75df 100644 --- a/port/src/system.c +++ b/port/src/system.c @@ -24,6 +24,10 @@ static CREATEWAITABLETIMEREXAFN pfnCreateWaitableTimerExA; #else +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + #include // figure out how to yield @@ -293,7 +297,7 @@ void sysSleep(const s64 hns) SetWaitableTimer(timer, &li, 0, NULL, NULL, FALSE); WaitForSingleObject(timer, INFINITE); #else - const timespec spec = { 0, hns * 100 }; + const struct timespec spec = { 0, hns * 100 }; nanosleep(&spec, NULL); #endif } From c9f880e42735579370bd532015ae6b12dcb86e37 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sat, 9 Mar 2024 22:38:11 +0100 Subject: [PATCH 13/68] port: fix #224, allow combat knife in jpn --- port/src/preprocess.c | 17 ++++++++++++++--- src/game/mplayer/mplayer.c | 2 +- src/include/constants.h | 38 +++++++++++++++++++++++++------------- 3 files changed, 40 insertions(+), 17 deletions(-) diff --git a/port/src/preprocess.c b/port/src/preprocess.c index 15f54f470..b0286aa2b 100644 --- a/port/src/preprocess.c +++ b/port/src/preprocess.c @@ -1045,12 +1045,23 @@ void preprocessMpConfigs(u8 *data, u32 size) // TODO: are these required or are they always 0? PD_SWAP_VAL(cfg->setup.fileguid.deviceserial); PD_SWAP_VAL(cfg->setup.fileguid.fileid); - // convert MPWEAPON_ to take classic weapons into account + // convert MPWEAPON_ to take classic weapons and JPN weapons into account for (s32 j = 0; j < ARRAYCOUNT(cfg->setup.weapons); ++j) { - // old MPWEAPON_SHIELD (0x24/0x25) and above are affected - if (cfg->setup.weapons[j] >= MPWEAPON_PP9I) { +#if VERSION == VERSION_JPN_FINAL /* TODO: replace with runtime check */ + if (cfg->setup.weapons[j] >= 0x24) { + // weapons after and including the shield need to be shifted cfg->setup.weapons[j] += (MPWEAPON_SHIELD - MPWEAPON_PP9I); } + if (cfg->setup.weapons[j] >= 0x19) { + // weapons after the combat knife also need to be shifted up in JPN + cfg->setup.weapons[j]++; + } +#else + // in other versions we only care about the shield and above + if (cfg->setup.weapons[j] >= 0x25) { + cfg->setup.weapons[j] += (MPWEAPON_SHIELD - MPWEAPON_PP9I); + } +#endif } } } diff --git a/src/game/mplayer/mplayer.c b/src/game/mplayer/mplayer.c index 9aca1a2a2..a5756ab8e 100644 --- a/src/game/mplayer/mplayer.c +++ b/src/game/mplayer/mplayer.c @@ -1505,7 +1505,7 @@ struct mpweaponset g_MpWeaponSets[12] = { { /*0x08*/ L_MPWEAPONS_047, { WEAPON_MAGSEC4, WEAPON_CMP150, WEAPON_AR34, WEAPON_DEVASTATOR, WEAPON_MPSHIELD, WEAPON_DISABLED }, { MPFEATURE_WEAPON_DEVASTATOR, 0, 0, 0 }, WEAPON_DISABLED, WEAPON_DISABLED, WEAPON_DISABLED, WEAPON_DISABLED, WEAPON_DISABLED, WEAPON_DISABLED }, // Grenade Launcher { /*0x09*/ L_MPWEAPONS_046, { WEAPON_MAULER, WEAPON_CYCLONE, WEAPON_DRAGON, WEAPON_ROCKETLAUNCHER, WEAPON_MPSHIELD, WEAPON_DISABLED }, { MPFEATURE_WEAPON_MAULER, 0, 0, 0 }, WEAPON_FALCON2, WEAPON_CYCLONE, WEAPON_DRAGON, WEAPON_ROCKETLAUNCHER, WEAPON_MPSHIELD, WEAPON_DISABLED }, // Rocket Launcher { /*0x0a*/ L_MPWEAPONS_045, { WEAPON_MAGSEC4, WEAPON_LAPTOPGUN, WEAPON_K7AVENGER, WEAPON_PROXIMITYMINE, WEAPON_MPSHIELD, WEAPON_DISABLED }, { MPFEATURE_WEAPON_LAPTOPGUN, MPFEATURE_WEAPON_K7AVENGER, MPFEATURE_WEAPON_PROXIMITYMINE, 0 }, WEAPON_DISABLED, WEAPON_DISABLED, WEAPON_DISABLED, WEAPON_DISABLED, WEAPON_DISABLED, WEAPON_DISABLED }, // Proximity Mine -#if VERSION == VERSION_JPN_FINAL +#if (VERSION == VERSION_JPN_FINAL) && defined(PLATFORM_N64) { /*0x0b*/ L_MPWEAPONS_044, { WEAPON_TIMEDMINE, WEAPON_CROSSBOW, WEAPON_TIMEDMINE, WEAPON_CROSSBOW, WEAPON_MPSHIELD, WEAPON_DISABLED }, { MPFEATURE_WEAPON_CROSSBOW, 0, 0, 0 }, WEAPON_TIMEDMINE, WEAPON_TIMEDMINE, WEAPON_TIMEDMINE, WEAPON_TIMEDMINE, WEAPON_MPSHIELD, WEAPON_DISABLED }, // Close Combat #else { /*0x0b*/ L_MPWEAPONS_044, { WEAPON_COMBATKNIFE, WEAPON_COMBATKNIFE, WEAPON_TIMEDMINE, WEAPON_CROSSBOW, WEAPON_MPSHIELD, WEAPON_DISABLED }, { MPFEATURE_WEAPON_CROSSBOW, 0, 0, 0 }, WEAPON_COMBATKNIFE, WEAPON_COMBATKNIFE, WEAPON_TIMEDMINE, WEAPON_TIMEDMINE, WEAPON_MPSHIELD, WEAPON_DISABLED }, // Close Combat diff --git a/src/include/constants.h b/src/include/constants.h index cbb8ec344..e51ec894a 100644 --- a/src/include/constants.h +++ b/src/include/constants.h @@ -2969,23 +2969,35 @@ #define MPWEAPON_DEVASTATOR 0x16 #define MPWEAPON_ROCKETLAUNCHER 0x17 #define MPWEAPON_SLAYER 0x18 -#define MPWEAPON_COMBATKNIFE (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0 : 0x19) -#define MPWEAPON_CROSSBOW (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0x19 : 0x1a) -#define MPWEAPON_TRANQUILIZER (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0x1a : 0x1b) -#define MPWEAPON_GRENADE (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0x1b : 0x1c) -#define MPWEAPON_NBOMB (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0x1c : 0x1d) -#define MPWEAPON_TIMEDMINE (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0x1d : 0x1e) -#define MPWEAPON_PROXIMITYMINE (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0x1e : 0x1f) -#define MPWEAPON_REMOTEMINE (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0x1f : 0x20) -#define MPWEAPON_LASER (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0x20 : 0x21) -#define MPWEAPON_XRAYSCANNER (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0x21 : 0x22) -#define MPWEAPON_CLOAKINGDEVICE (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0x22 : 0x23) -#define MPWEAPON_COMBATBOOST (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0x23 : 0x24) #ifdef PLATFORM_N64 +#define MPWEAPON_COMBATKNIFE (VERSION == VERSION_JPN_FINAL ? 0 : 0x19) +#define MPWEAPON_CROSSBOW (VERSION == VERSION_JPN_FINAL ? 0x19 : 0x1a) +#define MPWEAPON_TRANQUILIZER (VERSION == VERSION_JPN_FINAL ? 0x1a : 0x1b) +#define MPWEAPON_GRENADE (VERSION == VERSION_JPN_FINAL ? 0x1b : 0x1c) +#define MPWEAPON_NBOMB (VERSION == VERSION_JPN_FINAL ? 0x1c : 0x1d) +#define MPWEAPON_TIMEDMINE (VERSION == VERSION_JPN_FINAL ? 0x1d : 0x1e) +#define MPWEAPON_PROXIMITYMINE (VERSION == VERSION_JPN_FINAL ? 0x1e : 0x1f) +#define MPWEAPON_REMOTEMINE (VERSION == VERSION_JPN_FINAL ? 0x1f : 0x20) +#define MPWEAPON_LASER (VERSION == VERSION_JPN_FINAL ? 0x20 : 0x21) +#define MPWEAPON_XRAYSCANNER (VERSION == VERSION_JPN_FINAL ? 0x21 : 0x22) +#define MPWEAPON_CLOAKINGDEVICE (VERSION == VERSION_JPN_FINAL ? 0x22 : 0x23) +#define MPWEAPON_COMBATBOOST (VERSION == VERSION_JPN_FINAL ? 0x23 : 0x24) #define MPWEAPON_SHIELD (VERSION == VERSION_JPN_FINAL ? 0x24 : 0x25) #define MPWEAPON_DISABLED (VERSION == VERSION_JPN_FINAL ? 0x25 : 0x26) #define NUM_MPWEAPONS (VERSION == VERSION_JPN_FINAL ? 0x26 : 0x27) -#else // add all classic weapons to multiplayer +#else // add all classic weapons to multiplayer and allow combat knife in JPN +#define MPWEAPON_COMBATKNIFE 0x19 +#define MPWEAPON_CROSSBOW 0x1a +#define MPWEAPON_TRANQUILIZER 0x1b +#define MPWEAPON_GRENADE 0x1c +#define MPWEAPON_NBOMB 0x1d +#define MPWEAPON_TIMEDMINE 0x1e +#define MPWEAPON_PROXIMITYMINE 0x1f +#define MPWEAPON_REMOTEMINE 0x20 +#define MPWEAPON_LASER 0x21 +#define MPWEAPON_XRAYSCANNER 0x22 +#define MPWEAPON_CLOAKINGDEVICE 0x23 +#define MPWEAPON_COMBATBOOST 0x24 #define MPWEAPON_PP9I 0x25 #define MPWEAPON_CC13 0x26 #define MPWEAPON_KL01313 0x27 From 80faefbaf6fa32066e02ff51662c2e6b4b4a26db Mon Sep 17 00:00:00 2001 From: Jonaeru Date: Sun, 17 Mar 2024 15:12:26 +0900 Subject: [PATCH 14/68] port: give Night Vision at respawn in Perfect Darkness Combat --- src/game/player.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/game/player.c b/src/game/player.c index bb26bd28e..36c10511b 100644 --- a/src/game/player.c +++ b/src/game/player.c @@ -1100,6 +1100,10 @@ void playerSpawn(void) } } else { #ifndef PLATFORM_N64 + if (cheatIsActive(CHEAT_PERFECTDARKNESS)) { + invGiveSingleWeapon(WEAPON_NIGHTVISION); + } + if ((g_MpSetup.options & MPOPTION_SPAWNWITHWEAPON) && g_MpSetup.weapons[0] != MPWEAPON_NONE && g_MpSetup.weapons[0] != MPWEAPON_DISABLED) { From ec8310e4a161653f266349e73f045a53fcee0f27 Mon Sep 17 00:00:00 2001 From: Jonaeru Date: Sun, 17 Mar 2024 15:42:53 +0900 Subject: [PATCH 15/68] port: fix X-Ray Scanner model in Combat Simulator --- src/game/mplayer/mplayer.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/game/mplayer/mplayer.c b/src/game/mplayer/mplayer.c index a5756ab8e..20270b1ed 100644 --- a/src/game/mplayer/mplayer.c +++ b/src/game/mplayer/mplayer.c @@ -92,7 +92,12 @@ struct mpweapon g_MpWeapons[NUM_MPWEAPONS] = { /*0x1f*/ { WEAPON_PROXIMITYMINE, AMMOTYPE_PROXY_MINE, 5, 0, 0, 0, MPFEATURE_WEAPON_PROXIMITYMINE, MODEL_CHRPROXIMITYMINE, 384 }, /*0x20*/ { WEAPON_REMOTEMINE, AMMOTYPE_REMOTE_MINE, 5, 0, 0, 0, MPFEATURE_WEAPON_REMOTEMINE, MODEL_CHRREMOTEMINE, 384 }, /*0x21*/ { WEAPON_LASER, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_LASER, MODEL_CHRLASER, 512 }, +#ifndef PLATFORM_N64 + // fix X-Ray Scanner model + /*0x22*/ { WEAPON_XRAYSCANNER, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_XRAYSCANNER, MODEL_XRAYSPECS, 256 }, +#else /*0x22*/ { WEAPON_XRAYSCANNER, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_XRAYSCANNER, MODEL_CHRNIGHTSIGHT, 256 }, +#endif /*0x23*/ { WEAPON_CLOAKINGDEVICE, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_CLOAKINGDEVICE, MODEL_CHRCLOAKER, 256 }, /*0x24*/ { WEAPON_COMBATBOOST, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_COMBATBOOST, MODEL_CHRSPEEDPILL, 256 }, #ifndef PLATFORM_N64 From 0b61ec9641252e36adea13e00bc7898672ffd7a1 Mon Sep 17 00:00:00 2001 From: Jonaeru Date: Wed, 20 Mar 2024 01:53:50 +0900 Subject: [PATCH 16/68] port: add friendly fire mp option --- src/game/chraction.c | 12 ++++++++++++ src/game/mplayer/mplayer.c | 4 ++++ src/game/mplayer/scenarios/capturethecase.inc | 8 ++++++++ src/game/mplayer/scenarios/combat.inc | 8 ++++++++ src/game/mplayer/scenarios/hackthatmac.inc | 8 ++++++++ src/game/mplayer/scenarios/holdthebriefcase.inc | 8 ++++++++ src/game/mplayer/scenarios/kingofthehill.inc | 8 ++++++++ src/game/mplayer/scenarios/popacap.inc | 8 ++++++++ src/include/constants.h | 1 + 9 files changed, 65 insertions(+) diff --git a/src/game/chraction.c b/src/game/chraction.c index a770ee77c..8ff7b6502 100644 --- a/src/game/chraction.c +++ b/src/game/chraction.c @@ -4339,6 +4339,18 @@ void chrDamage(struct chrdata *chr, f32 damage, struct coord *vector, struct gse return; } +#ifndef PLATFORM_N64 + // Don't damage if multiplayer and friendly fire is off + if (g_Vars.mplayerisrunning + && !(g_MpSetup.options & MPOPTION_FRIENDLYFIRE) + && aprop + && aprop != vprop + && (aprop->type == PROPTYPE_PLAYER || aprop->type == PROPTYPE_CHR) + && chr->team == aprop->chr->team) { + return; + } +#endif + if (gset == NULL) { gset = &gset2; } diff --git a/src/game/mplayer/mplayer.c b/src/game/mplayer/mplayer.c index a5756ab8e..e74e8fc49 100644 --- a/src/game/mplayer/mplayer.c +++ b/src/game/mplayer/mplayer.c @@ -524,6 +524,10 @@ void mpInit(void) | MPOPTION_PAC_HIGHLIGHTTARGET | MPOPTION_PAC_SHOWONRADAR; +#ifndef PLATFORM_N64 + g_MpSetup.options |= MPOPTION_FRIENDLYFIRE; +#endif + g_Vars.mphilltime = 10; func0f187fec(); diff --git a/src/game/mplayer/scenarios/capturethecase.inc b/src/game/mplayer/scenarios/capturethecase.inc index 0e82d542a..920715fdb 100644 --- a/src/game/mplayer/scenarios/capturethecase.inc +++ b/src/game/mplayer/scenarios/capturethecase.inc @@ -69,6 +69,14 @@ struct menuitem g_CtcOptionsMenuItems[] = { MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, + { + MENUITEMTYPE_CHECKBOX, + 0, + MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"Friendly Fire", + MPOPTION_FRIENDLYFIRE, + menuhandlerMpDisplayTeam, + }, #endif { MENUITEMTYPE_CHECKBOX, diff --git a/src/game/mplayer/scenarios/combat.inc b/src/game/mplayer/scenarios/combat.inc index 7d096a55c..cc35e2207 100644 --- a/src/game/mplayer/scenarios/combat.inc +++ b/src/game/mplayer/scenarios/combat.inc @@ -64,6 +64,14 @@ struct menuitem g_MpCombatOptionsMenuItems[] = { MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, + { + MENUITEMTYPE_CHECKBOX, + 0, + MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"Friendly Fire", + MPOPTION_FRIENDLYFIRE, + menuhandlerMpDisplayTeam, + }, #endif { MENUITEMTYPE_SEPARATOR, diff --git a/src/game/mplayer/scenarios/hackthatmac.inc b/src/game/mplayer/scenarios/hackthatmac.inc index 1ca58458a..696182857 100644 --- a/src/game/mplayer/scenarios/hackthatmac.inc +++ b/src/game/mplayer/scenarios/hackthatmac.inc @@ -67,6 +67,14 @@ struct menuitem g_HtmOptionsMenuItems[] = { MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, + { + MENUITEMTYPE_CHECKBOX, + 0, + MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"Friendly Fire", + MPOPTION_FRIENDLYFIRE, + menuhandlerMpDisplayTeam, + }, #endif { MENUITEMTYPE_CHECKBOX, diff --git a/src/game/mplayer/scenarios/holdthebriefcase.inc b/src/game/mplayer/scenarios/holdthebriefcase.inc index fe9cc0bd6..021eedb79 100644 --- a/src/game/mplayer/scenarios/holdthebriefcase.inc +++ b/src/game/mplayer/scenarios/holdthebriefcase.inc @@ -67,6 +67,14 @@ struct menuitem g_HtbOptionsMenuItems[] = { MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, + { + MENUITEMTYPE_CHECKBOX, + 0, + MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"Friendly Fire", + MPOPTION_FRIENDLYFIRE, + menuhandlerMpDisplayTeam, + }, #endif { MENUITEMTYPE_CHECKBOX, diff --git a/src/game/mplayer/scenarios/kingofthehill.inc b/src/game/mplayer/scenarios/kingofthehill.inc index 120024f19..6beb27a3c 100644 --- a/src/game/mplayer/scenarios/kingofthehill.inc +++ b/src/game/mplayer/scenarios/kingofthehill.inc @@ -88,6 +88,14 @@ struct menuitem g_KohOptionsMenuItems[] = { MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, + { + MENUITEMTYPE_CHECKBOX, + 0, + MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"Friendly Fire", + MPOPTION_FRIENDLYFIRE, + menuhandlerMpDisplayTeam, + }, #endif { MENUITEMTYPE_CHECKBOX, diff --git a/src/game/mplayer/scenarios/popacap.inc b/src/game/mplayer/scenarios/popacap.inc index 7da8ed521..6d6ea5e75 100644 --- a/src/game/mplayer/scenarios/popacap.inc +++ b/src/game/mplayer/scenarios/popacap.inc @@ -65,6 +65,14 @@ struct menuitem g_PacOptionsMenuItems[] = { MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, + { + MENUITEMTYPE_CHECKBOX, + 0, + MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"Friendly Fire", + MPOPTION_FRIENDLYFIRE, + menuhandlerMpDisplayTeam, + }, #endif { MENUITEMTYPE_CHECKBOX, diff --git a/src/include/constants.h b/src/include/constants.h index e51ec894a..ac39e4c60 100644 --- a/src/include/constants.h +++ b/src/include/constants.h @@ -2890,6 +2890,7 @@ #define MPOPTION_PAC_HIGHLIGHTTARGET 0x00080000 #define MPOPTION_PAC_SHOWONRADAR 0x00100000 #define MPOPTION_SPAWNWITHWEAPON 0x00200000 +#define MPOPTION_FRIENDLYFIRE 0x00400000 #define MPPAUSEMODE_UNPAUSED 0 #define MPPAUSEMODE_PAUSED 1 From 501ab95b00c7835c72f2cb67a2f43ab7ea4889a6 Mon Sep 17 00:00:00 2001 From: Jonaeru Date: Wed, 20 Mar 2024 11:19:06 +0900 Subject: [PATCH 17/68] port: fix texts --- src/game/mplayer/scenarios/capturethecase.inc | 4 ++-- src/game/mplayer/scenarios/combat.inc | 4 ++-- src/game/mplayer/scenarios/hackthatmac.inc | 4 ++-- src/game/mplayer/scenarios/holdthebriefcase.inc | 4 ++-- src/game/mplayer/scenarios/kingofthehill.inc | 4 ++-- src/game/mplayer/scenarios/popacap.inc | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/game/mplayer/scenarios/capturethecase.inc b/src/game/mplayer/scenarios/capturethecase.inc index 920715fdb..e940390e7 100644 --- a/src/game/mplayer/scenarios/capturethecase.inc +++ b/src/game/mplayer/scenarios/capturethecase.inc @@ -72,8 +72,8 @@ struct menuitem g_CtcOptionsMenuItems[] = { { MENUITEMTYPE_CHECKBOX, 0, - MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Friendly Fire", + MENUITEMFLAG_LOCKABLEMINOR, + L_OPTIONS_257, // "Friendly Fire" MPOPTION_FRIENDLYFIRE, menuhandlerMpDisplayTeam, }, diff --git a/src/game/mplayer/scenarios/combat.inc b/src/game/mplayer/scenarios/combat.inc index cc35e2207..03834861f 100644 --- a/src/game/mplayer/scenarios/combat.inc +++ b/src/game/mplayer/scenarios/combat.inc @@ -67,8 +67,8 @@ struct menuitem g_MpCombatOptionsMenuItems[] = { { MENUITEMTYPE_CHECKBOX, 0, - MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Friendly Fire", + MENUITEMFLAG_LOCKABLEMINOR, + L_OPTIONS_257, // "Friendly Fire" MPOPTION_FRIENDLYFIRE, menuhandlerMpDisplayTeam, }, diff --git a/src/game/mplayer/scenarios/hackthatmac.inc b/src/game/mplayer/scenarios/hackthatmac.inc index 696182857..2ab930965 100644 --- a/src/game/mplayer/scenarios/hackthatmac.inc +++ b/src/game/mplayer/scenarios/hackthatmac.inc @@ -70,8 +70,8 @@ struct menuitem g_HtmOptionsMenuItems[] = { { MENUITEMTYPE_CHECKBOX, 0, - MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Friendly Fire", + MENUITEMFLAG_LOCKABLEMINOR, + L_OPTIONS_257, // "Friendly Fire" MPOPTION_FRIENDLYFIRE, menuhandlerMpDisplayTeam, }, diff --git a/src/game/mplayer/scenarios/holdthebriefcase.inc b/src/game/mplayer/scenarios/holdthebriefcase.inc index 021eedb79..f08a33f3c 100644 --- a/src/game/mplayer/scenarios/holdthebriefcase.inc +++ b/src/game/mplayer/scenarios/holdthebriefcase.inc @@ -70,8 +70,8 @@ struct menuitem g_HtbOptionsMenuItems[] = { { MENUITEMTYPE_CHECKBOX, 0, - MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Friendly Fire", + MENUITEMFLAG_LOCKABLEMINOR, + L_OPTIONS_257, // "Friendly Fire" MPOPTION_FRIENDLYFIRE, menuhandlerMpDisplayTeam, }, diff --git a/src/game/mplayer/scenarios/kingofthehill.inc b/src/game/mplayer/scenarios/kingofthehill.inc index 6beb27a3c..45684ff4b 100644 --- a/src/game/mplayer/scenarios/kingofthehill.inc +++ b/src/game/mplayer/scenarios/kingofthehill.inc @@ -91,8 +91,8 @@ struct menuitem g_KohOptionsMenuItems[] = { { MENUITEMTYPE_CHECKBOX, 0, - MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Friendly Fire", + MENUITEMFLAG_LOCKABLEMINOR, + L_OPTIONS_257, // "Friendly Fire" MPOPTION_FRIENDLYFIRE, menuhandlerMpDisplayTeam, }, diff --git a/src/game/mplayer/scenarios/popacap.inc b/src/game/mplayer/scenarios/popacap.inc index 6d6ea5e75..fa58c551f 100644 --- a/src/game/mplayer/scenarios/popacap.inc +++ b/src/game/mplayer/scenarios/popacap.inc @@ -68,8 +68,8 @@ struct menuitem g_PacOptionsMenuItems[] = { { MENUITEMTYPE_CHECKBOX, 0, - MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Friendly Fire", + MENUITEMFLAG_LOCKABLEMINOR, + L_OPTIONS_257, // "Friendly Fire" MPOPTION_FRIENDLYFIRE, menuhandlerMpDisplayTeam, }, From 2483d4fc35dafceb97c865bfbd1e71f93eef8ab4 Mon Sep 17 00:00:00 2001 From: Jonaeru Date: Tue, 26 Mar 2024 00:53:57 +0900 Subject: [PATCH 18/68] port: add auto random mp weapon option --- src/game/mplayer/mplayer.c | 18 ++++++++++++ src/game/mplayer/setup.c | 60 ++++++++++++++++++++++++++++++++++++++ src/include/constants.h | 2 ++ 3 files changed, 80 insertions(+) diff --git a/src/game/mplayer/mplayer.c b/src/game/mplayer/mplayer.c index 20270b1ed..851a2d1c5 100644 --- a/src/game/mplayer/mplayer.c +++ b/src/game/mplayer/mplayer.c @@ -184,6 +184,15 @@ void mpStartMatch(void) s32 numplayers = 0; s32 stagenum; +#ifndef PLATFORM_N64 + if (g_MpSetup.options & MPOPTION_AUTORANDOMWEAPON_START) { + if (g_MpWeaponSetNum == WEAPONSET_RANDOM + || g_MpWeaponSetNum == WEAPONSET_RANDOMFIVE) { + mpApplyWeaponSet(); + } + } +#endif + mpConfigureQuickTeamSimulants(); if (!challengeIsFeatureUnlocked(MPFEATURE_ONEHITKILLS)) { @@ -2458,6 +2467,15 @@ void mpEndMatch(void) challengeConsiderMarkingComplete(); } +#ifndef PLATFORM_N64 + if (g_MpSetup.options & MPOPTION_AUTORANDOMWEAPON_END) { + if (g_MpWeaponSetNum == WEAPONSET_RANDOM + || g_MpWeaponSetNum == WEAPONSET_RANDOMFIVE) { + mpApplyWeaponSet(); + } + } +#endif + func0f0f820c(NULL, -6); } diff --git a/src/game/mplayer/setup.c b/src/game/mplayer/setup.c index 87b99860d..37061aad9 100644 --- a/src/game/mplayer/setup.c +++ b/src/game/mplayer/setup.c @@ -31,6 +31,10 @@ struct menudialogdef g_MpChangeTeamNameMenuDialog; struct menudialogdef g_MpEditSimulantMenuDialog; struct menudialogdef g_MpSaveSetupNameMenuDialog; +#ifndef PLATFORM_N64 +extern s32 g_MpWeaponSetNum; +#endif + MenuItemHandlerResult menuhandlerMpDropOut(s32 operation, struct menuitem *item, union handlerdata *data) { if (operation == MENUOP_SET) { @@ -1160,6 +1164,52 @@ struct menudialogdef g_MpSaveSetupExistsMenuDialog = { NULL, }; +#ifndef PLATFORM_N64 +MenuItemHandlerResult menuhandlerMpAutoRandomWeapon(s32 operation, struct menuitem *item, union handlerdata *data) +{ + const char *labels[] = { + "Off", + "Start", + "End", + }; + + switch (operation) { + case MENUOP_CHECKDISABLED: + case MENUOP_CHECKHIDDEN: + if (g_MpWeaponSetNum == WEAPONSET_RANDOM + || g_MpWeaponSetNum == WEAPONSET_RANDOMFIVE) { + return false; + } + return true; + case MENUOP_GETOPTIONCOUNT: + data->dropdown.value = 3; + break; + case MENUOP_GETOPTIONTEXT: + return (intptr_t)labels[data->dropdown.value]; + case MENUOP_SET: + g_MpSetup.options &= ~(MPOPTION_AUTORANDOMWEAPON_START | MPOPTION_AUTORANDOMWEAPON_END); + + if (data->dropdown.value == 1) { + g_MpSetup.options |= MPOPTION_AUTORANDOMWEAPON_START; + } else if (data->dropdown.value == 2) { + g_MpSetup.options |= MPOPTION_AUTORANDOMWEAPON_END; + } + break; + case MENUOP_GETSELECTEDINDEX: + if (g_MpSetup.options & MPOPTION_AUTORANDOMWEAPON_END) { + data->dropdown.value = 2; + } else if (g_MpSetup.options & MPOPTION_AUTORANDOMWEAPON_START) { + data->dropdown.value = 1; + } else { + data->dropdown.value = 0; + } + break; + } + + return 0; +} +#endif + struct menuitem g_MpWeaponsMenuItems[] = { { MENUITEMTYPE_DROPDOWN, @@ -1169,6 +1219,16 @@ struct menuitem g_MpWeaponsMenuItems[] = { 0, menuhandlerMpWeaponSetDropdown, }, +#ifndef PLATFORM_N64 + { + MENUITEMTYPE_DROPDOWN, + 0, + MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"Auto Random\n", + 0, + menuhandlerMpAutoRandomWeapon, + }, +#endif { MENUITEMTYPE_SEPARATOR, 0, diff --git a/src/include/constants.h b/src/include/constants.h index e51ec894a..70c0384d4 100644 --- a/src/include/constants.h +++ b/src/include/constants.h @@ -2890,6 +2890,8 @@ #define MPOPTION_PAC_HIGHLIGHTTARGET 0x00080000 #define MPOPTION_PAC_SHOWONRADAR 0x00100000 #define MPOPTION_SPAWNWITHWEAPON 0x00200000 +#define MPOPTION_AUTORANDOMWEAPON_START 0x00400000 +#define MPOPTION_AUTORANDOMWEAPON_END 0x00800000 #define MPPAUSEMODE_UNPAUSED 0 #define MPPAUSEMODE_PAUSED 1 From c9a14f090bebbc33b8abb486f05e613bba63c237 Mon Sep 17 00:00:00 2001 From: Jonaeru Date: Tue, 26 Mar 2024 23:41:57 +0900 Subject: [PATCH 19/68] port: add constants --- src/game/mplayer/setup.c | 14 +++++++------- src/include/constants.h | 4 ++++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/game/mplayer/setup.c b/src/game/mplayer/setup.c index 37061aad9..94c422eb0 100644 --- a/src/game/mplayer/setup.c +++ b/src/game/mplayer/setup.c @@ -1167,7 +1167,7 @@ struct menudialogdef g_MpSaveSetupExistsMenuDialog = { #ifndef PLATFORM_N64 MenuItemHandlerResult menuhandlerMpAutoRandomWeapon(s32 operation, struct menuitem *item, union handlerdata *data) { - const char *labels[] = { + static const char *labels[] = { "Off", "Start", "End", @@ -1182,26 +1182,26 @@ MenuItemHandlerResult menuhandlerMpAutoRandomWeapon(s32 operation, struct menuit } return true; case MENUOP_GETOPTIONCOUNT: - data->dropdown.value = 3; + data->dropdown.value = ARRAYCOUNT(labels); break; case MENUOP_GETOPTIONTEXT: return (intptr_t)labels[data->dropdown.value]; case MENUOP_SET: g_MpSetup.options &= ~(MPOPTION_AUTORANDOMWEAPON_START | MPOPTION_AUTORANDOMWEAPON_END); - if (data->dropdown.value == 1) { + if (data->dropdown.value == AUTORANDOM_START) { g_MpSetup.options |= MPOPTION_AUTORANDOMWEAPON_START; - } else if (data->dropdown.value == 2) { + } else if (data->dropdown.value == AUTORANDOM_END) { g_MpSetup.options |= MPOPTION_AUTORANDOMWEAPON_END; } break; case MENUOP_GETSELECTEDINDEX: if (g_MpSetup.options & MPOPTION_AUTORANDOMWEAPON_END) { - data->dropdown.value = 2; + data->dropdown.value = AUTORANDOM_END; } else if (g_MpSetup.options & MPOPTION_AUTORANDOMWEAPON_START) { - data->dropdown.value = 1; + data->dropdown.value = AUTORANDOM_START; } else { - data->dropdown.value = 0; + data->dropdown.value = AUTORANDOM_OFF; } break; } diff --git a/src/include/constants.h b/src/include/constants.h index 70c0384d4..733484616 100644 --- a/src/include/constants.h +++ b/src/include/constants.h @@ -3804,6 +3804,10 @@ #define SLOWMOTION_ON 1 #define SLOWMOTION_SMART 2 +#define AUTORANDOM_OFF 0 +#define AUTORANDOM_START 1 +#define AUTORANDOM_END 2 + #define SMOKETYPE_NONE 0 #define SMOKETYPE_ELECTRICAL 1 // Dr Caroll, mainframes in Infiltration bunker #define SMOKETYPE_MINI 2 // Phoenix, Laptop sentry From 7580ebcaf96e3b8bc00eac603cbda29f07977a70 Mon Sep 17 00:00:00 2001 From: Jonaeru Date: Tue, 26 Mar 2024 23:45:55 +0900 Subject: [PATCH 20/68] port: rename constants --- src/game/mplayer/setup.c | 10 +++++----- src/include/constants.h | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/game/mplayer/setup.c b/src/game/mplayer/setup.c index 94c422eb0..44834bbfb 100644 --- a/src/game/mplayer/setup.c +++ b/src/game/mplayer/setup.c @@ -1189,19 +1189,19 @@ MenuItemHandlerResult menuhandlerMpAutoRandomWeapon(s32 operation, struct menuit case MENUOP_SET: g_MpSetup.options &= ~(MPOPTION_AUTORANDOMWEAPON_START | MPOPTION_AUTORANDOMWEAPON_END); - if (data->dropdown.value == AUTORANDOM_START) { + if (data->dropdown.value == AUTORANDOMWEAPON_START) { g_MpSetup.options |= MPOPTION_AUTORANDOMWEAPON_START; - } else if (data->dropdown.value == AUTORANDOM_END) { + } else if (data->dropdown.value == AUTORANDOMWEAPON_END) { g_MpSetup.options |= MPOPTION_AUTORANDOMWEAPON_END; } break; case MENUOP_GETSELECTEDINDEX: if (g_MpSetup.options & MPOPTION_AUTORANDOMWEAPON_END) { - data->dropdown.value = AUTORANDOM_END; + data->dropdown.value = AUTORANDOMWEAPON_END; } else if (g_MpSetup.options & MPOPTION_AUTORANDOMWEAPON_START) { - data->dropdown.value = AUTORANDOM_START; + data->dropdown.value = AUTORANDOMWEAPON_START; } else { - data->dropdown.value = AUTORANDOM_OFF; + data->dropdown.value = AUTORANDOMWEAPON_OFF; } break; } diff --git a/src/include/constants.h b/src/include/constants.h index 733484616..c94999b60 100644 --- a/src/include/constants.h +++ b/src/include/constants.h @@ -3804,9 +3804,9 @@ #define SLOWMOTION_ON 1 #define SLOWMOTION_SMART 2 -#define AUTORANDOM_OFF 0 -#define AUTORANDOM_START 1 -#define AUTORANDOM_END 2 +#define AUTORANDOMWEAPON_OFF 0 +#define AUTORANDOMWEAPON_START 1 +#define AUTORANDOMWEAPON_END 2 #define SMOKETYPE_NONE 0 #define SMOKETYPE_ELECTRICAL 1 // Dr Caroll, mainframes in Infiltration bunker From 68aee1d2f2280182658c3b42fc8c82003c3f427d Mon Sep 17 00:00:00 2001 From: Catherine Reprobate Date: Sun, 14 Apr 2024 14:49:32 -0700 Subject: [PATCH 21/68] fix for rcp120 alt button behavior --- src/game/bondgun.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/game/bondgun.c b/src/game/bondgun.c index 67825c973..c2dbc993e 100644 --- a/src/game/bondgun.c +++ b/src/game/bondgun.c @@ -11781,6 +11781,19 @@ s32 bgunConsiderToggleGunFunction(s32 usedowntime, bool trigpressed, bool fromac g_Vars.currentplayer->hands[HAND_RIGHT].activatesecondary = true; return (extcontrols ? USETIMER_STOP : USETIMER_REPEAT); case WEAPON_RCP120: + #ifndef PLATFORM_N64 + s32 cloaked = (g_Vars.currentplayer->devicesactive & DEVICE_CLOAKRCP120) != 0; + // very special alt-button handling for RCP-120's cloaking + if (!trigpressed && extcontrols && fromdedicatedbutton) { + if (cloaked) { + g_Vars.currentplayer->devicesactive &= ~DEVICE_CLOAKRCP120; + } else { + g_Vars.currentplayer->devicesactive = (g_Vars.currentplayer->devicesactive & ~DEVICE_CLOAKRCP120) | DEVICE_CLOAKRCP120; + } + g_Vars.currentplayer->gunctrl.invertgunfunc = false; + return USETIMER_STOP; + } + #endif case WEAPON_LAPTOPGUN: case WEAPON_DRAGON: case WEAPON_REMOTEMINE: From 5b1d03cbbb25e3ebf3d84e53a90d64914148be1c Mon Sep 17 00:00:00 2001 From: Not actually throwaway <98854201+throwaway29292@users.noreply.github.com> Date: Wed, 24 Apr 2024 22:44:00 +0200 Subject: [PATCH 22/68] Add an option in Combat Simulator to disable the blur effect from melee damage This effect might be annoyning or eye straining for some people so i believe it's a good idea to implement this option. There is still some free space in the MP Options bitfield for future expansion. --- src/game/lv.c | 7 +++++++ src/game/mplayer/scenarios/capturethecase.inc | 8 ++++++++ src/game/mplayer/scenarios/combat.inc | 8 ++++++++ src/game/mplayer/scenarios/hackthatmac.inc | 8 ++++++++ src/game/mplayer/scenarios/holdthebriefcase.inc | 8 ++++++++ src/game/mplayer/scenarios/kingofthehill.inc | 8 ++++++++ src/game/mplayer/scenarios/popacap.inc | 8 ++++++++ src/include/constants.h | 1 + 8 files changed, 56 insertions(+) diff --git a/src/game/lv.c b/src/game/lv.c index 1c746b77d..1762b2af2 100644 --- a/src/game/lv.c +++ b/src/game/lv.c @@ -1127,6 +1127,13 @@ Gfx *lvRender(Gfx *gdl) chr->blurdrugamount = 0; chr->blurnumtimesdied = 0; } +#ifndef PLATFORM_N64 //set the drug blur to 0 if it's disabled in MP settings. There might be a better way to block it from occuring, but this one works just fine + + if(g_Vars.mplayerisrunning && (g_MpSetup.options & MPOPTION_NODRUGBLUR)) + { + bluramount = 0; + } +#endif } } diff --git a/src/game/mplayer/scenarios/capturethecase.inc b/src/game/mplayer/scenarios/capturethecase.inc index 0e82d542a..2addfbfde 100644 --- a/src/game/mplayer/scenarios/capturethecase.inc +++ b/src/game/mplayer/scenarios/capturethecase.inc @@ -69,6 +69,14 @@ struct menuitem g_CtcOptionsMenuItems[] = { MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, + { + MENUITEMTYPE_CHECKBOX, + 0, + MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"No melee/tranquilizer blur", + MPOPTION_NODRUGBLUR, + menuhandlerMpCheckboxOption, + }, #endif { MENUITEMTYPE_CHECKBOX, diff --git a/src/game/mplayer/scenarios/combat.inc b/src/game/mplayer/scenarios/combat.inc index 7d096a55c..76da12a16 100644 --- a/src/game/mplayer/scenarios/combat.inc +++ b/src/game/mplayer/scenarios/combat.inc @@ -64,6 +64,14 @@ struct menuitem g_MpCombatOptionsMenuItems[] = { MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, + { + MENUITEMTYPE_CHECKBOX, + 0, + MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"No melee/tranquilizer blur", + MPOPTION_NODRUGBLUR, + menuhandlerMpCheckboxOption, + }, #endif { MENUITEMTYPE_SEPARATOR, diff --git a/src/game/mplayer/scenarios/hackthatmac.inc b/src/game/mplayer/scenarios/hackthatmac.inc index 1ca58458a..bc55d75b8 100644 --- a/src/game/mplayer/scenarios/hackthatmac.inc +++ b/src/game/mplayer/scenarios/hackthatmac.inc @@ -67,6 +67,14 @@ struct menuitem g_HtmOptionsMenuItems[] = { MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, + { + MENUITEMTYPE_CHECKBOX, + 0, + MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"No melee/tranquilizer blur", + MPOPTION_NODRUGBLUR, + menuhandlerMpCheckboxOption, + }, #endif { MENUITEMTYPE_CHECKBOX, diff --git a/src/game/mplayer/scenarios/holdthebriefcase.inc b/src/game/mplayer/scenarios/holdthebriefcase.inc index fe9cc0bd6..a0692c5e9 100644 --- a/src/game/mplayer/scenarios/holdthebriefcase.inc +++ b/src/game/mplayer/scenarios/holdthebriefcase.inc @@ -67,6 +67,14 @@ struct menuitem g_HtbOptionsMenuItems[] = { MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, + { + MENUITEMTYPE_CHECKBOX, + 0, + MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"No melee/tranquilizer blur", + MPOPTION_NODRUGBLUR, + menuhandlerMpCheckboxOption, + }, #endif { MENUITEMTYPE_CHECKBOX, diff --git a/src/game/mplayer/scenarios/kingofthehill.inc b/src/game/mplayer/scenarios/kingofthehill.inc index 120024f19..2d7857580 100644 --- a/src/game/mplayer/scenarios/kingofthehill.inc +++ b/src/game/mplayer/scenarios/kingofthehill.inc @@ -88,6 +88,14 @@ struct menuitem g_KohOptionsMenuItems[] = { MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, + { + MENUITEMTYPE_CHECKBOX, + 0, + MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"No melee/tranquilizer blur", + MPOPTION_NODRUGBLUR, + menuhandlerMpCheckboxOption, + }, #endif { MENUITEMTYPE_CHECKBOX, diff --git a/src/game/mplayer/scenarios/popacap.inc b/src/game/mplayer/scenarios/popacap.inc index 7da8ed521..faea5dd70 100644 --- a/src/game/mplayer/scenarios/popacap.inc +++ b/src/game/mplayer/scenarios/popacap.inc @@ -65,6 +65,14 @@ struct menuitem g_PacOptionsMenuItems[] = { MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, + { + MENUITEMTYPE_CHECKBOX, + 0, + MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"No melee/tranquilizer blur", + MPOPTION_NODRUGBLUR, + menuhandlerMpCheckboxOption, + }, #endif { MENUITEMTYPE_CHECKBOX, diff --git a/src/include/constants.h b/src/include/constants.h index e51ec894a..e42e8f93a 100644 --- a/src/include/constants.h +++ b/src/include/constants.h @@ -2890,6 +2890,7 @@ #define MPOPTION_PAC_HIGHLIGHTTARGET 0x00080000 #define MPOPTION_PAC_SHOWONRADAR 0x00100000 #define MPOPTION_SPAWNWITHWEAPON 0x00200000 +#define MPOPTION_NODRUGBLUR 0x00400000 #define MPPAUSEMODE_UNPAUSED 0 #define MPPAUSEMODE_PAUSED 1 From 73dc52cfd6cc3032595a9e0accbb901af53d2485 Mon Sep 17 00:00:00 2001 From: Paul Grandperrin Date: Thu, 25 Apr 2024 12:49:36 +0200 Subject: [PATCH 23/68] Makefile.port: fix dependencies for parallel compilation --- Makefile.port | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.port b/Makefile.port index b8ebadb12..d6a6699d4 100644 --- a/Makefile.port +++ b/Makefile.port @@ -271,7 +271,7 @@ export ROMID BIN := $(B_DIR)/$(BIN_NAME) -default: $(JSON_HEADERS) $(BIN) +default: $(BIN) ################################################################################ # Asset Manager header generation @@ -309,11 +309,11 @@ ifneq ($(CV2PDB),) $(CV2PDB) $(BIN) endif -$(B_DIR)/%.o: %.c +$(B_DIR)/%.o: %.c $(JSON_HEADERS) @mkdir -p $(dir $@) $(CC) -c $(CFLAGS) $(OPT_LVL) -o $@ $< -$(B_DIR)/%.o: %.cpp +$(B_DIR)/%.o: %.cpp $(JSON_HEADERS) @mkdir -p $(dir $@) $(CXX) -c $(CXXFLAGS) $(OPT_LVL) -o $@ $< From 798fbf7b90d909b73272cad9a769e8025ba85f42 Mon Sep 17 00:00:00 2001 From: Not actually throwaway <98854201+throwaway29292@users.noreply.github.com> Date: Wed, 1 May 2024 17:55:22 +0200 Subject: [PATCH 24/68] Add a cheat to allow dual-wielding all guns. The cheat's name is "Gameplay/(Two-Handed)" --- src/game/cheats.c | 13 +++++++++++++ src/game/game_0b0fd0.c | 7 ++++++- src/game/inv.c | 11 +++++++++++ src/include/constants.h | 1 + 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/game/cheats.c b/src/game/cheats.c index 71ac21ca8..260a390b3 100644 --- a/src/game/cheats.c +++ b/src/game/cheats.c @@ -100,6 +100,9 @@ struct cheat g_Cheats[] = { { L_MPWEAPONS_114, WEAPON_DMC, 0, 0, CHEATFLAG_FIRINGRANGE }, // DMC { L_MPWEAPONS_115, WEAPON_AR53, 0, 0, CHEATFLAG_FIRINGRANGE }, // AR53 { L_MPWEAPONS_116, WEAPON_RCP45, 0, 0, CHEATFLAG_FIRINGRANGE }, // RC-P45 +#ifndef PLATFORM_N64 + { L_MPWEAPONS_215, 0, SOLOSTAGEINDEX_EXTRACTION, DIFF_A, CHEATFLAG_COMPLETION }, // dual wield all guns cheat +#endif }; u32 cheatIsUnlocked(s32 cheat_id) @@ -1090,6 +1093,16 @@ struct menuitem g_CheatsGameplayMenuItems[] = { 0, cheatCheckboxMenuHandler, }, +#ifndef PLATFORM_N64 + { + MENUITEMTYPE_CHECKBOX, + CHEAT_DUALWIELDALLGUNS, + 0, + (uintptr_t)&cheatGetNameIfUnlocked, + 0, + cheatCheckboxMenuHandler, + }, +#endif { MENUITEMTYPE_SEPARATOR, 0, diff --git a/src/game/game_0b0fd0.c b/src/game/game_0b0fd0.c index 719959461..d30a54946 100644 --- a/src/game/game_0b0fd0.c +++ b/src/game/game_0b0fd0.c @@ -286,7 +286,12 @@ void currentPlayerZoomIn(f32 fovpersec) bool weaponHasFlag(s32 itemid, u32 flag) { struct weapon *weapon = weaponFindById(itemid); - +#ifndef PLATFORM_N64 //always return, that weapon is dual-wieldable if player sets the cheat. + if (cheatIsActive(CHEAT_DUALWIELDALLGUNS) && (flag == WEAPONFLAG_DUALWIELD)) + { + return true; + } +#endif if (!weapon) { return false; } diff --git a/src/game/inv.c b/src/game/inv.c index 825e21fe9..3cba713e1 100644 --- a/src/game/inv.c +++ b/src/game/inv.c @@ -510,6 +510,17 @@ s32 invGiveWeaponsByProp(struct prop *prop) weapon = prop->weapon; weaponnum = weapon->weaponnum; otherweaponnum; +#ifndef PLATFORM_N64 + //This piece of code makes the cheat work in singleplayer. + if (cheatIsActive(CHEAT_DUALWIELDALLGUNS) && !g_Vars.normmplayerisrunning) + { + if(invHasSingleWeaponExcAllGuns(weaponnum) && (invHasDoubleWeaponExcAllGuns(weapon->weaponnum, weapon->weaponnum)==0)) + { + invGiveDoubleWeapon(weaponnum, weaponnum); + numgiven = 2; + } + } +#endif if (cheatIsActive(CHEAT_PERFECTDARKNESS) && weaponnum == WEAPON_NIGHTVISION) { return 1; diff --git a/src/include/constants.h b/src/include/constants.h index e51ec894a..22b5edc10 100644 --- a/src/include/constants.h +++ b/src/include/constants.h @@ -449,6 +449,7 @@ #define CHEAT_DMC 39 #define CHEAT_AR53 40 #define CHEAT_RCP45 41 +#define CHEAT_DUALWIELDALLGUNS 42 #define CHEATFLAG_TIMED 0 #define CHEATFLAG_ALWAYSON 1 From 27faaecda23d6595dc850fe6dd95a4bc2158c554 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sat, 11 May 2024 14:13:51 +0200 Subject: [PATCH 25/68] gcc14 fixes --- src/game/camdraw.c | 2 +- src/game/modeldata/player.c | 2 +- src/game/mplayer/scenarios.c | 1 + src/include/lib/str.h | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/game/camdraw.c b/src/game/camdraw.c index 97498ec6e..ee9b25834 100644 --- a/src/game/camdraw.c +++ b/src/game/camdraw.c @@ -1333,7 +1333,7 @@ void func0f14bdbc(s32 index) s32 value; for (i = 0; i < 30; i++) { - thing->unk0dc[i] = NULL; + thing->unk0dc[i] = 0; } thing->unk094 = 0; diff --git a/src/game/modeldata/player.c b/src/game/modeldata/player.c index ad49e1c88..76e334f95 100644 --- a/src/game/modeldata/player.c +++ b/src/game/modeldata/player.c @@ -18,7 +18,7 @@ struct modeldef g_PlayerModeldef = { 3, 41.161228179932, 0, - NULL, + 0, }; // rodata parent next prev child diff --git a/src/game/mplayer/scenarios.c b/src/game/mplayer/scenarios.c index e2c144d21..aa502ed21 100644 --- a/src/game/mplayer/scenarios.c +++ b/src/game/mplayer/scenarios.c @@ -25,6 +25,7 @@ #include "game/mplayer/mplayer.h" #include "game/pad.h" #include "game/propobj.h" +#include "game/options.h" #include "bss.h" #include "lib/vi.h" #include "lib/snd.h" diff --git a/src/include/lib/str.h b/src/include/lib/str.h index c80ba0dae..1a8da3de0 100644 --- a/src/include/lib/str.h +++ b/src/include/lib/str.h @@ -16,6 +16,7 @@ s32 isalpha(char c); s32 isspace(char c); s32 strtol(const char *src, const char **endptr, s32 base); #else +#include #include #include #endif From ba5694745752ceaa8f3d03674ec97788d1726675 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sat, 11 May 2024 15:53:34 +0200 Subject: [PATCH 26/68] clarify build instructions a bit --- README.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 3451264ff..cc7ca77a4 100644 --- a/README.md +++ b/README.md @@ -94,23 +94,28 @@ Controls can be rebound in `pd.ini`. Default control scheme is as follows: 1. Install [MSYS2](https://www.msys2.org). 2. Open the `MINGW32` prompt. (**NOTE:** _not_ the `MSYS` prompt or the `MINGW64` prompt) 3. Install dependencies: `pacman -S mingw-w64-i686-toolchain mingw-w64-i686-SDL2 mingw-w64-i686-zlib make git` -4. Run `make -f Makefile.port` in the `perfect_dark` directory. -5. The resulting executable will be at `build/ntsc-final-port/pd.exe`. +4. Get the source code: `git clone --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark` +5. Run `make -f Makefile.port`. + * Add ` ROMID=pal-final` or ` ROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively. +6. The resulting executable will be at `build/ntsc-final-port/pd.exe`. +7. If you don't know where you downloaded the source to, you can run `explorer .` to open the current directory. ### Linux 1. Ensure you have gcc, g++ (version 10.0+) and 32-bit versions of SDL2 (version 2.0.12+), libGL and ZLib installed on your system. * On a 64-bit system you also need to have `gcc-multilib` and `g++-multilib` (or your distro's analogues) installed. -2. Run the following command in the `perfect_dark` directory: +2. Get the source code: `git clone --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark` +3. Run the following command: * On a 64-bit system: ```make -f Makefile.port TARGET_PLATFORM=i686-linux``` * On a 32-bit system: ```make -f Makefile.port``` -3. The resulting executable will be at `build/ntsc-final-port/pd.exe`. + * Add ` ROMID=pal-final` or ` ROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively. +4. The resulting executable will be at `build/ntsc-final-port/pd.exe`. Currently only `i686-linux` and `i686-windows` are supported, using `gcc -m32` and `i686-w64-mingw32-gcc` as compilers, respectively. Alternate compilers can be specified by passing `TOOLCHAIN=i686-whatever-` as a command line argument. You can build an executable with PAL or JPN ROM support by adding `ROMID=pal-final` or `ROMID=jpn-final` to the `make` command. -You will need to provide a `jpn-final` or `pal-final` ROM for those, named `pd.jpn-final.z64` or `pd.pal-final.z64`. +You will need to provide a `jpn-final` or `pal-final` ROM to run those, named `pd.jpn-final.z64` or `pd.pal-final.z64`. It might be possible to build a 32-bit ARM executable, but this has not been tested. From 13003121ea82ef82e859dbe5c9ff66ce06c2f829 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sat, 11 May 2024 15:54:52 +0200 Subject: [PATCH 27/68] Update README.md --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cc7ca77a4..4c4e4913a 100644 --- a/README.md +++ b/README.md @@ -93,8 +93,10 @@ Controls can be rebound in `pd.ini`. Default control scheme is as follows: 1. Install [MSYS2](https://www.msys2.org). 2. Open the `MINGW32` prompt. (**NOTE:** _not_ the `MSYS` prompt or the `MINGW64` prompt) -3. Install dependencies: `pacman -S mingw-w64-i686-toolchain mingw-w64-i686-SDL2 mingw-w64-i686-zlib make git` -4. Get the source code: `git clone --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark` +3. Install dependencies: + `pacman -S mingw-w64-i686-toolchain mingw-w64-i686-SDL2 mingw-w64-i686-zlib make git` +4. Get the source code: + `git clone --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark` 5. Run `make -f Makefile.port`. * Add ` ROMID=pal-final` or ` ROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively. 6. The resulting executable will be at `build/ntsc-final-port/pd.exe`. @@ -104,7 +106,8 @@ Controls can be rebound in `pd.ini`. Default control scheme is as follows: 1. Ensure you have gcc, g++ (version 10.0+) and 32-bit versions of SDL2 (version 2.0.12+), libGL and ZLib installed on your system. * On a 64-bit system you also need to have `gcc-multilib` and `g++-multilib` (or your distro's analogues) installed. -2. Get the source code: `git clone --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark` +2. Get the source code: + `git clone --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark` 3. Run the following command: * On a 64-bit system: ```make -f Makefile.port TARGET_PLATFORM=i686-linux``` * On a 32-bit system: ```make -f Makefile.port``` From 15c03275924d5c4c951a430f915f0d7b03f71410 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sun, 12 May 2024 16:22:34 +0200 Subject: [PATCH 28/68] port: better light glare hit detection --- src/game/bg.c | 22 +++++++ src/game/game_13c510.c | 44 ++++--------- src/game/lv.c | 5 ++ src/game/prop.c | 111 +++++++++++++++++++++++++++++++++ src/game/sky.c | 2 +- src/include/game/bg.h | 3 + src/include/game/game_13c510.h | 2 +- src/include/game/prop.h | 4 ++ 8 files changed, 160 insertions(+), 33 deletions(-) diff --git a/src/game/bg.c b/src/game/bg.c index 0b2c0b03b..3eaf35fc9 100644 --- a/src/game/bg.c +++ b/src/game/bg.c @@ -984,7 +984,9 @@ Gfx *bgRenderScene(Gfx *gdl) s16 roomorder[60]; RoomNum roomnums[60]; +#ifdef PLATFORM_N64 g_NumRoomsWithGlares = 0; +#endif if (g_Vars.currentplayer->visionmode == VISIONMODE_XRAY) { gdl = bgRenderSceneInXray(gdl); @@ -1206,6 +1208,7 @@ Gfx *bgRenderScene(Gfx *gdl) gdl = propsRender(gdl, thing->roomnum, RENDERPASS_XLU, roomnumsbyprop); } +#ifdef PLATFORM_N64 // on PC we do this earlier, before prop matrices turn into garbage if (!g_Vars.mplayerisrunning) { artifactsCalculateGlaresForRoom(thing->roomnum); @@ -1213,6 +1216,7 @@ Gfx *bgRenderScene(Gfx *gdl) g_GlareRooms[g_NumRoomsWithGlares++] = thing->roomnum; } } +#endif } #if VERSION < VERSION_NTSC_1_0 @@ -6397,3 +6401,21 @@ void bgFindEnteredRooms(struct coord *bbmin, struct coord *bbmax, RoomNum *rooms end: rooms[len] = -1; } + +#ifndef PLATFORM_N64 + +void bgCalculateGlaresForVisibleRooms(void) +{ + s32 i; + g_NumRoomsWithGlares = 0; + for (i = 1; i < g_Vars.roomcount; i++) { + if (g_Rooms[i].flags & ROOMFLAG_ONSCREEN) { + artifactsCalculateGlaresForRoom(i); + if (g_NumRoomsWithGlares < 100) { + g_GlareRooms[g_NumRoomsWithGlares++] = i; + } + } + } +} + +#endif diff --git a/src/game/game_13c510.c b/src/game/game_13c510.c index 6258fff51..8ac5f0515 100644 --- a/src/game/game_13c510.c +++ b/src/game/game_13c510.c @@ -20,7 +20,7 @@ #include "lib/collision.h" #include "lib/lib_17ce0.h" #include "game/player.h" -f32 fabsf(f32 value); +#include "game/prop.h" #endif u8 *var800a41a0; @@ -104,8 +104,10 @@ s32 func0f13c710(f32 arg0) #ifndef PLATFORM_N64 -bool artifactTestLos(struct coord *spec, struct coord *roompos) +bool artifactTestLos(struct coord *spec, struct coord *roompos, s32 xi, s32 yi) { + s32 i = 0; + if (!g_Vars.currentplayer) { return false; } @@ -115,35 +117,15 @@ bool artifactTestLos(struct coord *spec, struct coord *roompos) endpos.y = roompos->y + spec->y; endpos.z = roompos->z + spec->z; - // get what rooms the LOS goes through - RoomNum outrooms[17], tmprooms[8], srcrooms[2]; - srcrooms[0] = g_Vars.currentplayer->cam_room; - srcrooms[1] = -1; - outrooms[16] = -1; - portal00018148(&g_Vars.currentplayer->cam_pos, &endpos, srcrooms, tmprooms, outrooms, 16); + struct coord gundir2d; + struct coord gunpos2d = {{ 0.f, 0.f, 0.f }}; + struct coord gundir3d; + struct coord gunpos3d = g_Vars.currentplayer->cam_pos; + f32 crosspos[2] = { (f32)xi, (f32)yi }; + cam0f0b4c3c(crosspos, &gundir2d, 1.f); + mtx4RotateVec(camGetProjectionMtxF(), &gundir2d, &gundir3d); - // cheaper LOS test against props first - const u32 cdtype = CDTYPE_OBJS | CDTYPE_DOORS | CDTYPE_PLAYERS | CDTYPE_CHRS; - const u16 geoflags = GEOFLAG_BLOCK_SIGHT | GEOFLAG_BLOCK_SHOOT; - if (!cdTestAToB(&g_Vars.currentplayer->cam_pos, &endpos, outrooms, cdtype, geoflags, true, 1, 0, 0)) { - return false; - } - - // no prop was hit; check for bg hits - struct hitthing hit; - for (s32 i = 0; outrooms[i] != -1; ++i) { - if (bgTestHitInRoom(&g_Vars.currentplayer->cam_pos, &endpos, outrooms[i], &hit)) { - // check if it's far enough away from the end point - if (fabsf(hit.pos.x - endpos.x) >= 0.1f || - fabsf(hit.pos.y - endpos.y) >= 0.1f || - fabsf(hit.pos.z - endpos.z) >= 0.1f) { - return false; - } - } - } - - // nothing hit - return true; + return shotTestLos(&gunpos2d, &gundir2d, &gunpos3d, &gundir3d, &endpos); } #endif @@ -380,7 +362,7 @@ void artifactsCalculateGlaresForRoom(s32 roomnum) if (index < MAX_ARTIFACTS) { #ifndef PLATFORM_N64 - artifact->unk02 = artifactTestLos(&spec, &g_BgRooms[roomnum].pos); + artifact->unk02 = artifactTestLos(&spec, &g_BgRooms[roomnum].pos, xi, yi); #endif artifact->unk04 = func0f13c574(f0) >> 2; artifact->unk08 = &g_ZbufPtr1[viGetWidth() * yi + xi]; diff --git a/src/game/lv.c b/src/game/lv.c index 1c746b77d..c19cfbede 100644 --- a/src/game/lv.c +++ b/src/game/lv.c @@ -1194,6 +1194,11 @@ Gfx *lvRender(Gfx *gdl) autoaimTick(); handsTickAttack(); +#ifndef PLATFORM_N64 + // glares calculated earlier on PC, before prop matrices turn into garbage + bgCalculateGlaresForVisibleRooms(); +#endif + // Calculate lookingatprop if (PLAYERCOUNT() == 1 || g_Vars.coopplayernum >= 0 diff --git a/src/game/prop.c b/src/game/prop.c index 92505fa3a..4dbbba9f0 100644 --- a/src/game/prop.c +++ b/src/game/prop.c @@ -973,6 +973,117 @@ struct prop *shotCalculateHits(s32 handnum, bool isshooting, struct coord *gunpo return result; } +#ifndef PLATFORM_N64 + +/** + * Checks if the specified line of sight (gunpos3d - endpos3d) intersects any props or BG, + * using the same process as shotCalculateHits, except with no side effects and cheap = true. + * Returns true if nothing was hit. + */ +bool shotTestLos(struct coord *gunpos2d, struct coord *gundir2d, struct coord *gunpos3d, struct coord *gundir3d, struct coord *endpos3d) +{ + struct prop **propptr; + struct hitthing sp664; + struct coord delta; + struct shotdata shotdata; + s32 i; + RoomNum rooms[131]; + RoomNum spc8[8]; + RoomNum spb8[8]; + RoomNum *roomsptr; + struct prop *prop; + + shotdata.gunpos3d.x = gunpos3d->x; + shotdata.gunpos3d.y = gunpos3d->y; + shotdata.gunpos3d.z = gunpos3d->z; + + shotdata.gunpos2d.x = gunpos2d->x; + shotdata.gunpos2d.y = gunpos2d->y; + shotdata.gunpos2d.z = gunpos2d->z; + + shotdata.gundir3d.x = gundir3d->x; + shotdata.gundir3d.y = gundir3d->y; + shotdata.gundir3d.z = gundir3d->z; + + shotdata.gundir2d.x = gundir2d->x; + shotdata.gundir2d.y = gundir2d->y; + shotdata.gundir2d.z = gundir2d->z; + + // use falcon2 as a dummy weapon + shotdata.gset.weaponnum = WEAPON_FALCON2; + shotdata.gset.weaponfunc = 0; + shotdata.gset.unk063a = 0; + shotdata.gset.unk0639 = 0; + + shotdata.penetration = 1; + shotdata.distance = 999999999.f; + + for (i = 0; i < ARRAYCOUNT(shotdata.hits); i++) { + shotdata.hits[i].prop = NULL; + shotdata.hits[i].hitpart = 0; + shotdata.hits[i].bboxnode = NULL; + } + + rooms[0] = rooms[130] = -1; + spc8[0] = g_Vars.currentplayer->cam_room; + spc8[1] = -1; + portal00018148(&shotdata.gunpos3d, endpos3d, spc8, spb8, rooms, 30); + + roomsptr = rooms; + + while (*roomsptr != -1) { + roomsptr++; + } + + // Note this is being appended to rooms + bgGetForceOnscreenRooms(roomsptr, 100); + + // Check for BG hits first + for (i = 0; rooms[i] != -1; i++) { + if (bgTestHitInRoom(&shotdata.gunpos3d, endpos3d, rooms[i], &sp664)) { + // check if it's far enough away from the end point + if (fabsf(sp664.pos.x - endpos3d->x) >= 0.1f || + fabsf(sp664.pos.y - endpos3d->y) >= 0.1f || + fabsf(sp664.pos.z - endpos3d->z) >= 0.1f) { + return false; + } + } + } + + // didn't hit any bg, shrink distance to the line size + delta.x = endpos3d->x - gunpos3d->x; + delta.y = endpos3d->y - gunpos3d->y; + delta.z = endpos3d->z - gunpos3d->z; + shotdata.distance = sqrtf(delta.x * delta.x + delta.y * delta.y + delta.z * delta.z); + + // and check props + propptr = g_Vars.endonscreenprops - 1; + while (propptr >= g_Vars.onscreenprops) { + prop = *propptr; + if (prop) { + if (prop->type == PROPTYPE_CHR + || (prop->type == PROPTYPE_PLAYER && prop->chr && playermgrGetPlayerNumByProp(prop) != g_Vars.currentplayernum)) { + chrTestHit(prop, &shotdata, false, true); + } else if (prop->type == PROPTYPE_WEAPON || prop->type == PROPTYPE_DOOR + || (prop->type == PROPTYPE_OBJ && prop->obj->type != OBJTYPE_GLASS && prop->obj->type != OBJTYPE_TINTEDGLASS)) { + objTestHit(prop, &shotdata); + } + if (shotdata.hits[0].prop) { + // ignore some glass parts and shields + if (shotdata.hits[0].slowsbullet && shotdata.hits[0].hitthing.texturenum != 10000) { + return false; + } + } + } + propptr--; + } + + // did not hit anything + return true; +} + +#endif + struct prop *propFindAimingAt(s32 handnum, bool isshooting, u32 context) { struct coord gundir2d; diff --git a/src/game/sky.c b/src/game/sky.c index e46110911..e610cad83 100644 --- a/src/game/sky.c +++ b/src/game/sky.c @@ -2518,7 +2518,7 @@ void skyCreateSunArtifact(struct artifact *artifact, s32 x, s32 y) sunpos.x = env->suns[i].pos[0]; sunpos.y = env->suns[i].pos[1]; sunpos.z = env->suns[i].pos[2]; - artifact->unk02 = artifactTestLos(&sunpos, &zero) * 0xfffc; + artifact->unk02 = artifactTestLos(&sunpos, &zero, x, y) * 0xfffc; #endif artifact->unk08 = &g_ZbufPtr1[(s32)camGetScreenWidth() * y + x]; artifact->unk0c.u16_2 = x; diff --git a/src/include/game/bg.h b/src/include/game/bg.h index 0ac8645ca..89b6c7550 100644 --- a/src/include/game/bg.h +++ b/src/include/game/bg.h @@ -102,5 +102,8 @@ s32 bgFindPortalBetweenPositions(struct coord *pos1, struct coord *pos2); bool bgIsBboxOverlapping(struct coord *arg0, struct coord *arg1, struct coord *arg2, struct coord *arg3); void bgCalculatePortalBbox(s32 portalnum, struct coord *bbmin, struct coord *bbmax); void bgFindEnteredRooms(struct coord *bbmin, struct coord *upper, RoomNum *rooms, s32 maxlen, bool arg4); +#ifndef PLATFORM_N64 +void bgCalculateGlaresForVisibleRooms(void); +#endif #endif diff --git a/src/include/game/game_13c510.h b/src/include/game/game_13c510.h index 187cbc6ce..d8ee2f6dd 100644 --- a/src/include/game/game_13c510.h +++ b/src/include/game/game_13c510.h @@ -14,7 +14,7 @@ Gfx *artifactsConfigureForGlares(Gfx *gdl); Gfx *artifactsUnconfigureForGlares(Gfx *gdl); Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum); #ifndef PLATFORM_N64 -bool artifactTestLos(struct coord *spec, struct coord *roompos); +bool artifactTestLos(struct coord *spec, struct coord *roompos, s32 xi, s32 yi); #endif #endif diff --git a/src/include/game/prop.h b/src/include/game/prop.h index 2105cc061..cdbab1737 100644 --- a/src/include/game/prop.h +++ b/src/include/game/prop.h @@ -65,4 +65,8 @@ void propsDefragRoomProps(void); void propGetBbox(struct prop *prop, f32 *radius, f32 *ymax, f32 *ymin); bool propUpdateGeometry(struct prop *prop, u8 **start, u8 **end); +#ifndef PLATFORM_N64 +bool shotTestLos(struct coord *gunpos2d, struct coord *gundir2d, struct coord *gunpos3d, struct coord *gundir3d, struct coord *endpos3d); +#endif + #endif From ce6424117e38be1e2951ef44f54b9af9db83ec66 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sun, 12 May 2024 16:31:45 +0200 Subject: [PATCH 29/68] port: re-disable glare calculation in multiplayer they don't render anyway --- src/game/bg.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/game/bg.c b/src/game/bg.c index 3eaf35fc9..c6dddc699 100644 --- a/src/game/bg.c +++ b/src/game/bg.c @@ -6407,12 +6407,16 @@ end: void bgCalculateGlaresForVisibleRooms(void) { s32 i; + g_NumRoomsWithGlares = 0; - for (i = 1; i < g_Vars.roomcount; i++) { - if (g_Rooms[i].flags & ROOMFLAG_ONSCREEN) { - artifactsCalculateGlaresForRoom(i); - if (g_NumRoomsWithGlares < 100) { - g_GlareRooms[g_NumRoomsWithGlares++] = i; + + if (!g_Vars.mplayerisrunning) { + for (i = 1; i < g_Vars.roomcount; i++) { + if (g_Rooms[i].flags & ROOMFLAG_ONSCREEN) { + artifactsCalculateGlaresForRoom(i); + if (g_NumRoomsWithGlares < 100) { + g_GlareRooms[g_NumRoomsWithGlares++] = i; + } } } } From dca1e1752bd8d6b860dc45cfc39d278b7040084a Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sun, 12 May 2024 16:48:33 +0200 Subject: [PATCH 30/68] port: remove remnants of masked/blended texture support --- port/fast3d/gfx_cc.cpp | 18 -------------- port/fast3d/gfx_cc.h | 23 ++--------------- port/fast3d/gfx_opengl.cpp | 51 +------------------------------------- port/fast3d/gfx_pc.cpp | 6 ----- 4 files changed, 3 insertions(+), 95 deletions(-) diff --git a/port/fast3d/gfx_cc.cpp b/port/fast3d/gfx_cc.cpp index 066612843..6aaaa655e 100644 --- a/port/fast3d/gfx_cc.cpp +++ b/port/fast3d/gfx_cc.cpp @@ -26,10 +26,6 @@ void gfx_cc_get_features(uint64_t shader_id0, uint32_t shader_id1, struct CCFeat cc_features->used_textures[0] = false; cc_features->used_textures[1] = false; - cc_features->used_masks[0] = false; - cc_features->used_masks[1] = false; - cc_features->used_blend[0] = false; - cc_features->used_blend[1] = false; cc_features->num_inputs = 0; for (int c = 0; c < 2; c++) { @@ -60,18 +56,4 @@ void gfx_cc_get_features(uint64_t shader_id0, uint32_t shader_id1, struct CCFeat cc_features->color_alpha_same[c] = ((shader_id0 >> c * 32) & 0xffff) == ((shader_id0 >> (c * 32 + 16)) & 0xffff); } - - if (cc_features->used_textures[0] && (shader_id1 & SHADER_OPT_TEXEL0_MASK)) { - cc_features->used_masks[0] = true; - } - if (cc_features->used_textures[1] && (shader_id1 & SHADER_OPT_TEXEL1_MASK)) { - cc_features->used_masks[1] = true; - } - - if (cc_features->used_textures[0] && (shader_id1 & SHADER_OPT_TEXEL0_BLEND)) { - cc_features->used_blend[0] = true; - } - if (cc_features->used_textures[1] && (shader_id1 & SHADER_OPT_TEXEL1_BLEND)) { - cc_features->used_blend[1] = true; - } } diff --git a/port/fast3d/gfx_cc.h b/port/fast3d/gfx_cc.h index cfd00c9f6..6d51a2392 100644 --- a/port/fast3d/gfx_cc.h +++ b/port/fast3d/gfx_cc.h @@ -8,17 +8,6 @@ #include #endif -/*enum { - CC_0, - CC_TEXEL0, - CC_TEXEL1, - CC_PRIM, - CC_SHADE, - CC_ENV, - CC_TEXEL0A, - CC_LOD -};*/ - enum { SHADER_0, SHADER_INPUT_1, @@ -49,11 +38,7 @@ enum { #define SHADER_OPT_TEXEL0_CLAMP_T (1 << 9) #define SHADER_OPT_TEXEL1_CLAMP_S (1 << 10) #define SHADER_OPT_TEXEL1_CLAMP_T (1 << 11) -#define SHADER_OPT_TEXEL0_MASK (1 << 12) -#define SHADER_OPT_TEXEL1_MASK (1 << 13) -#define SHADER_OPT_TEXEL0_BLEND (1 << 14) -#define SHADER_OPT_TEXEL1_BLEND (1 << 15) -#define SHADER_OPT_BLUR (1 << 16) +#define SHADER_OPT_BLUR (1 << 12) struct ColorCombinerKey { uint64_t combine_mode; @@ -61,10 +46,8 @@ struct ColorCombinerKey { auto operator<=>(const ColorCombinerKey&) const = default; }; -#define SHADER_MAX_TEXTURES 6 +#define SHADER_MAX_TEXTURES 2 #define SHADER_FIRST_TEXTURE 0 -#define SHADER_FIRST_MASK_TEXTURE 2 -#define SHADER_FIRST_REPLACEMENT_TEXTURE 4 struct CCFeatures { uint8_t c[2][2][4]; @@ -78,8 +61,6 @@ struct CCFeatures { bool opt_grayscale; bool opt_blur; bool used_textures[2]; - bool used_masks[2]; - bool used_blend[2]; bool clamp[2][2]; int num_inputs; bool do_single[2][2]; diff --git a/port/fast3d/gfx_opengl.cpp b/port/fast3d/gfx_opengl.cpp index 86efd96bc..f486628a5 100644 --- a/port/fast3d/gfx_opengl.cpp +++ b/port/fast3d/gfx_opengl.cpp @@ -373,18 +373,6 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad if (cc_features.used_textures[1]) { append_line(fs_buf, &fs_len, "uniform sampler2D uTex1;"); } - if (cc_features.used_masks[0]) { - append_line(fs_buf, &fs_len, "uniform sampler2D uTexMask0;"); - } - if (cc_features.used_masks[1]) { - append_line(fs_buf, &fs_len, "uniform sampler2D uTexMask1;"); - } - if (cc_features.used_blend[0]) { - append_line(fs_buf, &fs_len, "uniform sampler2D uTexBlend0;"); - } - if (cc_features.used_blend[1]) { - append_line(fs_buf, &fs_len, "uniform sampler2D uTexBlend1;"); - } append_line(fs_buf, &fs_len, "uniform int frame_count;"); append_line(fs_buf, &fs_len, "uniform float noise_scale;"); @@ -473,24 +461,7 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad } } - fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = hookTexture2D(uTex%d, vTexCoordAdj%d, texSize%d);\n", i, - i, i, i); - if (cc_features.used_masks[i]) { - fs_len += sprintf(fs_buf + fs_len, "vec2 maskSize%d = textureSize(uTexMask%d, 0);\n", i, i); - - fs_len += - sprintf(fs_buf + fs_len, - "vec4 maskVal%d = hookTexture2D(uTexMask%d, vTexCoordAdj%d, maskSize%d);\n", i, i, i, i); - if (cc_features.used_blend[i]) { - fs_len += sprintf(fs_buf + fs_len, - "vec4 blendVal%d = hookTexture2D(uTexBlend%d, vTexCoordAdj%d, texSize%d);\n", i, - i, i, i); - } else { - fs_len += sprintf(fs_buf + fs_len, "vec4 blendVal%d = vec4(0, 0, 0, 0);\n", i); - } - - fs_len += sprintf(fs_buf + fs_len, "texVal%d = mix(texVal%d, blendVal%d, maskVal%d.a);\n", i, i, i, i); - } + fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = hookTexture2D(uTex%d, vTexCoordAdj%d, texSize%d);\n", i, i, i, i); } } @@ -653,10 +624,6 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad prg->num_inputs = cc_features.num_inputs; prg->used_textures[0] = cc_features.used_textures[0]; prg->used_textures[1] = cc_features.used_textures[1]; - prg->used_textures[2] = cc_features.used_masks[0]; - prg->used_textures[3] = cc_features.used_masks[1]; - prg->used_textures[4] = cc_features.used_blend[0]; - prg->used_textures[5] = cc_features.used_blend[1]; prg->num_floats = num_floats; prg->num_attribs = cnt; @@ -670,22 +637,6 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad GLint sampler_location = glGetUniformLocation(shader_program, "uTex1"); glUniform1i(sampler_location, 1); } - if (cc_features.used_masks[0]) { - GLint sampler_location = glGetUniformLocation(shader_program, "uTexMask0"); - glUniform1i(sampler_location, 2); - } - if (cc_features.used_masks[1]) { - GLint sampler_location = glGetUniformLocation(shader_program, "uTexMask1"); - glUniform1i(sampler_location, 3); - } - if (cc_features.used_blend[0]) { - GLint sampler_location = glGetUniformLocation(shader_program, "uTexBlend0"); - glUniform1i(sampler_location, 4); - } - if (cc_features.used_blend[1]) { - GLint sampler_location = glGetUniformLocation(shader_program, "uTexBlend1"); - glUniform1i(sampler_location, 5); - } prg->frame_count_location = glGetUniformLocation(shader_program, "frame_count"); prg->noise_scale_location = glGetUniformLocation(shader_program, "noise_scale"); diff --git a/port/fast3d/gfx_pc.cpp b/port/fast3d/gfx_pc.cpp index cdd0d3e3c..6ddb8e168 100644 --- a/port/fast3d/gfx_pc.cpp +++ b/port/fast3d/gfx_pc.cpp @@ -154,8 +154,6 @@ struct LoadedTexture { uint32_t line_size_bytes; uint32_t tex_flags; struct RawTexMetadata raw_tex_metadata; - bool masked; - bool blended; }; static struct RDP { @@ -1937,8 +1935,6 @@ static void gfx_dp_load_block(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t loaded_texture.tex_flags = rdp.texture_to_load.tex_flags; loaded_texture.raw_tex_metadata = rdp.texture_to_load.raw_tex_metadata; loaded_texture.addr = rdp.texture_to_load.addr; - loaded_texture.masked = false; - loaded_texture.blended = false; rdp.textures_changed[0] = rdp.textures_changed[1] = true; } @@ -1979,8 +1975,6 @@ static void gfx_dp_load_tile(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t loaded_texture.tex_flags = rdp.texture_to_load.tex_flags; loaded_texture.raw_tex_metadata = rdp.texture_to_load.raw_tex_metadata; loaded_texture.addr = rdp.texture_to_load.addr + start_offset_bytes; - loaded_texture.masked = false; - loaded_texture.blended = false; rdp.texture_tile[tile].uls = uls; rdp.texture_tile[tile].ult = ult; From 536c76679350fc79c46f7ef6e75294df0549a728 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sun, 12 May 2024 17:09:50 +0200 Subject: [PATCH 31/68] port: more gfx_pc cleanup --- port/fast3d/gfx_pc.cpp | 191 +++-------------------------------------- src/game/player.c | 8 -- 2 files changed, 12 insertions(+), 187 deletions(-) diff --git a/port/fast3d/gfx_pc.cpp b/port/fast3d/gfx_pc.cpp index 6ddb8e168..fbaf56be2 100644 --- a/port/fast3d/gfx_pc.cpp +++ b/port/fast3d/gfx_pc.cpp @@ -55,8 +55,7 @@ using namespace std; #define RATIO_Y (gfx_current_dimensions.height / (float)SCREEN_HEIGHT) #define MAX_BUFFERED 256 -// #define MAX_LIGHTS 2 -#define MAX_LIGHTS 32 +#define MAX_LIGHTS 4 #define MAX_VERTICES 128 #define MAX_VERTEX_COLORS 64 @@ -235,7 +234,6 @@ static size_t buf_vbo_num_tris; static struct GfxWindowManagerAPI* gfx_wapi; static struct GfxRenderingAPI* gfx_rapi; -static int markerOn; static uintptr_t segmentPointers[16]; struct FBInfo { @@ -1195,8 +1193,6 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo struct LoadedVertex* v3 = &rsp.loaded_vertices[vtx3_idx]; struct LoadedVertex* v_arr[3] = { v1, v2, v3 }; - // if (rand()%2) return; - if ((rsp.extra_geometry_mode & G_NO_CLIPPING_EXT) == 0) { if (v1->clip_rej & v2->clip_rej & v3->clip_rej) { // The whole triangle lies outside the visible area @@ -1274,20 +1270,18 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo rdp.viewport_or_scissor_changed = false; } - uint64_t cc_id = rdp.combine_mode; uint64_t cc_options = 0; bool use_alpha = (rdp.other_mode_l & (3 << 20)) == (G_BL_CLR_MEM << 20) && (rdp.other_mode_l & (3 << 16)) == (G_BL_1MA << 16); - bool use_fog = ((rdp.other_mode_l >> 30) == G_BL_CLR_FOG) || ((rdp.other_mode_l >> 26) == G_BL_A_FOG); - bool texture_edge = (rdp.other_mode_l & CVG_X_ALPHA) == CVG_X_ALPHA; - bool use_noise = (rdp.other_mode_l & (3U << G_MDSFT_ALPHACOMPARE)) == G_AC_DITHER; - bool use_2cyc = (rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)) == G_CYC_2CYCLE; - bool alpha_threshold = (rdp.other_mode_l & (3U << G_MDSFT_ALPHACOMPARE)) == G_AC_THRESHOLD; - bool invisible = - (rdp.other_mode_l & (3 << 24)) == (G_BL_0 << 24) && (rdp.other_mode_l & (3 << 20)) == (G_BL_CLR_MEM << 20); - bool use_grayscale = rdp.grayscale; - bool use_modulate = use_alpha && (rsp.extra_geometry_mode & G_MODULATE_EXT) != 0; - bool use_blur = (rdp.other_mode_h & (3U << G_MDSFT_TEXTFILT)) == G_TF_BLUR_EXT; + const bool use_fog = ((rdp.other_mode_l >> 30) == G_BL_CLR_FOG) || ((rdp.other_mode_l >> 26) == G_BL_A_FOG); + const bool texture_edge = (rdp.other_mode_l & CVG_X_ALPHA) == CVG_X_ALPHA; + const bool use_noise = (rdp.other_mode_l & (3U << G_MDSFT_ALPHACOMPARE)) == G_AC_DITHER; + const bool use_2cyc = (rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)) == G_CYC_2CYCLE; + const bool alpha_threshold = (rdp.other_mode_l & (3U << G_MDSFT_ALPHACOMPARE)) == G_AC_THRESHOLD; + const bool invisible = (rdp.other_mode_l & (3 << 24)) == (G_BL_0 << 24) && (rdp.other_mode_l & (3 << 20)) == (G_BL_CLR_MEM << 20); + const bool use_grayscale = rdp.grayscale; + const bool use_modulate = use_alpha && (rsp.extra_geometry_mode & G_MODULATE_EXT) != 0; + const bool use_blur = (rdp.other_mode_h & (3U << G_MDSFT_TEXTFILT)) == G_TF_BLUR_EXT; if (texture_edge) { use_alpha = true; @@ -1489,19 +1483,9 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo if (clampS) { buf_vbo[buf_vbo_len++] = (tex_width2[t] - 0.5f) / tex_width[t]; } -#ifdef __WIIU__ - else { - buf_vbo[buf_vbo_len++] = 0.0f; - } -#endif if (clampT) { buf_vbo[buf_vbo_len++] = (tex_height2[t] - 0.5f) / tex_height[t]; } -#ifdef __WIIU__ - else { - buf_vbo[buf_vbo_len++] = 0.0f; - } -#endif } if (use_fog) { @@ -1583,27 +1567,14 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo buf_vbo[buf_vbo_len++] = color->r / 255.0f; buf_vbo[buf_vbo_len++] = color->g / 255.0f; buf_vbo[buf_vbo_len++] = color->b / 255.0f; -#ifdef __WIIU__ - // padding - if (!use_alpha) { - buf_vbo[buf_vbo_len++] = 1.0f; - } -#endif } else { buf_vbo[buf_vbo_len++] = color->a / 255.0f; } } } - - // struct RGBA *color = &v_arr[i]->color; - // buf_vbo[buf_vbo_len++] = color->r / 255.0f; - // buf_vbo[buf_vbo_len++] = color->g / 255.0f; - // buf_vbo[buf_vbo_len++] = color->b / 255.0f; - // buf_vbo[buf_vbo_len++] = color->a / 255.0f; } if (++buf_vbo_num_tris == MAX_BUFFERED) { - // if (++buf_vbo_num_tris == 1) { gfx_flush(); } } @@ -1738,38 +1709,21 @@ static void gfx_sp_movemem(uint8_t index, uint8_t offset, const void* data) { rsp.lookat_enabled = (index == 0) || (rsp.lookat[1].dir[0] || rsp.lookat[1].dir[1]); rsp.lights_changed = true; break; -#ifdef F3DEX_GBI_2 - case G_MV_LIGHT: { - int lightidx = offset / 24 - 2; - if (lightidx >= 0 && lightidx <= MAX_LIGHTS) { // skip lookat - // NOTE: reads out of bounds if it is an ambient light - memcpy(rsp.current_lights + lightidx, data, sizeof(Light_t)); - } else if (lightidx < 0) { - memcpy(rsp.lookat + offset / 24, data, sizeof(Light_t)); - } - break; - } -#else case G_MV_L0: case G_MV_L1: case G_MV_L2: // NOTE: reads out of bounds if it is an ambient light memcpy(rsp.current_lights + (index - G_MV_L0) / 2, data, sizeof(Light_t)); break; -#endif } } static void gfx_sp_moveword(uint8_t index, uint16_t offset, uintptr_t data) { switch (index) { case G_MW_NUMLIGHT: -#ifdef F3DEX_GBI_2 - rsp.current_num_lights = data / 24 + 1; // add ambient light -#else // Ambient light is included // The 31th bit is a flag that lights should be recalculated rsp.current_num_lights = (data - 0x80000000U) / 32; -#endif rsp.lights_changed = 1; break; case G_MW_FOG: @@ -1986,38 +1940,6 @@ static void gfx_dp_load_tile(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t rdp.textures_changed[0] = rdp.textures_changed[1] = true; } -/*static uint8_t color_comb_component(uint32_t v) { - switch (v) { - case G_CCMUX_TEXEL0: - return CC_TEXEL0; - case G_CCMUX_TEXEL1: - return CC_TEXEL1; - case G_CCMUX_PRIMITIVE: - return CC_PRIM; - case G_CCMUX_SHADE: - return CC_SHADE; - case G_CCMUX_ENVIRONMENT: - return CC_ENV; - case G_CCMUX_TEXEL0_ALPHA: - return CC_TEXEL0A; - case G_CCMUX_LOD_FRACTION: - return CC_LOD; - default: - return CC_0; - } -} - -static inline uint32_t color_comb(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { - return color_comb_component(a) | - (color_comb_component(b) << 3) | - (color_comb_component(c) << 6) | - (color_comb_component(d) << 9); -} - -static void gfx_dp_set_combine_mode(uint32_t rgb, uint32_t alpha) { - rdp.combine_mode = rgb | (alpha << 12); -}*/ - static void gfx_dp_set_combine_mode(uint32_t rgb, uint32_t alpha, uint32_t rgb_cyc2, uint32_t alpha_cyc2) { rdp.combine_mode = rgb | (alpha << 16) | ((uint64_t)rgb_cyc2 << 28) | ((uint64_t)alpha_cyc2 << 44); } @@ -2147,7 +2069,6 @@ static void gfx_draw_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lr static void gfx_dp_texture_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry, uint8_t tile, int16_t uls, int16_t ult, int16_t dsdx, int16_t dtdy, bool flip) { - // printf("render %d at %d\n", tile, lrx); uint64_t saved_combine_mode = rdp.combine_mode; if ((rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)) == G_CYC_COPY) { // Per RDP Command Summary Set Tile's shift s and this dsdx should be set to 4 texels @@ -2357,49 +2278,23 @@ static void gfx_run_dl(Gfx* cmd) { case G_NOOP: break; case G_MTX: { -#ifdef F3DEX_GBI_2 - gfx_sp_matrix(C0(0, 8) ^ G_MTX_PUSH, (const int32_t*)seg_addr(cmd->words.w1)); -#else gfx_sp_matrix(C0(16, 8), (const int32_t*)seg_addr(cmd->words.w1)); -#endif break; } case (uint8_t)G_POPMTX: -#ifdef F3DEX_GBI_2 - gfx_sp_pop_matrix(cmd->words.w1 / 64); -#else gfx_sp_pop_matrix(1); -#endif break; case G_MOVEMEM: -#ifdef F3DEX_GBI_2 - gfx_sp_movemem(C0(0, 8), C0(8, 8) * 8, seg_addr(cmd->words.w1)); -#else gfx_sp_movemem(C0(16, 8), 0, seg_addr(cmd->words.w1)); -#endif break; case (uint8_t)G_MOVEWORD: -#ifdef F3DEX_GBI_2 - gfx_sp_moveword(C0(16, 8), C0(0, 16), cmd->words.w1); -#else gfx_sp_moveword(C0(0, 8), C0(8, 16), cmd->words.w1); -#endif break; case (uint8_t)G_TEXTURE: -#ifdef F3DEX_GBI_2 - gfx_sp_texture(C1(16, 16), C1(0, 16), C0(11, 3), C0(8, 3), C0(1, 7)); -#else gfx_sp_texture(C1(16, 16), C1(0, 16), C0(11, 3), C0(8, 3), C0(0, 8)); -#endif break; case G_VTX: -#ifdef F3DEX_GBI_2 - gfx_sp_vertex(C0(12, 8), C0(1, 7) - C0(12, 8), (const Vtx*)seg_addr(cmd->words.w1)); -#elif defined(F3DEX_GBI) || defined(F3DLP_GBI) - gfx_sp_vertex(C0(10, 6), C0(16, 8) / 2, (const Vtx*)seg_addr(cmd->words.w1)); -#else gfx_sp_vertex(C0(0, 16) / sizeof(Vtx), C0(16, 4), (const Vtx*)seg_addr(cmd->words.w1)); -#endif break; case G_DL: if (C0(16, 1) == 0) { @@ -2415,17 +2310,7 @@ static void gfx_run_dl(Gfx* cmd) { } break; case (uint8_t)G_ENDDL: - - // if (markerOn) - // printf("END DL ON MARKER\n"); - - markerOn = false; return; -#ifdef F3DEX_GBI_2 - case G_GEOMETRYMODE: - gfx_sp_geometry_mode(~C0(0, 24), cmd->words.w1); - break; -#else case (uint8_t)G_SETGEOMETRYMODE: gfx_sp_geometry_mode(0, cmd->words.w1); break; @@ -2435,43 +2320,17 @@ static void gfx_run_dl(Gfx* cmd) { case G_EXTRAGEOMETRYMODE_EXT: gfx_sp_extra_geometry_mode(~C0(0, 24), cmd->words.w1); break; -#endif case (uint8_t)G_TRI1: -#ifdef F3DEX_GBI_2 - gfx_sp_tri1(C0(16, 8) / 2, C0(8, 8) / 2, C0(0, 8) / 2, false); -#elif defined(F3DEX_GBI) || defined(F3DLP_GBI) - gfx_sp_tri1(C1(16, 8) / 2, C1(8, 8) / 2, C1(0, 8) / 2, false); -#else gfx_sp_tri1(C1(16, 8) / 10, C1(8, 8) / 10, C1(0, 8) / 10, false); -#endif break; -#ifdef F3DEX_GBI_2 - case G_QUAD: { - [[fallthrough]]; - } -#endif -#if defined(F3DEX_GBI) || defined(F3DLP_GBI) - case (uint8_t)G_TRI2: - gfx_sp_tri1(C0(16, 8) / 2, C0(8, 8) / 2, C0(0, 8) / 2, false); - gfx_sp_tri1(C1(16, 8) / 2, C1(8, 8) / 2, C1(0, 8) / 2, false); - break; -#endif case (uint8_t)G_TRI4: gfx_sp_tri4(cmd); break; case (uint8_t)G_SETOTHERMODE_L: -#ifdef F3DEX_GBI_2 - gfx_sp_set_other_mode(31 - C0(8, 8) - C0(0, 8), C0(0, 8) + 1, cmd->words.w1); -#else gfx_sp_set_other_mode(C0(8, 8), C0(0, 8), cmd->words.w1); -#endif break; case (uint8_t)G_SETOTHERMODE_H: -#ifdef F3DEX_GBI_2 - gfx_sp_set_other_mode(63 - C0(8, 8) - C0(0, 8), C0(0, 8) + 1, (uint64_t)cmd->words.w1 << 32); -#else gfx_sp_set_other_mode(C0(8, 8) + 32, C0(0, 8), (uint64_t)cmd->words.w1 << 32); -#endif break; case G_COL: gfx_sp_set_vertex_colors(C0(0, 16) / 4, (NormalColor *)seg_addr(cmd->words.w1)); @@ -2534,19 +2393,6 @@ static void gfx_run_dl(Gfx* cmd) { case G_TEXRECTFLIP: { int32_t lrx, lry, tile, ulx, uly; uint32_t uls, ult, dsdx, dtdy; -#ifdef F3DEX_GBI_2E - lrx = (int32_t)(C0(0, 24) << 8) >> 8; - lry = (int32_t)(C1(0, 24) << 8) >> 8; - tile = C1(24, 3); - ++cmd; - ulx = (int32_t)(C0(0, 24) << 8) >> 8; - uly = (int32_t)(C1(0, 24) << 8) >> 8; - ++cmd; - uls = C0(16, 16); - ult = C0(0, 16); - dsdx = C1(16, 16); - dtdy = C1(0, 16); -#else lrx = C0(12, 12); lry = C0(0, 12); tile = C1(24, 3); @@ -2558,26 +2404,12 @@ static void gfx_run_dl(Gfx* cmd) { ++cmd; dsdx = C1(16, 16); dtdy = C1(0, 16); -#endif gfx_dp_texture_rectangle(ulx, uly, lrx, lry, tile, uls, ult, dsdx, dtdy, opcode == G_TEXRECTFLIP); break; } case G_FILLRECT: -#ifdef F3DEX_GBI_2E - { - int32_t lrx, lry, ulx, uly; - lrx = (int32_t)(C0(0, 24) << 8) >> 8; - lry = (int32_t)(C1(0, 24) << 8) >> 8; - ++cmd; - ulx = (int32_t)(C0(0, 24) << 8) >> 8; - uly = (int32_t)(C1(0, 24) << 8) >> 8; - gfx_dp_fill_rectangle(ulx, uly, lrx, lry); - break; - } -#else gfx_dp_fill_rectangle(C1(12, 12), C1(0, 12), C0(12, 12), C0(0, 12)); break; -#endif case G_FILLRECT_WIDE_EXT: { int32_t lrx, lry, ulx, uly; lrx = (int32_t)(C0(0, 24) << 8) >> 8; @@ -2663,8 +2495,9 @@ static void gfx_run_dl(Gfx* cmd) { case (uint8_t)G_RDPHALF_1: case (uint8_t)G_RDPHALF_2: case (uint8_t)G_RDPHALF_CONT: - // TODO: skyRender uses these to render some types of skies and skybox water + // on N64 skyRender uses these to render some types of skies and skybox water // by issuing low-level ucode commands G_TRI_FILL and G_TRI_SHADE_TXTR + // the port renders the sky in a different manner break; case G_RDPFLUSH_EXT: gfx_flush(); diff --git a/src/game/player.c b/src/game/player.c index 36c10511b..eb4e2c891 100644 --- a/src/game/player.c +++ b/src/game/player.c @@ -4594,20 +4594,12 @@ Gfx *playerRenderHud(Gfx *gdl) && ((g_Vars.currentplayer->devicesactive & ~g_Vars.currentplayer->devicesinhibit) & DEVICE_NIGHTVISION)) { gdl = bviewDrawNvLens(gdl); gdl = bviewDrawNvBinoculars(gdl); -#ifndef PLATFORM_N64 - // turn off "greenscale" - gDPGrayscaleEXT(gdl++, G_OFF); -#endif } else if (g_Vars.currentplayer->isdead == false && g_InCutscene == 0 && (!g_Vars.currentplayer->eyespy || (g_Vars.currentplayer->eyespy && !g_Vars.currentplayer->eyespy->active)) && ((g_Vars.currentplayer->devicesactive & ~g_Vars.currentplayer->devicesinhibit) & DEVICE_IRSCANNER)) { gdl = bviewDrawIrLens(gdl); gdl = bviewDrawIrBinoculars(gdl); -#ifndef PLATFORM_N64 - // turn off "redscale" - gDPGrayscaleEXT(gdl++, G_OFF); -#endif } if (g_Vars.currentplayer->eyesshutfrac > 0) { From f86746364fe15890d95c800599ed3f3a9cc27296 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sun, 12 May 2024 17:12:37 +0200 Subject: [PATCH 32/68] port: no need to explicitly disable player collision when tracing light glares --- src/game/game_13c510.c | 9 --------- src/game/prop.c | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/game/game_13c510.c b/src/game/game_13c510.c index 8ac5f0515..c2b4b81e9 100644 --- a/src/game/game_13c510.c +++ b/src/game/game_13c510.c @@ -168,11 +168,6 @@ void artifactsCalculateGlaresForRoom(s32 roomnum) struct coord *campos = &g_Vars.currentplayer->cam_pos; struct artifact *artifact; -#ifndef PLATFORM_N64 - const bool prevperim = g_Vars.currentplayer->bondperimenabled; - playerSetPerimEnabled(g_Vars.currentplayer->prop, false); -#endif - if (g_Rooms[roomnum].gfxdata != NULL && g_Rooms[roomnum].loaded240) { numlights = g_Rooms[roomnum].gfxdata->numlights; @@ -378,10 +373,6 @@ void artifactsCalculateGlaresForRoom(s32 roomnum) } } } - -#ifndef PLATFORM_N64 - playerSetPerimEnabled(g_Vars.currentplayer->prop, prevperim); -#endif } u8 func0f13d3c4(u8 arg0, u8 arg1) diff --git a/src/game/prop.c b/src/game/prop.c index 4dbbba9f0..ae8da24f2 100644 --- a/src/game/prop.c +++ b/src/game/prop.c @@ -1062,7 +1062,7 @@ bool shotTestLos(struct coord *gunpos2d, struct coord *gundir2d, struct coord *g prop = *propptr; if (prop) { if (prop->type == PROPTYPE_CHR - || (prop->type == PROPTYPE_PLAYER && prop->chr && playermgrGetPlayerNumByProp(prop) != g_Vars.currentplayernum)) { + || (prop->type == PROPTYPE_PLAYER && prop->chr && (g_Vars.in_cutscene || playermgrGetPlayerNumByProp(prop) != g_Vars.currentplayernum))) { chrTestHit(prop, &shotdata, false, true); } else if (prop->type == PROPTYPE_WEAPON || prop->type == PROPTYPE_DOOR || (prop->type == PROPTYPE_OBJ && prop->obj->type != OBJTYPE_GLASS && prop->obj->type != OBJTYPE_TINTEDGLASS)) { From 9755f3ab41d6aa7611621bcd0e38f03b99a0c9cf Mon Sep 17 00:00:00 2001 From: fgsfds Date: Mon, 13 May 2024 00:28:19 +0200 Subject: [PATCH 33/68] port: even more gfx_pc cleanup --- port/fast3d/gfx_cc.h | 3 ++- port/fast3d/gfx_pc.cpp | 27 +++++++++++---------------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/port/fast3d/gfx_cc.h b/port/fast3d/gfx_cc.h index 6d51a2392..5fd4797c7 100644 --- a/port/fast3d/gfx_cc.h +++ b/port/fast3d/gfx_cc.h @@ -23,7 +23,8 @@ enum { SHADER_TEXEL1A, SHADER_1, SHADER_COMBINED, - SHADER_NOISE + SHADER_NOISE, + SHADER_LOD_FRAC, }; #define SHADER_OPT_ALPHA (1 << 0) diff --git a/port/fast3d/gfx_pc.cpp b/port/fast3d/gfx_pc.cpp index fbaf56be2..c91a135ea 100644 --- a/port/fast3d/gfx_pc.cpp +++ b/port/fast3d/gfx_pc.cpp @@ -33,8 +33,6 @@ uintptr_t gfxFramebuffer; -using namespace std; - #define ALIGN(x, a) (((x) + (a - 1)) & ~(a - 1)) #define SUPPORT_CHECK(x) assert(x) @@ -85,8 +83,8 @@ struct LoadedVertex { static struct { TextureCacheMap map; - list lru; - vector free_texture_ids; + std::list lru; + std::vector free_texture_ids; } gfx_texture_cache; struct ColorCombiner { @@ -97,8 +95,8 @@ struct ColorCombiner { uint8_t shader_input_mapping[2][7]; }; -static map color_combiner_pool; -static map::iterator prev_combiner = color_combiner_pool.end(); +static std::map color_combiner_pool; +static std::map::iterator prev_combiner = color_combiner_pool.end(); static uint8_t* tex_upload_buffer = nullptr; @@ -223,8 +221,6 @@ static int game_framebuffer_msaa_resolved; uint32_t gfx_msaa_level = 1; -static bool has_drawn_imgui_menu; - static bool dropped_frame; static float buf_vbo[MAX_BUFFERED * (32 * 3)]; // 3 vertices in a triangle and 32 floats per vtx @@ -243,8 +239,8 @@ struct FBInfo { }; static bool fbActive = 0; -static map::iterator active_fb; -static map framebuffers; +static std::map::iterator active_fb; +static std::map framebuffers; static constexpr float clampf(const float x, const float min, const float max) { return (x < min) ? min : (x > max) ? max : x; @@ -503,7 +499,7 @@ static struct ColorCombiner* gfx_lookup_or_create_color_combiner(const ColorComb return &prev_combiner->second; } gfx_flush(); - prev_combiner = color_combiner_pool.insert(make_pair(key, ColorCombiner())).first; + prev_combiner = color_combiner_pool.insert(std::make_pair(key, ColorCombiner())).first; gfx_generate_cc(&prev_combiner->second, key); return &prev_combiner->second; } @@ -547,7 +543,7 @@ static bool gfx_texture_cache_lookup(int i, const TextureCacheKey& key) { texture_id = gfx_rapi->new_texture(); } - it = gfx_texture_cache.map.insert(make_pair(key, TextureCacheValue())).first; + it = gfx_texture_cache.map.insert(std::make_pair(key, TextureCacheValue())).first; TextureCacheNode* node = &*it; node->second.texture_id = texture_id; node->second.lru_location = gfx_texture_cache.lru.insert(gfx_texture_cache.lru.end(), { it }); @@ -1377,7 +1373,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo cms &= ~G_TX_CLAMP; } if ((cmt & G_TX_CLAMP) && ((cmt & G_TX_MIRROR) || tex_height1 != tex_height2[i])) { - tm |= 1 << 2 * i + 1; + tm |= 1 << (2 * i + 1); cmt &= ~G_TX_CLAMP; } @@ -1478,7 +1474,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo buf_vbo[buf_vbo_len++] = v / tex_height[t]; bool clampS = tm & (1 << 2 * t); - bool clampT = tm & (1 << 2 * t + 1); + bool clampT = tm & (1 << (2 * t + 1)); if (clampS) { buf_vbo[buf_vbo_len++] = (tex_width2[t] - 0.5f) / tex_width[t]; @@ -2549,7 +2545,7 @@ extern "C" void gfx_init(struct GfxWindowManagerAPI* wapi, struct GfxRenderingAP if (tex_upload_buffer == nullptr) { // We cap texture max to 8k, because why would you need more? - int max_tex_size = min(8192, gfx_rapi->get_max_texture_size()); + int max_tex_size = std::min(8192, gfx_rapi->get_max_texture_size()); tex_upload_buffer = (uint8_t*)malloc(max_tex_size * max_tex_size * 4); } @@ -2689,7 +2685,6 @@ extern "C" void gfx_run(Gfx* commands) { gfx_rapi->end_frame(); gfx_wapi->swap_buffers_begin(); - has_drawn_imgui_menu = false; } extern "C" void gfx_end_frame(void) { From 1d040b1ccc335467fcea64636ea47ece9aa50304 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Mon, 13 May 2024 00:30:21 +0200 Subject: [PATCH 34/68] port: hackfix detail textures this might have broken something else --- port/fast3d/gfx_pc.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/port/fast3d/gfx_pc.cpp b/port/fast3d/gfx_pc.cpp index c91a135ea..dd15d4a41 100644 --- a/port/fast3d/gfx_pc.cpp +++ b/port/fast3d/gfx_pc.cpp @@ -179,6 +179,8 @@ static struct RDP { bool textures_changed[2]; uint8_t first_tile_index; + uint8_t tex_min_lod; + uint8_t tex_max_lod; uint32_t other_mode_l, other_mode_h; uint64_t combine_mode; @@ -851,7 +853,7 @@ static void import_texture(int i, int tile, bool importReplacement) { const uint32_t tex_flags = loaded_texture.tex_flags; const uint8_t palette_index = rdp.texture_tile[tile].palette; - if (rdp.tex_lod || !loaded_texture.addr) { + if ((rdp.tex_lod && tile >= rdp.first_tile_index + rdp.tex_detail) || !loaded_texture.addr) { // set up miplevel 0; also acts as a catch-all for when .addr is NULL because my texture loader sucks loaded_texture.addr = rdp.texture_to_load.addr; loaded_texture.line_size_bytes = rdp.texture_tile[tile].line_size_bytes; @@ -1327,7 +1329,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo for (int i = 0; i < 2; i++) { // TODO: fix this; for now just ignore smaller mips - const uint32_t tile = rdp.first_tile_index + (rdp.tex_lod ? rdp.tex_detail : i); + const uint32_t tile = rdp.first_tile_index + ((rdp.tex_lod && !rdp.tex_detail) ? 0 : i); if (comb->used_textures[i]) { if (rdp.textures_changed[i]) { gfx_flush(); @@ -1432,7 +1434,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo } // TODO: fix this; for now just ignore smaller mips - const uint32_t tile = (rdp.tex_lod ? rdp.tex_detail : t); + const uint32_t tile = ((rdp.tex_lod && !rdp.tex_detail) ? 0 : t); float u = v_arr[i]->u / 32.0f; float v = v_arr[i]->v / 32.0f; @@ -1535,10 +1537,11 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo } case G_CCMUX_LOD_FRACTION: { if (rdp.other_mode_h & G_TL_LOD) { - // "Hack" that works for Bowser - Peach painting - float distance_frac = (v1->w - 3000.0f) / 3000.0f; - if (distance_frac < 0.0f) { - distance_frac = 0.0f; + // HACK: very roughly eyeballed based on the carpets in Defection + // this is actually supposed to be calculated per pixel + float distance_frac = (w - 256.0f) / 512.0f; + if (distance_frac < 0.5f) { + distance_frac = 0.5f; } if (distance_frac > 1.0f) { distance_frac = 1.0f; @@ -1747,12 +1750,12 @@ static void gfx_sp_moveword(uint8_t index, uint16_t offset, uintptr_t data) { static void gfx_sp_texture(uint16_t sc, uint16_t tc, uint8_t level, uint8_t tile, uint8_t on) { rsp.texture_scaling_factor.s = sc; rsp.texture_scaling_factor.t = tc; + rdp.tex_max_lod = level; if (rdp.first_tile_index != tile) { rdp.textures_changed[0] = true; rdp.textures_changed[1] = true; + rdp.first_tile_index = tile; } - - rdp.first_tile_index = tile; } static void gfx_dp_set_scissor(uint32_t mode, uint32_t ulx, uint32_t uly, uint32_t lrx, uint32_t lry) { @@ -1964,6 +1967,7 @@ static void gfx_dp_set_env_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { static void gfx_dp_set_prim_color(uint8_t m, uint8_t l, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { rdp.prim_lod_fraction = l; + rdp.tex_min_lod = m; rdp.prim_color.r = r; rdp.prim_color.g = g; rdp.prim_color.b = b; From ef3d53b9f7f03b2873d3bc95cc002f3236fedff5 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Mon, 13 May 2024 01:15:30 +0200 Subject: [PATCH 35/68] port: make detail textures less intense --- port/fast3d/gfx_pc.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/port/fast3d/gfx_pc.cpp b/port/fast3d/gfx_pc.cpp index dd15d4a41..e5722d8c8 100644 --- a/port/fast3d/gfx_pc.cpp +++ b/port/fast3d/gfx_pc.cpp @@ -1539,14 +1539,8 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo if (rdp.other_mode_h & G_TL_LOD) { // HACK: very roughly eyeballed based on the carpets in Defection // this is actually supposed to be calculated per pixel - float distance_frac = (w - 256.0f) / 512.0f; - if (distance_frac < 0.5f) { - distance_frac = 0.5f; - } - if (distance_frac > 1.0f) { - distance_frac = 1.0f; - } - tmp.r = tmp.g = tmp.b = tmp.a = distance_frac * 255.0f; + const float distance_frac = std::max(0.f, std::min(w / 1024.f, 1.f)); + tmp.r = tmp.g = tmp.b = tmp.a = (0.65f + distance_frac * 0.35f) * 255.f; } else { tmp.r = tmp.g = tmp.b = tmp.a = 255; } @@ -1967,7 +1961,6 @@ static void gfx_dp_set_env_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { static void gfx_dp_set_prim_color(uint8_t m, uint8_t l, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { rdp.prim_lod_fraction = l; - rdp.tex_min_lod = m; rdp.prim_color.r = r; rdp.prim_color.g = g; rdp.prim_color.b = b; @@ -1976,6 +1969,8 @@ static void gfx_dp_set_prim_color(uint8_t m, uint8_t l, uint8_t r, uint8_t g, ui rdp.fill_color.g = g; rdp.fill_color.b = b; rdp.fill_color.a = a; + rdp.tex_min_lod = m; + } static void gfx_dp_set_fog_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { From f3c124285831aa06af282968ff402ee2d05b9de4 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Mon, 13 May 2024 12:15:42 +0200 Subject: [PATCH 36/68] port: more detail texture adjustment --- port/fast3d/gfx_pc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/port/fast3d/gfx_pc.cpp b/port/fast3d/gfx_pc.cpp index e5722d8c8..fe989e085 100644 --- a/port/fast3d/gfx_pc.cpp +++ b/port/fast3d/gfx_pc.cpp @@ -1540,7 +1540,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo // HACK: very roughly eyeballed based on the carpets in Defection // this is actually supposed to be calculated per pixel const float distance_frac = std::max(0.f, std::min(w / 1024.f, 1.f)); - tmp.r = tmp.g = tmp.b = tmp.a = (0.65f + distance_frac * 0.35f) * 255.f; + tmp.r = tmp.g = tmp.b = tmp.a = (0.7f + distance_frac * 0.3f) * 255.f; } else { tmp.r = tmp.g = tmp.b = tmp.a = 255; } From c5c1ef1d4e4cacd2c31c245372e2a1f701d19af9 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Mon, 13 May 2024 12:19:34 +0200 Subject: [PATCH 37/68] port: ask for high performance GPU on windows --- port/src/system.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/port/src/system.c b/port/src/system.c index e889f75df..36f9475ce 100644 --- a/port/src/system.c +++ b/port/src/system.c @@ -22,6 +22,10 @@ static CREATEWAITABLETIMEREXAFN pfnCreateWaitableTimerExA; // winapi also provides a yield macro #define DO_YIELD() YieldProcessor() +// ask system for high performance GPU, if any +__attribute__((dllexport)) u32 NvOptimusEnablement = 1; +__attribute__((dllexport)) u32 AmdPowerXpressRequestHighPerformance = 1; + #else #ifndef _GNU_SOURCE From 12cf9df01b72898d2138de95dc2efd8afa880ac9 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Mon, 13 May 2024 12:55:29 +0200 Subject: [PATCH 38/68] port: allow overriding CC and CXX --- Makefile.port | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/Makefile.port b/Makefile.port index d6a6699d4..550b7cb60 100644 --- a/Makefile.port +++ b/Makefile.port @@ -151,9 +151,15 @@ G_DIR := src/generated/$(ROMID) ifneq (,$(findstring windows,$(TARGET_PLATFORM))) TARGET_CFLAGS := $(shell pkg-config sdl2 --cflags-only-I) - TARGET_LDFLAGS := $(shell pkg-config sdl2 --libs) -lz -lopengl32 -static-libstdc++ -ldbghelp + TARGET_LDFLAGS := $(shell pkg-config sdl2 --libs) -lz -lopengl32 -ldbghelp # on windows/mingw we need this to be built with a 32-bit compiler so it finds the correct libs TOOLCHAIN ?= i686-w64-mingw32- + # on GCC link libstdc++ statically + ifeq (,$(findstring clang,$(CC))$(findstring clang,$(CXX))) + TARGET_LDFLAGS += -static-libstdc++ + else + TARGET_LDFLAGS += -lstdc++ + endif else # assume *nix TARGET_CFLAGS := $(shell pkg-config sdl2 --cflags-only-I) TARGET_LDFLAGS := $(shell pkg-config sdl2 --libs) -lGL -lz -ldl @@ -162,6 +168,10 @@ else # assume *nix # TODO: detect soft/hardfloat abi TOOLCHAIN ?= arm-linux-gnueabihf- endif + # on clang link libc++ + ifneq (,$(findstring clang,$(CC))$(findstring clang,$(CXX))) + TARGET_LDFLAGS += -lc++ + endif endif # On x86_64 gcc add -m32 to CFLAGS if building a 32-bit executable. @@ -233,8 +243,8 @@ INCLUDES = \ -I port/include TOOLCHAIN ?= -CC := $(TOOLCHAIN)gcc -std=c11 -CXX := $(TOOLCHAIN)g++ -std=c++20 +CC ?= $(TOOLCHAIN)gcc +CXX ?= $(TOOLCHAIN)g++ ifneq (,$(CXX_O_FILES)) LD := $(CXX) else @@ -250,7 +260,6 @@ COMMON_CFLAGS := $(C_DEFINES) -DAVOID_UB=1 $(INCLUDES) $(TARGET_CFLAGS) -g \ -fwrapv \ -Wall \ -Wno-address \ - -Wno-aggressive-loop-optimizations \ -Wno-int-in-bool-context \ -Wno-misleading-indentation \ -Wno-missing-braces \ @@ -261,8 +270,8 @@ COMMON_CFLAGS := $(C_DEFINES) -DAVOID_UB=1 $(INCLUDES) $(TARGET_CFLAGS) -g \ -Wno-unused-variable \ -Wno-format-truncation -CFLAGS := $(COMMON_CFLAGS) -Wno-pointer-sign -CXXFLAGS := $(COMMON_CFLAGS) -Wno-unused-function +CFLAGS := -std=c11 $(COMMON_CFLAGS) -Wno-pointer-sign +CXXFLAGS := -std=c++20 $(COMMON_CFLAGS) -Wno-unused-function LDFLAGS := $(TARGET_LDFLAGS) # Make ROMID available as an environment variable to all tooling. From 62a55a3d6e1b0e74916b69436794ff22f77f55ff Mon Sep 17 00:00:00 2001 From: fgsfds Date: Mon, 13 May 2024 15:24:45 +0200 Subject: [PATCH 39/68] port: don't force libc++, fix system.c on clang16+ --- Makefile.port | 4 ---- port/src/system.c | 8 ++++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Makefile.port b/Makefile.port index 550b7cb60..650f02474 100644 --- a/Makefile.port +++ b/Makefile.port @@ -168,10 +168,6 @@ else # assume *nix # TODO: detect soft/hardfloat abi TOOLCHAIN ?= arm-linux-gnueabihf- endif - # on clang link libc++ - ifneq (,$(findstring clang,$(CC))$(findstring clang,$(CXX))) - TARGET_LDFLAGS += -lc++ - endif endif # On x86_64 gcc add -m32 to CFLAGS if building a 32-bit executable. diff --git a/port/src/system.c b/port/src/system.c index 36f9475ce..16b689c47 100644 --- a/port/src/system.c +++ b/port/src/system.c @@ -1,3 +1,7 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + #include #include #include @@ -28,10 +32,6 @@ __attribute__((dllexport)) u32 AmdPowerXpressRequestHighPerformance = 1; #else -#ifndef _GNU_SOURCE -#define _GNU_SOURCE 1 -#endif - #include // figure out how to yield From 95b43b3f7b47eb5bcc9efac47f633b76a5af07bd Mon Sep 17 00:00:00 2001 From: fgsfds Date: Mon, 13 May 2024 18:48:35 +0200 Subject: [PATCH 40/68] port: remove sprintf redeclaration --- include/PR/os_libc.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/PR/os_libc.h b/include/PR/os_libc.h index 23a13d72e..6ec0f4db8 100644 --- a/include/PR/os_libc.h +++ b/include/PR/os_libc.h @@ -32,6 +32,10 @@ #include "os_pfs.h" +#ifndef PLATFORM_N64 +#include +#endif + #ifdef _LANGUAGE_C_PLUS_PLUS extern "C" { #endif @@ -86,7 +90,9 @@ extern void bzero(void *, size_t); /* Printf */ +#ifdef PLATFORM_N64 extern int sprintf(char *s, const char *fmt, ...); +#endif extern void osSyncPrintf(const char *fmt, ...); From 4bd314f60b8015fdd712515bb864c0c4706c1ab8 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Mon, 13 May 2024 22:23:04 +0200 Subject: [PATCH 41/68] port: add exclusive fullscreen and hidpi settings for now config only exclusive fullscreen uses DefaultWidth/DefaultHeight for resolution hidpi defaults to off --- port/fast3d/gfx_api.h | 10 +++-- port/fast3d/gfx_pc.cpp | 15 +++---- port/fast3d/gfx_sdl2.cpp | 67 ++++++++++++++++++++++------ port/fast3d/gfx_window_manager_api.h | 16 ++++++- port/src/video.c | 22 ++++++++- 5 files changed, 103 insertions(+), 27 deletions(-) diff --git a/port/fast3d/gfx_api.h b/port/fast3d/gfx_api.h index 3bf8427ad..271e8abb6 100644 --- a/port/fast3d/gfx_api.h +++ b/port/fast3d/gfx_api.h @@ -20,6 +20,12 @@ struct GfxDimensions { float aspect_ratio; }; +struct GfxInitSettings { + struct GfxWindowManagerAPI *wapi; + struct GfxRenderingAPI *rapi; + struct GfxWindowInitSettings window_settings; +}; + extern struct GfxDimensions gfx_current_window_dimensions; // The dimensions of the window extern struct GfxDimensions gfx_current_dimensions; // The dimensions of the draw area the game draws to, before scaling (if applicable) @@ -30,9 +36,7 @@ extern struct XYWidthHeight gfx_current_native_viewport; // The internal/native extern float gfx_current_native_aspect; // The aspect ratio of the above mode extern bool gfx_framebuffers_enabled; -void gfx_init(struct GfxWindowManagerAPI* wapi, struct GfxRenderingAPI* rapi, const char* game_name, - bool start_in_fullscreen, bool start_maximized, uint32_t width, uint32_t height, - uint32_t posX, uint32_t posY); +void gfx_init(const struct GfxInitSettings *settings); void gfx_destroy(void); struct GfxRenderingAPI* gfx_get_current_rendering_api(void); void gfx_start_frame(void); diff --git a/port/fast3d/gfx_pc.cpp b/port/fast3d/gfx_pc.cpp index fe989e085..a9fd646a0 100644 --- a/port/fast3d/gfx_pc.cpp +++ b/port/fast3d/gfx_pc.cpp @@ -2520,16 +2520,15 @@ extern "C" void gfx_get_dimensions(uint32_t* width, uint32_t* height, int32_t* p gfx_wapi->get_dimensions(width, height, posX, posY); } -extern "C" void gfx_init(struct GfxWindowManagerAPI* wapi, struct GfxRenderingAPI* rapi, const char* game_name, - bool start_in_fullscreen, bool start_maximized, uint32_t width, uint32_t height, uint32_t posX, uint32_t posY) { - gfx_wapi = wapi; - gfx_rapi = rapi; - gfx_wapi->init(game_name, rapi->get_name(), start_in_fullscreen, start_maximized, width, height, posX, posY); +extern "C" void gfx_init(const GfxInitSettings *settings) { + gfx_wapi = settings->wapi; + gfx_rapi = settings->rapi; + gfx_wapi->init(&settings->window_settings); gfx_rapi->init(); - gfx_rapi->update_framebuffer_parameters(0, width, height, 1, false, true, true, true); + gfx_rapi->update_framebuffer_parameters(0, settings->window_settings.width, settings->window_settings.height, 1, false, true, true, true); gfx_current_dimensions.internal_mul = 1; - gfx_current_game_window_viewport.width = gfx_current_dimensions.width = width; - gfx_current_game_window_viewport.height = gfx_current_dimensions.height = height; + gfx_current_game_window_viewport.width = gfx_current_dimensions.width = settings->window_settings.width; + gfx_current_game_window_viewport.height = gfx_current_dimensions.height = settings->window_settings.height; game_framebuffer = gfx_rapi->create_framebuffer(); game_framebuffer_msaa_resolved = gfx_rapi->create_framebuffer(); diff --git a/port/fast3d/gfx_sdl2.cpp b/port/fast3d/gfx_sdl2.cpp index bd6e4def7..181038d26 100644 --- a/port/fast3d/gfx_sdl2.cpp +++ b/port/fast3d/gfx_sdl2.cpp @@ -17,6 +17,7 @@ static bool vsync_enabled = true; // OTRTODO: These are redundant. Info can be queried from SDL. static int window_width = DESIRED_SCREEN_WIDTH; static int window_height = DESIRED_SCREEN_HEIGHT; +static uint32_t fullscreen_flag = SDL_WINDOW_FULLSCREEN_DESKTOP; static bool fullscreen_state; static bool maximized_state; static bool is_running = true; @@ -34,7 +35,7 @@ static void set_fullscreen(bool on, bool call_callback) { return; } fullscreen_state = on; - SDL_SetWindowFullscreen(wnd, on ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); + SDL_SetWindowFullscreen(wnd, on ? fullscreen_flag : 0); if (call_callback && on_fullscreen_changed_callback) { on_fullscreen_changed_callback(on); } @@ -60,10 +61,20 @@ static void gfx_sdl_get_active_window_refresh_rate(uint32_t* refresh_rate) { *refresh_rate = mode.refresh_rate; } -static void gfx_sdl_init(const char* game_name, const char* gfx_api_name, bool start_in_fullscreen, bool start_maximized, uint32_t width, - uint32_t height, int32_t posX, int32_t posY) { - window_width = width; - window_height = height; +static void gfx_sdl_init(const struct GfxWindowInitSettings *set) { + window_width = set->width; + window_height = set->height; + +#ifdef SDL_HINT_VIDEO_HIGHDPI_DISABLED + if (!set->allow_hidpi) { + // HiDPI control, if available + SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1"); +#if defined(PLATFORM_WIN32) && defined(SDL_HINT_WINDOWS_DPI_AWARENESS) + // if HiDPI is disabled, declare ourselves DPI aware to get 1:1 window size on Windows + SDL_SetHint(SDL_HINT_WINDOWS_DPI_AWARENESS, "permonitor"); +#endif + } +#endif if (SDL_Init(SDL_INIT_VIDEO) != 0) { sysFatalError("Could not init SDL:\n%s", SDL_GetError()); @@ -77,18 +88,38 @@ static void gfx_sdl_init(const char* game_name, const char* gfx_api_name, bool s SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); } - char title[512]; - snprintf(title, sizeof(title), "%s (%s)", game_name, gfx_api_name); - + int posX = set->x; + int posY = set->y; int display_in_use = SDL_GetWindowDisplayIndex(wnd); if (display_in_use < 0) { // Fallback to default if out of bounds posX = 100; posY = 100; } - const Uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_OPENGL; + if (set->fullscreen_is_exclusive) { + fullscreen_flag = SDL_WINDOW_FULLSCREEN; + } - wnd = SDL_CreateWindow(title, posX, posY, window_width, window_height, flags); + Uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL; + + // if fullscreen was requested, start the window in fullscreen right away + if (set->fullscreen) { + flags |= fullscreen_flag; + fullscreen_state = true; + } + + if (set->maximized) { + flags |= SDL_WINDOW_MAXIMIZED; + maximized_state = true; + } + +#ifdef SDL_WINDOW_ALLOW_HIGHDPI + if (set->allow_hidpi) { + flags |= SDL_WINDOW_ALLOW_HIGHDPI; + } +#endif + + wnd = SDL_CreateWindow(set->title, posX, posY, window_width, window_height, flags); if (!wnd) { sysFatalError("Could not open SDL window:\n%s", SDL_GetError()); } @@ -143,9 +174,6 @@ static void gfx_sdl_init(const char* game_name, const char* gfx_api_name, bool s SDL_GL_SetSwapInterval(1); qpc_freq = SDL_GetPerformanceFrequency(); - - set_maximize_window(start_maximized); - set_fullscreen(start_in_fullscreen, false); } static void gfx_sdl_close(void) { @@ -160,6 +188,18 @@ static void gfx_sdl_set_fullscreen(bool enable) { set_fullscreen(enable, true); } +static void gfx_sdl_set_fullscreen_exclusive(bool enable) { + const uint32_t newflag = enable ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP; + if (fullscreen_flag != newflag) { + fullscreen_flag = newflag; + // reset fullscreen to take new value into account if it already is in fullscreen + if (fullscreen_state) { + fullscreen_state = false; + set_fullscreen(enable, true); + } + } +} + static void gfx_sdl_set_maximize_window(bool enable) { set_maximize_window(enable); } @@ -284,6 +324,7 @@ struct GfxWindowManagerAPI gfx_sdl = { gfx_sdl_close, gfx_sdl_set_fullscreen_changed_callback, gfx_sdl_set_fullscreen, + gfx_sdl_set_fullscreen_exclusive, gfx_sdl_set_maximize_window, gfx_sdl_get_active_window_refresh_rate, gfx_sdl_set_cursor_visibility, diff --git a/port/fast3d/gfx_window_manager_api.h b/port/fast3d/gfx_window_manager_api.h index 44eda4160..61b05315f 100644 --- a/port/fast3d/gfx_window_manager_api.h +++ b/port/fast3d/gfx_window_manager_api.h @@ -4,12 +4,24 @@ #include #include +struct GfxWindowInitSettings { + const char *title; + uint32_t width; + uint32_t height; + int32_t x; + int32_t y; + bool fullscreen; + bool fullscreen_is_exclusive; + bool maximized; + bool allow_hidpi; +}; + struct GfxWindowManagerAPI { - void (*init)(const char* game_name, const char* gfx_api_name, bool start_in_fullscreen, bool start_maximized, uint32_t width, - uint32_t height, int32_t posX, int32_t posY); + void (*init)(const struct GfxWindowInitSettings *settings); void (*close)(void); void (*set_fullscreen_changed_callback)(void (*on_fullscreen_changed)(bool is_now_fullscreen)); void (*set_fullscreen)(bool enable); + void (*set_fullscreen_exclusive)(bool exc); void (*set_maximize)(bool enable); void (*get_active_window_refresh_rate)(uint32_t* refresh_rate); void (*set_cursor_visibility)(bool visible); diff --git a/port/src/video.c b/port/src/video.c index 18da94fc0..c838bc524 100644 --- a/port/src/video.c +++ b/port/src/video.c @@ -21,7 +21,9 @@ static s32 vidWidth = 640; static s32 vidHeight = 480; static s32 vidFramebuffers = true; static s32 vidFullscreen = false; +static s32 vidFullscreenExclusive = false; static s32 vidMaximize = false; +static s32 vidAllowHiDpi = false; static s32 vidVsync = 1; static s32 vidMSAA = 1; static s32 vidFramerateLimit = 0; @@ -45,7 +47,23 @@ s32 videoInit(void) gfx_framebuffers_enabled = (bool)vidFramebuffers; gfx_msaa_level = vidMSAA; - gfx_init(wmAPI, renderingAPI, "PD", vidFullscreen, vidMaximize, vidWidth, vidHeight, 100, 100); + struct GfxInitSettings set = { + .wapi = wmAPI, + .rapi = renderingAPI, + .window_settings = { + .title = "Perfect Dark", + .width = vidWidth, + .height = vidHeight, + .x = 100, + .y = 100, + .fullscreen = vidFullscreen, + .fullscreen_is_exclusive = vidFullscreenExclusive, + .maximized = vidMaximize, + .allow_hidpi = vidAllowHiDpi + } + }; + + gfx_init(&set); if (!wmAPI->set_swap_interval(vidVsync)) { vidVsync = 0; @@ -249,6 +267,8 @@ PD_CONSTRUCTOR static void videoConfigInit(void) configRegisterInt("Video.DefaultMaximize", &vidMaximize, 0, 1); configRegisterInt("Video.DefaultWidth", &vidWidth, 0, 32767); configRegisterInt("Video.DefaultHeight", &vidHeight, 0, 32767); + configRegisterInt("Video.ExclusiveFullscreen", &vidFullscreenExclusive, 0, 1); + configRegisterInt("Video.AllowHiDpi", &vidAllowHiDpi, 0, 1); configRegisterInt("Video.VSync", &vidVsync, -1, 10); configRegisterInt("Video.FramebufferEffects", &vidFramebuffers, 0, 1); configRegisterInt("Video.FramerateLimit", &vidFramerateLimit, 0, VIDEO_MAX_FPS); From 197208b951345da546e83fbd63c1b251707eec9c Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 14 May 2024 10:13:50 +0200 Subject: [PATCH 42/68] port: add detail textures toggle --- port/fast3d/gfx_api.h | 1 + port/fast3d/gfx_pc.cpp | 11 +++++++++-- port/include/video.h | 6 ++++-- port/src/optionsmenu.c | 21 +++++++++++++++++++++ port/src/video.c | 18 ++++++++++++++++-- 5 files changed, 51 insertions(+), 6 deletions(-) diff --git a/port/fast3d/gfx_api.h b/port/fast3d/gfx_api.h index 271e8abb6..279a684ef 100644 --- a/port/fast3d/gfx_api.h +++ b/port/fast3d/gfx_api.h @@ -35,6 +35,7 @@ extern uint32_t gfx_msaa_level; extern struct XYWidthHeight gfx_current_native_viewport; // The internal/native video mode of the game extern float gfx_current_native_aspect; // The aspect ratio of the above mode extern bool gfx_framebuffers_enabled; +extern bool gfx_detail_textures_enabled; void gfx_init(const struct GfxInitSettings *settings); void gfx_destroy(void); diff --git a/port/fast3d/gfx_pc.cpp b/port/fast3d/gfx_pc.cpp index a9fd646a0..7938fdd77 100644 --- a/port/fast3d/gfx_pc.cpp +++ b/port/fast3d/gfx_pc.cpp @@ -216,6 +216,7 @@ struct XYWidthHeight gfx_current_game_window_viewport; struct XYWidthHeight gfx_current_native_viewport; float gfx_current_native_aspect = 4.f / 3.f; bool gfx_framebuffers_enabled = true; +bool gfx_detail_textures_enabled = true; static bool game_renders_to_framebuffer; static int game_framebuffer; @@ -1185,6 +1186,12 @@ static void gfx_sp_modify_vertex(uint16_t vtx_idx, uint8_t where, uint32_t val) v->v = t; } +static inline int gfx_lod_tile_offset(const int i) { + if (gfx_detail_textures_enabled) + return ((rdp.tex_lod && !rdp.tex_detail) ? 0 : i); + return (rdp.tex_lod ? rdp.tex_detail : i); +} + static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bool is_rect) { struct LoadedVertex* v1 = &rsp.loaded_vertices[vtx1_idx]; struct LoadedVertex* v2 = &rsp.loaded_vertices[vtx2_idx]; @@ -1329,7 +1336,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo for (int i = 0; i < 2; i++) { // TODO: fix this; for now just ignore smaller mips - const uint32_t tile = rdp.first_tile_index + ((rdp.tex_lod && !rdp.tex_detail) ? 0 : i); + const uint32_t tile = rdp.first_tile_index + gfx_lod_tile_offset(i); if (comb->used_textures[i]) { if (rdp.textures_changed[i]) { gfx_flush(); @@ -1434,7 +1441,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo } // TODO: fix this; for now just ignore smaller mips - const uint32_t tile = ((rdp.tex_lod && !rdp.tex_detail) ? 0 : t); + const uint32_t tile = gfx_lod_tile_offset(t); float u = v_arr[i]->u / 32.0f; float v = v_arr[i]->v / 32.0f; diff --git a/port/include/video.h b/port/include/video.h index 105f78699..d7a888886 100644 --- a/port/include/video.h +++ b/port/include/video.h @@ -30,12 +30,14 @@ s32 videoGetFullscreen(void); s32 videoGetMaximizeWindow(void); void videoSetMaximizeWindow(s32 fs); u32 videoGetTextureFilter(void); -u32 videoGetTextureFilter2D(void); +s32 videoGetTextureFilter2D(void); +s32 videoGetDetailTextures(void); void videoSetWindowOffset(s32 x, s32 y); void videoSetFullscreen(s32 fs); void videoSetTextureFilter(u32 filter); -void videoSetTextureFilter2D(u32 filter); +void videoSetTextureFilter2D(s32 filter); +void videoSetDetailTextures(s32 detail); s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize); void videoSetFramebuffer(s32 target); diff --git a/port/src/optionsmenu.c b/port/src/optionsmenu.c index e8085b564..b6ac6dab7 100644 --- a/port/src/optionsmenu.c +++ b/port/src/optionsmenu.c @@ -678,6 +678,19 @@ static MenuItemHandlerResult menuhandlerTexFilter(s32 operation, struct menuitem return 0; } +static MenuItemHandlerResult menuhandlerTexDetail(s32 operation, struct menuitem *item, union handlerdata *data) +{ + switch (operation) { + case MENUOP_GET: + return (videoGetDetailTextures() != 0); + case MENUOP_SET: + videoSetDetailTextures(data->checkbox.value); + break; + } + + return 0; +} + static MenuItemHandlerResult menuhandlerTexFilter2D(s32 operation, struct menuitem *item, union handlerdata *data) { switch (operation) { @@ -769,6 +782,14 @@ struct menuitem g_ExtendedVideoMenuItems[] = { 0, menuhandlerMaximizeWindow, }, + { + MENUITEMTYPE_CHECKBOX, + 0, + MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"Detail Textures", + 0, + menuhandlerTexDetail, + }, { MENUITEMTYPE_CHECKBOX, 0, diff --git a/port/src/video.c b/port/src/video.c index c838bc524..181af3ab5 100644 --- a/port/src/video.c +++ b/port/src/video.c @@ -30,6 +30,7 @@ static s32 vidFramerateLimit = 0; static s32 texFilter = FILTER_LINEAR; static s32 texFilter2D = true; +static s32 texDetail = true; static u32 dlcount = 0; static u32 frames = 0; @@ -45,6 +46,7 @@ s32 videoInit(void) gfx_current_native_viewport.height = 220; gfx_current_native_aspect = 320.f / 220.f; gfx_framebuffers_enabled = (bool)vidFramebuffers; + gfx_detail_textures_enabled = (bool)texDetail; gfx_msaa_level = vidMSAA; struct GfxInitSettings set = { @@ -176,7 +178,7 @@ f32 videoGetAspect(void) return gfx_current_dimensions.aspect_ratio; } -u32 videoGetTextureFilter2D(void) +s32 videoGetTextureFilter2D(void) { return texFilter2D; } @@ -186,6 +188,11 @@ u32 videoGetTextureFilter(void) return texFilter; } +s32 videoGetDetailTextures(void) +{ + return texDetail; +} + void videoSetWindowOffset(s32 x, s32 y) { gfx_current_game_window_viewport.x = x; @@ -215,11 +222,17 @@ void videoSetTextureFilter(u32 filter) renderingAPI->set_texture_filter((enum FilteringMode)filter); } -void videoSetTextureFilter2D(u32 filter) +void videoSetTextureFilter2D(s32 filter) { texFilter2D = !!filter; } +void videoSetDetailTextures(s32 detail) +{ + texDetail = !!detail; + gfx_detail_textures_enabled = (bool)texDetail; +} + s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize) { return gfx_create_framebuffer(w, h, upscale, autoresize); @@ -275,4 +288,5 @@ PD_CONSTRUCTOR static void videoConfigInit(void) configRegisterInt("Video.MSAA", &vidMSAA, 1, 16); configRegisterInt("Video.TextureFilter", &texFilter, 0, 2); configRegisterInt("Video.TextureFilter2D", &texFilter2D, 0, 1); + configRegisterInt("Video.DetailTextures", &texDetail, 0, 1); } From fef8985b6b9e424f871c30c7bcc82bb0fa8e6476 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 14 May 2024 10:34:16 +0200 Subject: [PATCH 43/68] port: fix whitespace and scope in bgunConsiderToggleGunFunction --- src/game/bondgun.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/game/bondgun.c b/src/game/bondgun.c index c2dbc993e..8c99e39c1 100644 --- a/src/game/bondgun.c +++ b/src/game/bondgun.c @@ -11735,6 +11735,7 @@ s32 bgunConsiderToggleGunFunction(s32 usedowntime, bool trigpressed, bool fromac { #ifndef PLATFORM_N64 const bool extcontrols = PLAYER_EXTCFG().extcontrols; + bool docontinue; #endif switch (bgunGetWeaponNum(HAND_RIGHT)) { case WEAPON_SNIPERRIFLE: @@ -11759,7 +11760,6 @@ s32 bgunConsiderToggleGunFunction(s32 usedowntime, bool trigpressed, bool fromac } #ifndef PLATFORM_N64 - bool docontinue; if (extcontrols) { docontinue = (ABS(usedowntime) < 0); } else { @@ -11781,19 +11781,18 @@ s32 bgunConsiderToggleGunFunction(s32 usedowntime, bool trigpressed, bool fromac g_Vars.currentplayer->hands[HAND_RIGHT].activatesecondary = true; return (extcontrols ? USETIMER_STOP : USETIMER_REPEAT); case WEAPON_RCP120: - #ifndef PLATFORM_N64 - s32 cloaked = (g_Vars.currentplayer->devicesactive & DEVICE_CLOAKRCP120) != 0; +#ifndef PLATFORM_N64 // very special alt-button handling for RCP-120's cloaking if (!trigpressed && extcontrols && fromdedicatedbutton) { - if (cloaked) { + if (g_Vars.currentplayer->devicesactive & DEVICE_CLOAKRCP120) { g_Vars.currentplayer->devicesactive &= ~DEVICE_CLOAKRCP120; } else { g_Vars.currentplayer->devicesactive = (g_Vars.currentplayer->devicesactive & ~DEVICE_CLOAKRCP120) | DEVICE_CLOAKRCP120; } - g_Vars.currentplayer->gunctrl.invertgunfunc = false; + g_Vars.currentplayer->gunctrl.invertgunfunc = false; return USETIMER_STOP; } - #endif +#endif case WEAPON_LAPTOPGUN: case WEAPON_DRAGON: case WEAPON_REMOTEMINE: From d8a26fa2211d9ffeead8894a23ca3b4f1b2be0dd Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 14 May 2024 10:56:50 +0200 Subject: [PATCH 44/68] port: clean up whitespace --- src/game/cheats.c | 2 +- src/game/game_0b0fd0.c | 14 ++++++++------ src/game/inv.c | 14 +++++++------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/game/cheats.c b/src/game/cheats.c index 260a390b3..4567f5e30 100644 --- a/src/game/cheats.c +++ b/src/game/cheats.c @@ -101,7 +101,7 @@ struct cheat g_Cheats[] = { { L_MPWEAPONS_115, WEAPON_AR53, 0, 0, CHEATFLAG_FIRINGRANGE }, // AR53 { L_MPWEAPONS_116, WEAPON_RCP45, 0, 0, CHEATFLAG_FIRINGRANGE }, // RC-P45 #ifndef PLATFORM_N64 - { L_MPWEAPONS_215, 0, SOLOSTAGEINDEX_EXTRACTION, DIFF_A, CHEATFLAG_COMPLETION }, // dual wield all guns cheat + { L_MPWEAPONS_215, 0, SOLOSTAGEINDEX_EXTRACTION, DIFF_A, CHEATFLAG_COMPLETION }, // Dual wield all guns #endif }; diff --git a/src/game/game_0b0fd0.c b/src/game/game_0b0fd0.c index d30a54946..3747c37a4 100644 --- a/src/game/game_0b0fd0.c +++ b/src/game/game_0b0fd0.c @@ -286,16 +286,18 @@ void currentPlayerZoomIn(f32 fovpersec) bool weaponHasFlag(s32 itemid, u32 flag) { struct weapon *weapon = weaponFindById(itemid); -#ifndef PLATFORM_N64 //always return, that weapon is dual-wieldable if player sets the cheat. - if (cheatIsActive(CHEAT_DUALWIELDALLGUNS) && (flag == WEAPONFLAG_DUALWIELD)) - { - return true; - } -#endif + if (!weapon) { return false; } +#ifndef PLATFORM_N64 + // always dual-wieldable if cheat is enabled + if (cheatIsActive(CHEAT_DUALWIELDALLGUNS) && (flag == WEAPONFLAG_DUALWIELD)) { + return true; + } +#endif + return (weapon->flags & flag) != 0; } diff --git a/src/game/inv.c b/src/game/inv.c index 3cba713e1..04fce4a8a 100644 --- a/src/game/inv.c +++ b/src/game/inv.c @@ -510,14 +510,14 @@ s32 invGiveWeaponsByProp(struct prop *prop) weapon = prop->weapon; weaponnum = weapon->weaponnum; otherweaponnum; + #ifndef PLATFORM_N64 - //This piece of code makes the cheat work in singleplayer. - if (cheatIsActive(CHEAT_DUALWIELDALLGUNS) && !g_Vars.normmplayerisrunning) - { - if(invHasSingleWeaponExcAllGuns(weaponnum) && (invHasDoubleWeaponExcAllGuns(weapon->weaponnum, weapon->weaponnum)==0)) - { - invGiveDoubleWeapon(weaponnum, weaponnum); - numgiven = 2; + // always allow picking up a second gun if dual wield cheat is on + if (!g_Vars.normmplayerisrunning && cheatIsActive(CHEAT_DUALWIELDALLGUNS)) { + if (invHasSingleWeaponExcAllGuns(weaponnum) && !invHasDoubleWeaponExcAllGuns(weaponnum, weaponnum)) { + if (invGiveDoubleWeapon(weaponnum, weaponnum)) { + return 2; + } } } #endif From 70b02da1633653a3bd4c7f287827302aeb481494 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 14 May 2024 11:12:49 +0200 Subject: [PATCH 45/68] port: fix long option names and whitespace --- src/game/lv.c | 8 ++++---- src/game/mplayer/scenarios/capturethecase.inc | 4 ++-- src/game/mplayer/scenarios/combat.inc | 4 ++-- src/game/mplayer/scenarios/hackthatmac.inc | 4 ++-- src/game/mplayer/scenarios/holdthebriefcase.inc | 4 ++-- src/game/mplayer/scenarios/kingofthehill.inc | 4 ++-- src/game/mplayer/scenarios/popacap.inc | 4 ++-- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/game/lv.c b/src/game/lv.c index e4b066709..c3273c6c6 100644 --- a/src/game/lv.c +++ b/src/game/lv.c @@ -1127,10 +1127,10 @@ Gfx *lvRender(Gfx *gdl) chr->blurdrugamount = 0; chr->blurnumtimesdied = 0; } -#ifndef PLATFORM_N64 //set the drug blur to 0 if it's disabled in MP settings. There might be a better way to block it from occuring, but this one works just fine - - if(g_Vars.mplayerisrunning && (g_MpSetup.options & MPOPTION_NODRUGBLUR)) - { + +#ifndef PLATFORM_N64 + // reset the drug blur to 0 if it's disabled in MP settings + if (g_Vars.mplayerisrunning && (g_MpSetup.options & MPOPTION_NODRUGBLUR)) { bluramount = 0; } #endif diff --git a/src/game/mplayer/scenarios/capturethecase.inc b/src/game/mplayer/scenarios/capturethecase.inc index 2addfbfde..529fd2916 100644 --- a/src/game/mplayer/scenarios/capturethecase.inc +++ b/src/game/mplayer/scenarios/capturethecase.inc @@ -65,7 +65,7 @@ struct menuitem g_CtcOptionsMenuItems[] = { MENUITEMTYPE_CHECKBOX, 0, MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Spawn With Weapon", + (uintptr_t)"Spawn With Gun", MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, @@ -73,7 +73,7 @@ struct menuitem g_CtcOptionsMenuItems[] = { MENUITEMTYPE_CHECKBOX, 0, MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"No melee/tranquilizer blur", + (uintptr_t)"No Drug Blur", MPOPTION_NODRUGBLUR, menuhandlerMpCheckboxOption, }, diff --git a/src/game/mplayer/scenarios/combat.inc b/src/game/mplayer/scenarios/combat.inc index 76da12a16..9e58b6b65 100644 --- a/src/game/mplayer/scenarios/combat.inc +++ b/src/game/mplayer/scenarios/combat.inc @@ -60,7 +60,7 @@ struct menuitem g_MpCombatOptionsMenuItems[] = { MENUITEMTYPE_CHECKBOX, 0, MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Spawn With Weapon", + (uintptr_t)"Spawn With Gun", MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, @@ -68,7 +68,7 @@ struct menuitem g_MpCombatOptionsMenuItems[] = { MENUITEMTYPE_CHECKBOX, 0, MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"No melee/tranquilizer blur", + (uintptr_t)"No Drug Blur", MPOPTION_NODRUGBLUR, menuhandlerMpCheckboxOption, }, diff --git a/src/game/mplayer/scenarios/hackthatmac.inc b/src/game/mplayer/scenarios/hackthatmac.inc index bc55d75b8..a158bf9d5 100644 --- a/src/game/mplayer/scenarios/hackthatmac.inc +++ b/src/game/mplayer/scenarios/hackthatmac.inc @@ -63,7 +63,7 @@ struct menuitem g_HtmOptionsMenuItems[] = { MENUITEMTYPE_CHECKBOX, 0, MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Spawn With Weapon", + (uintptr_t)"Spawn With Gun", MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, @@ -71,7 +71,7 @@ struct menuitem g_HtmOptionsMenuItems[] = { MENUITEMTYPE_CHECKBOX, 0, MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"No melee/tranquilizer blur", + (uintptr_t)"No Drug Blur", MPOPTION_NODRUGBLUR, menuhandlerMpCheckboxOption, }, diff --git a/src/game/mplayer/scenarios/holdthebriefcase.inc b/src/game/mplayer/scenarios/holdthebriefcase.inc index a0692c5e9..39f98a728 100644 --- a/src/game/mplayer/scenarios/holdthebriefcase.inc +++ b/src/game/mplayer/scenarios/holdthebriefcase.inc @@ -63,7 +63,7 @@ struct menuitem g_HtbOptionsMenuItems[] = { MENUITEMTYPE_CHECKBOX, 0, MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Spawn With Weapon", + (uintptr_t)"Spawn With Gun", MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, @@ -71,7 +71,7 @@ struct menuitem g_HtbOptionsMenuItems[] = { MENUITEMTYPE_CHECKBOX, 0, MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"No melee/tranquilizer blur", + (uintptr_t)"No Drug Blur", MPOPTION_NODRUGBLUR, menuhandlerMpCheckboxOption, }, diff --git a/src/game/mplayer/scenarios/kingofthehill.inc b/src/game/mplayer/scenarios/kingofthehill.inc index 2d7857580..2a4d5c7aa 100644 --- a/src/game/mplayer/scenarios/kingofthehill.inc +++ b/src/game/mplayer/scenarios/kingofthehill.inc @@ -84,7 +84,7 @@ struct menuitem g_KohOptionsMenuItems[] = { MENUITEMTYPE_CHECKBOX, 0, MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Spawn With Weapon", + (uintptr_t)"Spawn With Gun", MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, @@ -92,7 +92,7 @@ struct menuitem g_KohOptionsMenuItems[] = { MENUITEMTYPE_CHECKBOX, 0, MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"No melee/tranquilizer blur", + (uintptr_t)"No Drug Blur", MPOPTION_NODRUGBLUR, menuhandlerMpCheckboxOption, }, diff --git a/src/game/mplayer/scenarios/popacap.inc b/src/game/mplayer/scenarios/popacap.inc index faea5dd70..26221b569 100644 --- a/src/game/mplayer/scenarios/popacap.inc +++ b/src/game/mplayer/scenarios/popacap.inc @@ -61,7 +61,7 @@ struct menuitem g_PacOptionsMenuItems[] = { MENUITEMTYPE_CHECKBOX, 0, MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Spawn With Weapon", + (uintptr_t)"Spawn With Gun", MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, @@ -69,7 +69,7 @@ struct menuitem g_PacOptionsMenuItems[] = { MENUITEMTYPE_CHECKBOX, 0, MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"No melee/tranquilizer blur", + (uintptr_t)"No Drug Blur", MPOPTION_NODRUGBLUR, menuhandlerMpCheckboxOption, }, From dc9d0f3c9c29ac75dd6b213f0c2a2db529cacdcb Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 14 May 2024 11:50:07 +0200 Subject: [PATCH 46/68] ci: give write permission to release job --- .github/workflows/c-cpp.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 5a940b1a6..5e1566fe2 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -70,6 +70,8 @@ jobs: runs-on: ubuntu-latest if: github.ref == 'refs/heads/port' needs: [build-i686-windows, build-i686-linux] + permissions: + contents: write steps: - uses: actions/checkout@v4 - uses: actions/download-artifact@v4 From 865ca682dc48750996c7b98309be81f85a9d7461 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 14 May 2024 11:58:04 +0200 Subject: [PATCH 47/68] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4c4e4913a..a855ea0f2 100644 --- a/README.md +++ b/README.md @@ -40,9 +40,9 @@ though you might have to install some additional libraries. ## Download -Latest [automatic builds](https://github.com/fgsfdsfgs/perfect_dark/actions) for supported platforms: -* [i686-windows](https://nightly.link/fgsfdsfgs/perfect_dark/workflows/c-cpp/port/pd-i686-windows.zip) -* [i686-linux](https://nightly.link/fgsfdsfgs/perfect_dark/workflows/c-cpp/port/pd-i686-linux.zip) +Latest [automatic builds](https://github.com/fgsfdsfgs/perfect_dark/releases/tag/ci-dev-build) for supported platforms: +* [i686-windows](https://github.com/fgsfdsfgs/perfect_dark/releases/download/ci-dev-build/pd-i686-windows.zip) +* [i686-linux](https://github.com/fgsfdsfgs/perfect_dark/releases/download/ci-dev-build/pd-i686-linux.tar.gz) If you are looking for netplay builds (the `port-net` branch), see [this link](https://github.com/fgsfdsfgs/perfect_dark/blob/port-net/README.md#download). From a83e0aa4079ad8b3d0626260a0717fb4f0c2d123 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 14 May 2024 20:28:59 +0200 Subject: [PATCH 48/68] port: add mouse control to menus; mouse now unlocks when you pause --- port/include/input.h | 118 ++++++++++++++++----------------- port/src/input.c | 34 ++++++---- port/src/main.c | 1 + src/game/bondmove.c | 6 ++ src/game/menu.c | 140 ++++++++++++++++++++++++++++++++++++---- src/game/menuitem.c | 6 ++ src/game/menustop.c | 9 +++ src/game/player.c | 18 ++++++ src/include/data.h | 1 + src/include/game/menu.h | 2 +- src/include/types.h | 9 +++ 11 files changed, 261 insertions(+), 83 deletions(-) diff --git a/port/include/input.h b/port/include/input.h index 2ddaab94a..fcb9d962c 100644 --- a/port/include/input.h +++ b/port/include/input.h @@ -17,68 +17,68 @@ #define CONT_NUM_BUTTONS 32 // not including the stick axes enum virtkey { - /* same order as SDL scancodes */ - VK_KEYBOARD_BEGIN = 0, - VK_RETURN = 40, - VK_ESCAPE = 41, - VK_DELETE = 76, + /* same order as SDL scancodes */ + VK_KEYBOARD_BEGIN = 0, + VK_RETURN = 40, + VK_ESCAPE = 41, + VK_DELETE = 76, - /* same order as SDL mouse buttons */ - VK_MOUSE_BEGIN = 512, - VK_MOUSE_LEFT = VK_MOUSE_BEGIN, - VK_MOUSE_MIDDLE, - VK_MOUSE_RIGHT, - VK_MOUSE_X1, - VK_MOUSE_X2, - VK_MOUSE_WHEEL_UP, - VK_MOUSE_WHEEL_DN, + /* same order as SDL mouse buttons */ + VK_MOUSE_BEGIN = 512, + VK_MOUSE_LEFT = VK_MOUSE_BEGIN, + VK_MOUSE_MIDDLE, + VK_MOUSE_RIGHT, + VK_MOUSE_X1, + VK_MOUSE_X2, + VK_MOUSE_WHEEL_UP, + VK_MOUSE_WHEEL_DN, - /* same order as SDL gamecontroller buttons plus two buttons for triggers */ - VK_JOY_BEGIN, - VK_JOY1_BEGIN = VK_JOY_BEGIN, - VK_JOY1_LTRIG = VK_JOY1_BEGIN + 30, - VK_JOY1_RTRIG = VK_JOY1_BEGIN + 31, - VK_JOY2_BEGIN = VK_JOY1_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS, - VK_JOY3_BEGIN = VK_JOY2_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS, - VK_JOY4_BEGIN = VK_JOY3_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS, + /* same order as SDL gamecontroller buttons plus two buttons for triggers */ + VK_JOY_BEGIN, + VK_JOY1_BEGIN = VK_JOY_BEGIN, + VK_JOY1_LTRIG = VK_JOY1_BEGIN + 30, + VK_JOY1_RTRIG = VK_JOY1_BEGIN + 31, + VK_JOY2_BEGIN = VK_JOY1_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS, + VK_JOY3_BEGIN = VK_JOY2_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS, + VK_JOY4_BEGIN = VK_JOY3_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS, - VK_TOTAL_COUNT = VK_JOY_BEGIN + INPUT_MAX_CONTROLLERS * INPUT_MAX_CONTROLLER_BUTTONS, + VK_TOTAL_COUNT = VK_JOY_BEGIN + INPUT_MAX_CONTROLLERS * INPUT_MAX_CONTROLLER_BUTTONS, }; enum contkey { - CK_C_R, - CK_C_L, - CK_C_D, - CK_C_U, - CK_RTRIG, - CK_LTRIG, - CK_X, // gap in CONT_ - CK_Y, // gap in CONT_ - CK_DPAD_R, - CK_DPAD_L, - CK_DPAD_D, - CK_DPAD_U, - CK_START, - CK_ZTRIG, - CK_B, - CK_A, - CK_STICK_XNEG, - CK_STICK_XPOS, - CK_STICK_YNEG, - CK_STICK_YPOS, - CK_0010, - CK_0020, - CK_0040, - CK_0080, - CK_0100, - CK_0200, - CK_0400, - CK_0800, - CK_1000, - CK_2000, - CK_4000, - CK_8000, - CK_TOTAL_COUNT + CK_C_R, + CK_C_L, + CK_C_D, + CK_C_U, + CK_RTRIG, + CK_LTRIG, + CK_X, // gap in CONT_ + CK_Y, // gap in CONT_ + CK_DPAD_R, + CK_DPAD_L, + CK_DPAD_D, + CK_DPAD_U, + CK_START, + CK_ZTRIG, + CK_B, + CK_A, + CK_STICK_XNEG, + CK_STICK_XPOS, + CK_STICK_YNEG, + CK_STICK_YPOS, + CK_0010, + CK_0020, + CK_0040, + CK_0080, + CK_0100, + CK_0200, + CK_0400, + CK_0800, + CK_1000, + CK_2000, + CK_4000, + CK_8000, + CK_TOTAL_COUNT }; // returns bitmask of connected controllers or -1 if failed @@ -132,6 +132,7 @@ s32 inputAssignController(s32 cidx, s32 id); // vk is a value from the virtkey enum above s32 inputKeyPressed(u32 vk); +s32 inputKeyJustPressed(u32 vk); // idx is controller index, contbtn is one of the CONT_ constants s32 inputButtonPressed(s32 idx, u32 contbtn); @@ -166,8 +167,9 @@ void inputLockMouse(s32 lock); // returns the current state of the above s32 inputMouseIsLocked(void); -// returns mouse position in native viewport coordinates (ie, 320x240 most of the time) -void inputMouseGetPosition(s32 *x, s32 *y); +// sets x, y to mouse position in native viewport coordinates (ie, 320x240 most of the time) +// returns true if mouse has moved this input frame +s32 inputMouseGetPosition(s32 *x, s32 *y); // returns changes in mouse position since last frame, in window coordinates void inputMouseGetRawDelta(s32 *dx, s32 *dy); diff --git a/port/src/input.c b/port/src/input.c index 96438e3f6..69e28508f 100644 --- a/port/src/input.c +++ b/port/src/input.c @@ -169,6 +169,8 @@ static const char *vkJoyNames[] = { static char vkNames[VK_TOTAL_COUNT][64]; +static s8 vkPrevState[VK_TOTAL_COUNT]; + void inputSetDefaultKeyBinds(s32 cidx, s32 n64mode) { // TODO: make VK constants for all these @@ -799,12 +801,6 @@ static inline void inputUpdateMouse(void) mouseX = mx; mouseY = my; - - if (!mouseLocked && (mouseButtons & SDL_BUTTON_LMASK)) { - inputLockMouse(1); - } else if (mouseLocked && inputKeyPressed(VK_ESCAPE)) { - inputLockMouse(0); - } } void inputUpdate(void) @@ -1051,9 +1047,13 @@ s32 inputKeyPressed(u32 vk) if (vk >= VK_KEYBOARD_BEGIN && vk < VK_MOUSE_BEGIN) { const u8 *state = SDL_GetKeyboardState(NULL); return state[vk - VK_KEYBOARD_BEGIN]; - } else if (vk >= VK_MOUSE_BEGIN && vk < VK_JOY_BEGIN) { - return mouseButtons & SDL_BUTTON(vk - VK_MOUSE_BEGIN + 1); - } else if (vk >= VK_JOY_BEGIN && vk < VK_TOTAL_COUNT) { + } + + if (vk >= VK_MOUSE_BEGIN && vk < VK_JOY_BEGIN) { + return (mouseButtons & SDL_BUTTON(vk - VK_MOUSE_BEGIN + 1)) != 0; + } + + if (vk >= VK_JOY_BEGIN && vk < VK_TOTAL_COUNT) { vk -= VK_JOY_BEGIN; const s32 idx = vk / INPUT_MAX_CONTROLLER_BUTTONS; if (idx < 0 || idx >= INPUT_MAX_CONTROLLERS || !pads[idx]) { @@ -1067,9 +1067,18 @@ s32 inputKeyPressed(u32 vk) } return SDL_GameControllerGetButton(pads[idx], vk); } + return 0; } +s32 inputKeyJustPressed(u32 vk) +{ + const s8 pressed = inputKeyPressed(vk); + const s32 result = pressed && !vkPrevState[vk]; + vkPrevState[vk] = pressed; + return result; +} + static inline u32 inputContToContKey(const u32 cont) { if (cont == 0) { @@ -1099,10 +1108,11 @@ s32 inputMouseIsLocked(void) return mouseLocked; } -void inputMouseGetPosition(s32 *x, s32 *y) +s32 inputMouseGetPosition(s32 *x, s32 *y) { if (x) *x = mouseX * videoGetNativeWidth() / videoGetWidth(); if (y) *y = mouseY * videoGetNativeHeight() / videoGetHeight(); + return (mouseDX != 0 || mouseDY != 0); } void inputMouseGetRawDelta(s32 *dx, s32 *dy) @@ -1172,9 +1182,7 @@ s32 inputGetMouseDefaultLocked(void) void inputSetMouseDefaultLocked(s32 defaultLocked) { mouseDefaultLocked = !!defaultLocked; - if (mouseEnabled) { - inputLockMouse(mouseDefaultLocked); - } + inputLockMouse(mouseDefaultLocked); } const char *inputGetContKeyName(u32 ck) diff --git a/port/src/main.c b/port/src/main.c index fa39ff518..e31e090a2 100644 --- a/port/src/main.c +++ b/port/src/main.c @@ -159,6 +159,7 @@ PD_CONSTRUCTOR static void gameConfigInit(void) { configRegisterInt("Game.MemorySize", &g_OsMemSizeMb, 4, 2048); configRegisterInt("Game.CenterHUD", &g_HudCenter, 0, 2); + configRegisterInt("Game.MenuMouseControl", &g_MenuMouseControl, 0, 1); configRegisterFloat("Game.ScreenShakeIntensity", &g_ViShakeIntensityMult, 0.f, 10.f); configRegisterInt("Game.TickRateDivisor", &g_TickRateDiv, 0, 10); configRegisterInt("Game.ExtraSleep", &g_TickExtraSleep, 0, 1); diff --git a/src/game/bondmove.c b/src/game/bondmove.c index 9b59f3847..ede1b11d0 100644 --- a/src/game/bondmove.c +++ b/src/game/bondmove.c @@ -780,6 +780,12 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i movedata.freelookdy = -movedata.freelookdy; } } + // always pause with ESC + if (allowc1buttons && g_Vars.currentplayer->isdead == false && g_Vars.currentplayer->pausemode == PAUSEMODE_UNPAUSED) { + if (inputKeyJustPressed(VK_ESCAPE)) { + c1buttonsthisframe |= START_BUTTON; + } + } #endif // Pausing diff --git a/src/game/menu.c b/src/game/menu.c index 46e743aca..68742bf24 100644 --- a/src/game/menu.c +++ b/src/game/menu.c @@ -50,6 +50,7 @@ #include "types.h" #ifndef PLATFORM_N64 #include "video.h" +#include "input.h" #define BLUR_OFS 10 #else #define BLUR_OFS 30 @@ -136,6 +137,10 @@ char *g_StringPointer2 = &g_CheatMarqueeString[VERSION >= VERSION_PAL_FINAL ? 15 s32 g_MpPlayerNum = 0; +#ifndef PLATFORM_N64 +s32 g_MenuMouseControl = true; +#endif + void menuPlaySound(s32 menusound) { s32 sound = -1; @@ -1347,20 +1352,68 @@ s32 dialogChangeItemFocusHorizontally(struct menudialog *dialog, s32 leftright) return swipedir; } -s32 dialogChangeItemFocus(struct menudialog *dialog, s32 leftright, s32 updown) +#ifndef PLATFORM_N64 + +bool dialogChangeItemFocusWithMouse(struct menudialog *dialog, s32 mx, s32 my) +{ + struct menu *menu = &g_Menus[g_MpPlayerNum]; + s32 col, row; + s32 curx, cury; + s32 colwidth = 0; + + // only allow mouse control of player 1 menus + if (menu->playernum != 0) { + return false; + } + + curx = dialog->x; + + for (col = 0; col < dialog->numcols; col++, curx += colwidth) { + s32 colindex = dialog->colstart + col; + colwidth = menu->cols[colindex].width; + if (mx <= curx || mx >= curx + colwidth) { + continue; + } + + cury = dialog->y + LINEHEIGHT + 1 + dialog->scroll; + for (row = 0; row < menu->cols[colindex].numrows; row++) { + s32 rowindex = menu->cols[colindex].rowstart + row; + s32 rowheight = menu->rows[rowindex].height; + struct menuitem *item = &dialog->definition->items[menu->rows[rowindex].itemindex]; + if (my > cury && my < cury + rowheight && + item != dialog->focuseditem && menuIsItemFocusable(item, dialog, 0)) { + dialog->focuseditem = item; + return true; + } + cury += rowheight; + } + } + + return false; +} + +#endif + +s32 dialogChangeItemFocus(struct menudialog *dialog, struct menuinputs *inputs) { s32 swipedir = 0; - if (leftright == 0 && updown == 0) { + if (inputs->leftright == 0 && inputs->updown == 0) { +#ifndef PLATFORM_N64 + if (!dialogChangeItemFocusWithMouse(dialog, inputs->mousex, inputs->mousey)) { + return 0; + } +#else return 0; +#endif } - if (updown != 0) { - dialogChangeItemFocusVertically(dialog, updown); + if (inputs->updown != 0) { + dialogChangeItemFocusVertically(dialog, inputs->updown); } - if (leftright != 0) { - swipedir = dialogChangeItemFocusHorizontally(dialog, leftright); + if (inputs->leftright != 0) { + swipedir = dialogChangeItemFocusHorizontally(dialog, inputs->leftright); } if (dialog->focuseditem != 0) { @@ -1448,6 +1501,10 @@ void menuOpenDialog(struct menudialogdef *dialogdef, struct menudialog *dialog, dialog->y = dialog->dsty; dialog->width = dialog->dstwidth; dialog->height = dialog->dstheight; + +#ifndef PLATFORM_N64 + dialog->usingmouse = false; +#endif } void menuPushDialog(struct menudialogdef *dialogdef) @@ -3418,6 +3475,12 @@ void menuClose(void) g_Menus[g_MpPlayerNum].curdialog = NULL; g_Menus[g_MpPlayerNum].openinhibit = 10; +#ifndef PLATFORM_N64 + if (inputMouseIsEnabled()) { + inputLockMouse(true); + } +#endif + if (g_MenuData.root == MENUROOT_MPPAUSE) { g_PlayersWithControl[g_Menus[g_MpPlayerNum].playernum] = true; } @@ -3528,6 +3591,12 @@ void menuPushRootDialog(struct menudialogdef *dialogdef, s32 root) g_PlayersWithControl[g_Menus[g_MpPlayerNum].playernum] = false; +#ifndef PLATFORM_N64 + if (inputMouseIsEnabled()) { + inputLockMouse(false); + } +#endif + func0f0f1494(); g_MenuData.count++; @@ -4389,14 +4458,14 @@ void dialogTick(struct menudialog *dialog, struct menuinputs *inputs, u32 tickfl if (layer->numsiblings <= 1) { struct menuitem *prevfocuseditem = dialog->focuseditem; - dialogChangeItemFocus(dialog, inputs->leftright, inputs->updown); + dialogChangeItemFocus(dialog, inputs); if (dialog->focuseditem != prevfocuseditem) { menuPlaySound(MENUSOUND_FOCUS); } } else { struct menuitem *prevfocuseditem = dialog->focuseditem; - s32 swipedir = dialogChangeItemFocus(dialog, inputs->leftright, inputs->updown); + s32 swipedir = dialogChangeItemFocus(dialog, inputs); if (swipedir != 0) { menuSwipe(swipedir); @@ -4441,8 +4510,15 @@ void dialogTick(struct menudialog *dialog, struct menuinputs *inputs, u32 tickfl s32 y = dialogFindItem(dialog, dialog->focuseditem, &rowindex, &colindex); if ((dialog->focuseditem->flags & MENUITEMFLAG_00010000) == 0) { - itemy = y + menu->rows[rowindex].height / 2; - dstscroll = (dialog->height - LINEHEIGHT - 1) / 2 - itemy; +#ifndef PLATFORM_N64 + if (dialog->usingmouse) { + dstscroll = dialog->dstscroll - inputs->mousescroll * LINEHEIGHT; + } else +#endif + { + itemy = y + menu->rows[rowindex].height / 2; + dstscroll = (dialog->height - LINEHEIGHT - 1) / 2 - itemy; + } if (dstscroll > 0) { dstscroll = 0; @@ -4590,6 +4666,28 @@ void menuProcessInput(void) inputs.shoulder = 0; inputs.back2 = 0; +#ifndef PLATFORM_N64 + inputs.mousemoved = false; + inputs.mousescroll = 0; + inputs.mousex = 0; + inputs.mousey = 0; + // only allow mouse controls for player 1 menus + if (menu->playernum == 0) { + // ESC always acts as back + inputs.back = inputKeyJustPressed(VK_ESCAPE); + if (inputMouseIsEnabled() && !inputMouseIsLocked() && g_MenuMouseControl) { + inputs.mousemoved = inputMouseGetPosition(&inputs.mousex, &inputs.mousey); + inputs.mousescroll = inputKeyPressed(VK_MOUSE_WHEEL_DN) - inputKeyPressed(VK_MOUSE_WHEEL_UP); + // aspect correct the X + const f32 cx = ((f32)inputs.mousex - (f32)(SCREEN_WIDTH_LO / 2)) * (videoGetAspect() / SCREEN_ASPECT); + inputs.mousex = (f32)(SCREEN_WIDTH_LO / 2) + cx; + } + if (dialog && inputs.mousemoved) { + dialog->usingmouse = true; + } + } +#endif + if (g_Menus[g_MpPlayerNum].curdialog) { stickx = 0; sticky = 0; @@ -4651,7 +4749,8 @@ void menuProcessInput(void) inputs.select = 1; } - if (buttonsnow & BUTTON_WPNBACK) { + // don't back out on weapon back when using mouse because it's likely bound to wheel + if (!dialog->usingmouse && (buttonsnow & BUTTON_WPNBACK)) { inputs.back = 1; } #endif @@ -4994,6 +5093,25 @@ void menuProcessInput(void) inputs.unk14 = 0; inputs.start = starttap ? true : false; +#ifndef PLATFORM_N64 + // if we haven't been using the mouse but we have been keyboard scrolling disable the mouse + if (!inputs.mousemoved && (inputs.leftright || inputs.updown || inputs.leftrightheld || inputs.updownheld)) { + dialog->usingmouse = false; + } + // otherwise rotate left/right by clicking on the side of the menu + if (dialog->usingmouse && inputs.select && !inputs.leftright && !inputs.leftrightheld) { + if (inputs.mousey > dialog->y && inputs.mousey < dialog->y + dialog->height) { + if (inputs.mousex < dialog->x) { + inputs.leftright = -1; + inputs.select = 0; + } else if (inputs.mousex > dialog->x + dialog->width) { + inputs.leftright = 1; + inputs.select = 0; + } + } + } +#endif + // Handle dialogs that allow pressing start to select, // and handle pressing start on a list item. if (g_Menus[g_MpPlayerNum].curdialog && starttap) { diff --git a/src/game/menuitem.c b/src/game/menuitem.c index 0f5d68b6b..117d92bd4 100644 --- a/src/game/menuitem.c +++ b/src/game/menuitem.c @@ -732,9 +732,15 @@ bool menuitemListTick(struct menuitem *item, struct menuinputs *inputs, u32 tick data->list.targetoffsety = menuitemListGetOffsetY(data->list.index, item); } +#ifdef PLATFORM_N64 if (inputs->updown) { prev2 = data->list.index; data->list.index += inputs->updown; +#else + if (inputs->updown || inputs->mousescroll) { + prev2 = data->list.index; + data->list.index += inputs->updown + inputs->mousescroll; +#endif if (data->list.index < 0) { data->list.index = handlerdata.list.value - 1; diff --git a/src/game/menustop.c b/src/game/menustop.c index a58773847..d86344a46 100644 --- a/src/game/menustop.c +++ b/src/game/menustop.c @@ -26,9 +26,18 @@ #include "lib/snd.h" #include "data.h" #include "types.h" +#ifndef PLATFORM_N64 +#include "input.h" +#endif void menuStop(void) { +#ifndef PLATFORM_N64 + if (inputMouseIsEnabled()) { + inputLockMouse(true); + } +#endif + if (var80062944) { var80062944 = 0; var80062948 = 0; diff --git a/src/game/player.c b/src/game/player.c index eb4e2c891..a74753fa5 100644 --- a/src/game/player.c +++ b/src/game/player.c @@ -2039,6 +2039,12 @@ void playerTickCutscene(bool arg0) g_CutsceneCurTotalFrame60f += g_Vars.lvupdate60freal; } +#ifndef PLATFORM_N64 + if (arg0 && inputKeyJustPressed(VK_ESCAPE)) { + buttons |= START_BUTTON; + } +#endif + #if VERSION >= VERSION_NTSC_1_0 if (g_CutsceneCurTotalFrame60f > 30 && (buttons & 0xffffffff)) { g_CutsceneSkipRequested = true; @@ -3297,6 +3303,12 @@ void playerTick(bool arg0) s8 contpad1 = optionsGetContpadNum1(g_Vars.currentplayerstats->mpindex); u32 buttons = arg0 ? joyGetButtons(contpad1, 0xffffffff) : 0; +#ifndef PLATFORM_N64 + if (arg0 && inputKeyJustPressed(VK_ESCAPE)) { + buttons |= START_BUTTON; + } +#endif + if (g_Vars.currentplayer->isdead == false && g_Vars.currentplayer->pausemode == PAUSEMODE_UNPAUSED && (buttons & START_BUTTON)) { @@ -3577,6 +3589,12 @@ void playerTick(bool arg0) } } +#ifndef PLATFORM_N64 + if (g_PlayersWithControl[g_Vars.currentplayernum] && inputKeyJustPressed(VK_ESCAPE)) { + pause = true; + } +#endif + if (pause) { if (g_Vars.mplayerisrunning == false) { playerPause(MENUROOT_MAINMENU); diff --git a/src/include/data.h b/src/include/data.h index c59d6ba99..853dbd622 100644 --- a/src/include/data.h +++ b/src/include/data.h @@ -540,6 +540,7 @@ extern const struct weathercfg *g_CurWeatherConfig; extern f32 g_ViShakeIntensityMult; extern u32 g_TexFilter2D; extern s32 g_HudCenter; +extern s32 g_MenuMouseControl; extern u32 g_HudAlignModeL; extern u32 g_HudAlignModeR; extern s32 g_PrevFrameFb; diff --git a/src/include/game/menu.h b/src/include/game/menu.h index 46fd44ad6..419fb659e 100644 --- a/src/include/game/menu.h +++ b/src/include/game/menu.h @@ -46,7 +46,7 @@ struct menuitem *dialogFindFirstItem(struct menudialog *dialog); struct menuitem *dialogFindFirstItemRight(struct menudialog *dialog); void dialogChangeItemFocusVertically(struct menudialog *dialog, s32 updown); s32 dialogChangeItemFocusHorizontally(struct menudialog *dialog, s32 leftright); -s32 dialogChangeItemFocus(struct menudialog *dialog, s32 leftright, s32 updown); +s32 dialogChangeItemFocus(struct menudialog *dialog, struct menuinputs *inputs); void menuOpenDialog(struct menudialogdef *dialogdef, struct menudialog *arg1, struct menu *menu); void menuPushDialog(struct menudialogdef *dialogdef); diff --git a/src/include/types.h b/src/include/types.h index 0d772d798..57f018b7a 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -3739,6 +3739,9 @@ struct menudialog { /*0x6c*/ u8 unk6c; /*0x6d*/ s8 swipedir; /*0x6e*/ u8 unk6e; +#ifndef PLATFORM_N64 + /*0x6f*/ u8 usingmouse; +#endif }; struct menudfc { @@ -4991,6 +4994,12 @@ struct menuinputs { /*0x0c*/ s32 unk0c; /*0x10*/ s32 unk10; /*0x14*/ u8 unk14; +#ifndef PLATFORM_N64 + /*0x15*/ u8 mousemoved; + /*0x16*/ s8 mousescroll; + /*0x18*/ s32 mousex; + /*0x1c*/ s32 mousey; +#endif }; struct mpconfigsim { From 85872d7e715e49c4995fb66cf045c227a0fed965 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 14 May 2024 20:58:51 +0200 Subject: [PATCH 49/68] port: add mouse controls to virtual keyboard --- src/game/menuitem.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/game/menuitem.c b/src/game/menuitem.c index 117d92bd4..6f585b75b 100644 --- a/src/game/menuitem.c +++ b/src/game/menuitem.c @@ -1366,6 +1366,34 @@ bool menuitemKeyboardTick(struct menuitem *item, struct menuinputs *inputs, u32 s16 prevcol = kb->col; s16 prevrow = kb->row; +#ifndef PLATFORM_N64 + // handle mouse + struct menudialog *dialog = g_Menus[g_MpPlayerNum].curdialog; + if (dialog && dialog->usingmouse && !inputs->leftright && !inputs->updown) { + const s32 dleft = dialog->x + 4; + const s32 dright = dleft + 12 * 10; + const s32 dtop = dialog->y + 13 + 12; + const s32 dbottom = dtop + 11 * 5; + const s32 mx = inputs->mousex; + const s32 my = inputs->mousey; + if (mx > dleft && mx < dright && my > dtop && my < dbottom) { + kb->row = (my - dtop) / 11; + kb->col = (mx - dleft) / 12; + if (kb->row == 4) { + if (kb->col < 2) { + kb->col = 0; + } else if (kb->col < 5) { + kb->col = 2; + } else if (kb->col < 8) { + kb->col = 5; + } else { + kb->col = 8; + } + } + } + } +#endif + // Handle left/right movement // In most cases the loop only runs once, but on row 4 the buttons span // across multiple columns so the loop will run again until the column From 548e2c1f0bd2e871ac4e2ade1220cbf18e090709 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 14 May 2024 21:06:16 +0200 Subject: [PATCH 50/68] port: only navigate with mouse if it's enabled in the dialog --- src/game/menu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/game/menu.c b/src/game/menu.c index 68742bf24..f660a8bbf 100644 --- a/src/game/menu.c +++ b/src/game/menu.c @@ -1361,8 +1361,8 @@ bool dialogChangeItemFocusWithMouse(struct menudialog *dialog, s32 mx, s32 my) s32 curx, cury; s32 colwidth = 0; - // only allow mouse control of player 1 menus - if (menu->playernum != 0) { + // only allow mouse control of player 1 menus; ignore mouse if navigating with keyboard + if (menu->playernum != 0 || !dialog->usingmouse) { return false; } From 926e4dce287e984fe5773718a6783cdc1baa0958 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 14 May 2024 21:59:44 +0200 Subject: [PATCH 51/68] ci: autobuild pal and jpn and include them in release --- .github/workflows/c-cpp.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 5e1566fe2..a01a2b06d 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -29,10 +29,16 @@ jobs: uses: actions/checkout@v4 - name: Build pd.exe run: make -f Makefile.port -j + - name: Build pd.pal.exe + run: make -f Makefile.port -j ROMID=pal-final + - name: Build pd.jpn.exe + run: make -f Makefile.port -j ROMID=jpn-final - name: Prepare artifact for packaging run: | mkdir -p bin/data cp build/ntsc-final-port/pd.exe bin/ + cp build/pal-final-port/pd.pal.exe bin/ + cp build/jpn-final-port/pd.jpn.exe bin/ cp /mingw32/bin/{SDL2.dll,zlib1.dll,libgcc_s_dw2-1.dll,libwinpthread-1.dll} bin/ touch bin/data/put_your_rom_here.txt - name: Upload artifact @@ -54,10 +60,16 @@ jobs: uses: actions/checkout@v4 - name: Build pd.exe run: make -f Makefile.port TARGET_PLATFORM=i686-linux -j2 + - name: Build pd.pal.exe + run: make -f Makefile.port TARGET_PLATFORM=i686-linux -j2 ROMID=pal-final + - name: Build pd.jpn.exe + run: make -f Makefile.port TARGET_PLATFORM=i686-linux -j2 ROMID=jpn-final - name: Prepare artifact for packaging run: | mkdir -p bin/data cp build/ntsc-final-port/pd.exe bin/pd + cp build/pal-final-port/pd.exe bin/pd.pal + cp build/jpn-final-port/pd.exe bin/pd.jpn touch bin/data/put_your_rom_here.txt - name: Upload artifact uses: actions/upload-artifact@v4 From 45ec35172de0e77cdef488a29a4aff272afd8d65 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 14 May 2024 22:04:27 +0200 Subject: [PATCH 52/68] ci: fix executable names on linux --- .github/workflows/c-cpp.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index a01a2b06d..3515c9d3b 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -68,8 +68,8 @@ jobs: run: | mkdir -p bin/data cp build/ntsc-final-port/pd.exe bin/pd - cp build/pal-final-port/pd.exe bin/pd.pal - cp build/jpn-final-port/pd.exe bin/pd.jpn + cp build/pal-final-port/pd.pal.exe bin/pd.pal + cp build/jpn-final-port/pd.jpn.exe bin/pd.jpn touch bin/data/put_your_rom_here.txt - name: Upload artifact uses: actions/upload-artifact@v4 From bf8192ee84d1d0201e0c86a69ebceb2f6790138d Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 14 May 2024 22:21:14 +0200 Subject: [PATCH 53/68] Update README.md --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a855ea0f2..045a7824a 100644 --- a/README.md +++ b/README.md @@ -50,10 +50,14 @@ If you are looking for netplay builds (the `port-net` branch), see [this link](h You must already have a Perfect Dark ROM to run the game, as specified above. -1. Create a directory named `data` next to `pd.exe`. -2. Put your Perfect Dark ROM named `pd.ntsc-final.z64` into it. +1. Create a directory named `data` next to `pd.exe` if it's not there. +2. Put your Perfect Dark NTSC ROM named `pd.ntsc-final.z64` into it. 3. Run `pd.exe`. +If you want to use a PAL or JPN ROM instead, put them into the `data` directory and run the appropriate executable: +* PAL: ROM name `pd.pal-final.z64`, EXE name `pd.pal.exe`. +* JPN: ROM name `pd.jpn-final.z64`, EXE name `pd.jpn.exe`. + Additional information can be found in the [wiki](https://github.com/fgsfdsfgs/perfect_dark/wiki). A GPU supporting OpenGL 3.0 or above is required to run the port. From 2ba192d411f77526870977c350b2e27e392d2f4c Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 14 May 2024 22:53:02 +0200 Subject: [PATCH 54/68] port: make menu mouse flag global --- src/game/menu.c | 17 +++++++---------- src/game/menuitem.c | 2 +- src/include/data.h | 2 ++ src/include/types.h | 3 --- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/game/menu.c b/src/game/menu.c index f660a8bbf..e91aa5687 100644 --- a/src/game/menu.c +++ b/src/game/menu.c @@ -139,6 +139,7 @@ s32 g_MpPlayerNum = 0; #ifndef PLATFORM_N64 s32 g_MenuMouseControl = true; +s32 g_MenuUsingMouse = false; #endif void menuPlaySound(s32 menusound) @@ -1362,7 +1363,7 @@ bool dialogChangeItemFocusWithMouse(struct menudialog *dialog, s32 mx, s32 my) s32 colwidth = 0; // only allow mouse control of player 1 menus; ignore mouse if navigating with keyboard - if (menu->playernum != 0 || !dialog->usingmouse) { + if (menu->playernum != 0 || !g_MenuUsingMouse) { return false; } @@ -1501,10 +1502,6 @@ void menuOpenDialog(struct menudialogdef *dialogdef, struct menudialog *dialog, dialog->y = dialog->dsty; dialog->width = dialog->dstwidth; dialog->height = dialog->dstheight; - -#ifndef PLATFORM_N64 - dialog->usingmouse = false; -#endif } void menuPushDialog(struct menudialogdef *dialogdef) @@ -4511,7 +4508,7 @@ void dialogTick(struct menudialog *dialog, struct menuinputs *inputs, u32 tickfl if ((dialog->focuseditem->flags & MENUITEMFLAG_00010000) == 0) { #ifndef PLATFORM_N64 - if (dialog->usingmouse) { + if (g_MenuUsingMouse) { dstscroll = dialog->dstscroll - inputs->mousescroll * LINEHEIGHT; } else #endif @@ -4683,7 +4680,7 @@ void menuProcessInput(void) inputs.mousex = (f32)(SCREEN_WIDTH_LO / 2) + cx; } if (dialog && inputs.mousemoved) { - dialog->usingmouse = true; + g_MenuUsingMouse = true; } } #endif @@ -4750,7 +4747,7 @@ void menuProcessInput(void) } // don't back out on weapon back when using mouse because it's likely bound to wheel - if (!dialog->usingmouse && (buttonsnow & BUTTON_WPNBACK)) { + if (!g_MenuUsingMouse && (buttonsnow & BUTTON_WPNBACK)) { inputs.back = 1; } #endif @@ -5096,10 +5093,10 @@ void menuProcessInput(void) #ifndef PLATFORM_N64 // if we haven't been using the mouse but we have been keyboard scrolling disable the mouse if (!inputs.mousemoved && (inputs.leftright || inputs.updown || inputs.leftrightheld || inputs.updownheld)) { - dialog->usingmouse = false; + g_MenuUsingMouse = false; } // otherwise rotate left/right by clicking on the side of the menu - if (dialog->usingmouse && inputs.select && !inputs.leftright && !inputs.leftrightheld) { + if (g_MenuUsingMouse && inputs.select && !inputs.leftright && !inputs.leftrightheld) { if (inputs.mousey > dialog->y && inputs.mousey < dialog->y + dialog->height) { if (inputs.mousex < dialog->x) { inputs.leftright = -1; diff --git a/src/game/menuitem.c b/src/game/menuitem.c index 6f585b75b..d64706f15 100644 --- a/src/game/menuitem.c +++ b/src/game/menuitem.c @@ -1369,7 +1369,7 @@ bool menuitemKeyboardTick(struct menuitem *item, struct menuinputs *inputs, u32 #ifndef PLATFORM_N64 // handle mouse struct menudialog *dialog = g_Menus[g_MpPlayerNum].curdialog; - if (dialog && dialog->usingmouse && !inputs->leftright && !inputs->updown) { + if (dialog && g_MenuUsingMouse && !inputs->leftright && !inputs->updown) { const s32 dleft = dialog->x + 4; const s32 dright = dleft + 12 * 10; const s32 dtop = dialog->y + 13 + 12; diff --git a/src/include/data.h b/src/include/data.h index 853dbd622..24c106292 100644 --- a/src/include/data.h +++ b/src/include/data.h @@ -537,6 +537,8 @@ extern struct weathercfg g_WeatherConfig[WEATHERCFG_MAX_STAGES]; extern const struct weathercfg g_DefaultWeatherConfig; extern const struct weathercfg *g_CurWeatherConfig; +extern s32 g_MenuUsingMouse; + extern f32 g_ViShakeIntensityMult; extern u32 g_TexFilter2D; extern s32 g_HudCenter; diff --git a/src/include/types.h b/src/include/types.h index 57f018b7a..496d002c4 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -3739,9 +3739,6 @@ struct menudialog { /*0x6c*/ u8 unk6c; /*0x6d*/ s8 swipedir; /*0x6e*/ u8 unk6e; -#ifndef PLATFORM_N64 - /*0x6f*/ u8 usingmouse; -#endif }; struct menudfc { From 9530924c217ef1091aa5187e1402b1ddd0fba94f Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 14 May 2024 22:56:47 +0200 Subject: [PATCH 55/68] port: add mouse navigation toggle to options --- port/src/optionsmenu.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/port/src/optionsmenu.c b/port/src/optionsmenu.c index b6ac6dab7..8d042de1b 100644 --- a/port/src/optionsmenu.c +++ b/port/src/optionsmenu.c @@ -132,6 +132,22 @@ static MenuItemHandlerResult menuhandlerMouseDefaultLocked(s32 operation, struct return 0; } +static MenuItemHandlerResult menuhandlerMenuMouseControl(s32 operation, struct menuitem *item, union handlerdata *data) +{ + switch (operation) { + case MENUOP_GET: + return g_MenuMouseControl; + case MENUOP_SET: + g_MenuMouseControl = data->checkbox.value; + if (!g_MenuMouseControl) { + g_MenuUsingMouse = false; + } + break; + } + + return 0; +} + static MenuItemHandlerResult menuhandlerMouseSpeedX(s32 operation, struct menuitem *item, union handlerdata *data) { f32 x, y; @@ -265,6 +281,14 @@ struct menuitem g_ExtendedMouseMenuItems[] = { 0, menuhandlerMouseDefaultLocked, }, + { + MENUITEMTYPE_CHECKBOX, + 0, + MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"Mouse Menu Navigation", + 0, + menuhandlerMenuMouseControl, + }, { MENUITEMTYPE_SEPARATOR, 0, From da8b9be09d3bb334f63cafb1e8427a9a9ce6b39c Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 14 May 2024 22:59:20 +0200 Subject: [PATCH 56/68] port: completely disable back on WPNBACK if using mouse navigation --- src/game/menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/menu.c b/src/game/menu.c index e91aa5687..ffa389088 100644 --- a/src/game/menu.c +++ b/src/game/menu.c @@ -4747,7 +4747,7 @@ void menuProcessInput(void) } // don't back out on weapon back when using mouse because it's likely bound to wheel - if (!g_MenuUsingMouse && (buttonsnow & BUTTON_WPNBACK)) { + if (!g_MenuMouseControl && (buttonsnow & BUTTON_WPNBACK)) { inputs.back = 1; } #endif From a6e7d503e6fac76a267c7e0dc5cc3b255a9ca976 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 14 May 2024 23:16:36 +0200 Subject: [PATCH 57/68] port: add mouse controls to sliders --- src/game/menuitem.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/game/menuitem.c b/src/game/menuitem.c index d64706f15..27e1f0353 100644 --- a/src/game/menuitem.c +++ b/src/game/menuitem.c @@ -2454,6 +2454,34 @@ bool menuitemSliderTick(struct menuitem *item, struct menudialog *dialog, struct f32 f14; if ((tickflags & MENUTICKFLAG_ITEMISFOCUSED)) { +#ifndef PLATFORM_N64 + if (g_MenuUsingMouse && inputs->select) { + // handle mouse + struct menudialog *dialog = g_Menus[g_MpPlayerNum].curdialog; + if (dialog) { + const s32 left = dialog->x + dialog->width - 82; + const s32 right = dialog->x + dialog->width - 7; + const s32 size = right - left; + const s32 delta = inputs->mousex - left; + if (delta >= -8 && delta <= size + 8) { + index = (delta / (f32)size) * item->param3; + if (index < 0) { + index = 0; + } + if (index > item->param3) { + index = item->param3; + } + if (item->handler) { + item->handler(MENUOP_GET, item, &handlerdata); + handlerdata.slider.value = index; + item->handler(MENUOP_SET, item, &handlerdata); + } + return true; + } + } + } +#endif + if (tickflags & MENUTICKFLAG_DIALOGISDIMMED) { if (item->handler) { item->handler(MENUOP_GETSLIDER, item, &handlerdata); From f3757e75e9e993e42893c44add38827de53e5b83 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Wed, 15 May 2024 12:10:17 +0200 Subject: [PATCH 58/68] port: don't crash when spawn with weapon is on and that weapon is a shield --- src/game/bot.c | 3 ++- src/game/player.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/game/bot.c b/src/game/bot.c index 826bc2a51..b9b4c0a2e 100644 --- a/src/game/bot.c +++ b/src/game/bot.c @@ -264,7 +264,8 @@ void botSpawn(struct chrdata *chr, u8 respawning) #ifndef PLATFORM_N64 if ((g_MpSetup.options & MPOPTION_SPAWNWITHWEAPON) && g_MpSetup.weapons[0] != MPWEAPON_NONE - && g_MpSetup.weapons[0] != MPWEAPON_DISABLED) { + && g_MpSetup.weapons[0] != MPWEAPON_DISABLED + && g_MpSetup.weapons[0] != MPWEAPON_SHIELD) { struct mpweapon *mpweapon = &g_MpWeapons[g_MpSetup.weapons[0]]; botinvGiveSingleWeapon(chr, mpweapon->weaponnum); botactGiveAmmoByType(aibot, mpweapon->priammotype - 1, mpweapon->priammoqty / 2); diff --git a/src/game/player.c b/src/game/player.c index a74753fa5..92ed2e15c 100644 --- a/src/game/player.c +++ b/src/game/player.c @@ -1106,7 +1106,8 @@ void playerSpawn(void) if ((g_MpSetup.options & MPOPTION_SPAWNWITHWEAPON) && g_MpSetup.weapons[0] != MPWEAPON_NONE - && g_MpSetup.weapons[0] != MPWEAPON_DISABLED) { + && g_MpSetup.weapons[0] != MPWEAPON_DISABLED + && g_MpSetup.weapons[0] != MPWEAPON_SHIELD) { struct mpweapon *mpweapon = &g_MpWeapons[g_MpSetup.weapons[0]]; invGiveSingleWeapon(mpweapon->weaponnum); bgunEquipWeapon2(HAND_LEFT, WEAPON_NONE); From 9edfd667b7f2183ab4ee03cbec524797c03aeeb2 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Wed, 15 May 2024 12:13:35 +0200 Subject: [PATCH 59/68] port: give start with weapon a better short name --- src/game/mplayer/scenarios/capturethecase.inc | 2 +- src/game/mplayer/scenarios/combat.inc | 2 +- src/game/mplayer/scenarios/hackthatmac.inc | 2 +- src/game/mplayer/scenarios/holdthebriefcase.inc | 2 +- src/game/mplayer/scenarios/kingofthehill.inc | 2 +- src/game/mplayer/scenarios/popacap.inc | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/game/mplayer/scenarios/capturethecase.inc b/src/game/mplayer/scenarios/capturethecase.inc index 192b8923c..fa6d4946c 100644 --- a/src/game/mplayer/scenarios/capturethecase.inc +++ b/src/game/mplayer/scenarios/capturethecase.inc @@ -65,7 +65,7 @@ struct menuitem g_CtcOptionsMenuItems[] = { MENUITEMTYPE_CHECKBOX, 0, MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Spawn With Gun", + (uintptr_t)"Start Armed", MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, diff --git a/src/game/mplayer/scenarios/combat.inc b/src/game/mplayer/scenarios/combat.inc index 854e38319..5052aea0c 100644 --- a/src/game/mplayer/scenarios/combat.inc +++ b/src/game/mplayer/scenarios/combat.inc @@ -60,7 +60,7 @@ struct menuitem g_MpCombatOptionsMenuItems[] = { MENUITEMTYPE_CHECKBOX, 0, MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Spawn With Gun", + (uintptr_t)"Start Armed", MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, diff --git a/src/game/mplayer/scenarios/hackthatmac.inc b/src/game/mplayer/scenarios/hackthatmac.inc index 9a7cf4b42..32a0a265a 100644 --- a/src/game/mplayer/scenarios/hackthatmac.inc +++ b/src/game/mplayer/scenarios/hackthatmac.inc @@ -63,7 +63,7 @@ struct menuitem g_HtmOptionsMenuItems[] = { MENUITEMTYPE_CHECKBOX, 0, MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Spawn With Gun", + (uintptr_t)"Start Armed", MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, diff --git a/src/game/mplayer/scenarios/holdthebriefcase.inc b/src/game/mplayer/scenarios/holdthebriefcase.inc index b4bfedf75..d0e36e7d0 100644 --- a/src/game/mplayer/scenarios/holdthebriefcase.inc +++ b/src/game/mplayer/scenarios/holdthebriefcase.inc @@ -63,7 +63,7 @@ struct menuitem g_HtbOptionsMenuItems[] = { MENUITEMTYPE_CHECKBOX, 0, MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Spawn With Gun", + (uintptr_t)"Start Armed", MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, diff --git a/src/game/mplayer/scenarios/kingofthehill.inc b/src/game/mplayer/scenarios/kingofthehill.inc index ff72ea228..41810b9a6 100644 --- a/src/game/mplayer/scenarios/kingofthehill.inc +++ b/src/game/mplayer/scenarios/kingofthehill.inc @@ -84,7 +84,7 @@ struct menuitem g_KohOptionsMenuItems[] = { MENUITEMTYPE_CHECKBOX, 0, MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Spawn With Gun", + (uintptr_t)"Start Armed", MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, diff --git a/src/game/mplayer/scenarios/popacap.inc b/src/game/mplayer/scenarios/popacap.inc index 7e37939f7..b667ad269 100644 --- a/src/game/mplayer/scenarios/popacap.inc +++ b/src/game/mplayer/scenarios/popacap.inc @@ -61,7 +61,7 @@ struct menuitem g_PacOptionsMenuItems[] = { MENUITEMTYPE_CHECKBOX, 0, MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Spawn With Gun", + (uintptr_t)"Start Armed", MPOPTION_SPAWNWITHWEAPON, menuhandlerMpCheckboxOption, }, From 5c7d4ecf52cae499a7d07079bb402327cf4aa827 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Wed, 15 May 2024 12:29:39 +0200 Subject: [PATCH 60/68] port: give correct ammo to bots when spawning armed; give at least one round when spawning armed --- src/game/bot.c | 9 ++++++++- src/game/player.c | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/game/bot.c b/src/game/bot.c index b9b4c0a2e..2f087092f 100644 --- a/src/game/bot.c +++ b/src/game/bot.c @@ -268,7 +268,14 @@ void botSpawn(struct chrdata *chr, u8 respawning) && g_MpSetup.weapons[0] != MPWEAPON_SHIELD) { struct mpweapon *mpweapon = &g_MpWeapons[g_MpSetup.weapons[0]]; botinvGiveSingleWeapon(chr, mpweapon->weaponnum); - botactGiveAmmoByType(aibot, mpweapon->priammotype - 1, mpweapon->priammoqty / 2); + const s32 ammotype = (g_MpSetup.weapons[0] == MPWEAPON_COMBATBOOST) ? AMMOTYPE_BOOST : mpweapon->priammotype; + if (ammotype) { + s32 startammo = mpweapon->priammoqty / 2; + if (startammo == 0) { + startammo = 1; + } + botactGiveAmmoByType(aibot, ammotype, startammo); + } botinvSwitchToWeapon(chr, mpweapon->weaponnum, FUNC_PRIMARY); } #endif diff --git a/src/game/player.c b/src/game/player.c index 92ed2e15c..ddb73c726 100644 --- a/src/game/player.c +++ b/src/game/player.c @@ -1110,9 +1110,16 @@ void playerSpawn(void) && g_MpSetup.weapons[0] != MPWEAPON_SHIELD) { struct mpweapon *mpweapon = &g_MpWeapons[g_MpSetup.weapons[0]]; invGiveSingleWeapon(mpweapon->weaponnum); + const s32 ammotype = (g_MpSetup.weapons[0] == MPWEAPON_COMBATBOOST) ? AMMOTYPE_BOOST : mpweapon->priammotype; + if (ammotype) { + s32 startammo = mpweapon->priammoqty / 2; + if (startammo == 0) { + startammo = 1; + } + bgunSetAmmoQuantity(ammotype, startammo); + } bgunEquipWeapon2(HAND_LEFT, WEAPON_NONE); bgunEquipWeapon2(HAND_RIGHT, mpweapon->weaponnum); - bgunSetAmmoQuantity(mpweapon->priammotype, mpweapon->priammoqty / 2); } else #endif { From 4601a9c318fde95b174ddd002103abfcb4cc700a Mon Sep 17 00:00:00 2001 From: fgsfds Date: Wed, 15 May 2024 13:39:12 +0200 Subject: [PATCH 61/68] port: only respect friendly fire setting in team games --- src/game/chraction.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/game/chraction.c b/src/game/chraction.c index 8ff7b6502..6e1daaa8f 100644 --- a/src/game/chraction.c +++ b/src/game/chraction.c @@ -4340,8 +4340,9 @@ void chrDamage(struct chrdata *chr, f32 damage, struct coord *vector, struct gse } #ifndef PLATFORM_N64 - // Don't damage if multiplayer and friendly fire is off + // Don't damage if team multiplayer and friendly fire is off if (g_Vars.mplayerisrunning + && (g_MpSetup.options & MPOPTION_TEAMSENABLED) && !(g_MpSetup.options & MPOPTION_FRIENDLYFIRE) && aprop && aprop != vprop From e8e513fecb03afa787eb39c19c7d1a968ba06ead Mon Sep 17 00:00:00 2001 From: fgsfds Date: Wed, 15 May 2024 14:11:24 +0200 Subject: [PATCH 62/68] port: possible fix for #401 --- src/game/botinv.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/game/botinv.c b/src/game/botinv.c index 77a0522c9..7bb773378 100644 --- a/src/game/botinv.c +++ b/src/game/botinv.c @@ -71,14 +71,14 @@ struct aibotweaponpreference g_AibotWeaponPreferences[] = { /*0x22*/ { 44, 156, 0, 0, 1, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 5, 5, 2, 2, 1, 0 }, // WEAPON_REMOTEMINE /*0x23*/ { 8, 8, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_COMBATBOOST #ifndef PLATFORM_N64 // add all classic weapons to multiplayer - /*0x24*/ { 56, 60, 84, 88, 1, 1, BOTDISTCFG_PISTOL, BOTDISTCFG_CLOSE, 30, 0, 10, 0, 1, 0 }, // WEAPON_PP9I - /*0x25*/ { 56, 60, 84, 88, 1, 1, BOTDISTCFG_PISTOL, BOTDISTCFG_CLOSE, 30, 0, 10, 0, 1, 0 }, // WEAPON_CC13 - /*0x26*/ { 56, 60, 84, 88, 1, 1, BOTDISTCFG_DEFAULT, BOTDISTCFG_CLOSE, 30, 0, 10, 0, 1, 0 }, // WEAPON_KL01313 - /*0x27*/ { 124, 148, 0, 0, 1, 1, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 90, 0, 30, 0, 1, 0 }, // WEAPON_KF7SPECIAL - /*0x28*/ { 116, 128, 136, 152, 1, 1, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 100, 0, 30, 0, 1, 0 }, // WEAPON_ZZT - /*0x29*/ { 124, 148, 0, 0, 1, 1, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 90, 0, 30, 0, 1, 0 }, // WEAPON_DMC + /*0x24*/ { 56, 60, 84, 88, 1, 0, BOTDISTCFG_PISTOL, BOTDISTCFG_CLOSE, 30, 0, 10, 0, 1, 0 }, // WEAPON_PP9I + /*0x25*/ { 56, 60, 84, 88, 1, 0, BOTDISTCFG_PISTOL, BOTDISTCFG_CLOSE, 30, 0, 10, 0, 1, 0 }, // WEAPON_CC13 + /*0x26*/ { 56, 60, 84, 88, 1, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_CLOSE, 30, 0, 10, 0, 1, 0 }, // WEAPON_KL01313 + /*0x27*/ { 124, 148, 0, 0, 1, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 90, 0, 30, 0, 1, 0 }, // WEAPON_KF7SPECIAL + /*0x28*/ { 116, 128, 136, 152, 1, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 100, 0, 30, 0, 1, 0 }, // WEAPON_ZZT + /*0x29*/ { 124, 148, 0, 0, 1, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 90, 0, 30, 0, 1, 0 }, // WEAPON_DMC /*0x2a*/ { 156, 180, 0, 0, 1, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 150, 0, 30, 0, 1, 0 }, // WEAPON_AR53 - /*0x2b*/ { 164, 188, 0, 0, 1, 1, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 200, 0, 40, 0, 1, 0 }, // WEAPON_RCP45 + /*0x2b*/ { 164, 188, 0, 0, 1, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 200, 0, 40, 0, 1, 0 }, // WEAPON_RCP45 #else /*0x24*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_PP9I /*0x25*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_CC13 From 4c552a42f2b3ab015fd7afcb059ee0fd9912b3cd Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sat, 18 May 2024 18:53:12 +0200 Subject: [PATCH 63/68] port: experimental multithreaded audio --- Makefile.port | 4 +-- port/fast3d/gfx_sdl2.cpp | 2 +- port/include/audio.h | 3 +- port/include/system.h | 6 +++- port/include/thread.h | 27 ++++++++++++++ port/src/audio.c | 40 ++++++++++++--------- port/src/libultra.c | 2 +- port/src/pdmain.c | 2 +- port/src/pdsched.c | 19 +--------- port/src/system.c | 11 ++++-- port/src/thread.c | 27 ++++++++++++++ port/src/video.c | 3 +- src/game/chraicommands.c | 10 ++---- src/game/timing.c | 2 +- src/include/lib/audiomgr.h | 7 +++- src/include/platform.h | 3 ++ src/lib/audiomgr.c | 74 ++++++++++++++++++++++++++++++++++++++ 17 files changed, 186 insertions(+), 56 deletions(-) create mode 100644 port/include/thread.h create mode 100644 port/src/thread.c diff --git a/Makefile.port b/Makefile.port index 650f02474..b3e3b953e 100644 --- a/Makefile.port +++ b/Makefile.port @@ -150,7 +150,7 @@ B_DIR := build/$(ROMID)-port G_DIR := src/generated/$(ROMID) ifneq (,$(findstring windows,$(TARGET_PLATFORM))) - TARGET_CFLAGS := $(shell pkg-config sdl2 --cflags-only-I) + TARGET_CFLAGS := $(shell pkg-config sdl2 --cflags-only-I) -pthread TARGET_LDFLAGS := $(shell pkg-config sdl2 --libs) -lz -lopengl32 -ldbghelp # on windows/mingw we need this to be built with a 32-bit compiler so it finds the correct libs TOOLCHAIN ?= i686-w64-mingw32- @@ -161,7 +161,7 @@ ifneq (,$(findstring windows,$(TARGET_PLATFORM))) TARGET_LDFLAGS += -lstdc++ endif else # assume *nix - TARGET_CFLAGS := $(shell pkg-config sdl2 --cflags-only-I) + TARGET_CFLAGS := $(shell pkg-config sdl2 --cflags-only-I) -pthread TARGET_LDFLAGS := $(shell pkg-config sdl2 --libs) -lGL -lz -ldl ifneq (,$(findstring arm,$(TARGET_PLATFORM))$(findstring aarch,$(TARGET_PLATFORM))) # linux on arm or aarch64 diff --git a/port/fast3d/gfx_sdl2.cpp b/port/fast3d/gfx_sdl2.cpp index 181038d26..537b4c52d 100644 --- a/port/fast3d/gfx_sdl2.cpp +++ b/port/fast3d/gfx_sdl2.cpp @@ -261,7 +261,7 @@ static inline void sync_framerate_with_timer(void) { // We want to exit a bit early, so we can busy-wait the rest to never miss the deadline left -= 15000UL; if (left > 0) { - sysSleep(left); + sysFrameLimiterSleep(left); } do { diff --git a/port/include/audio.h b/port/include/audio.h index 32fc16cbe..8aa5a453c 100644 --- a/port/include/audio.h +++ b/port/include/audio.h @@ -6,7 +6,6 @@ s32 audioInit(void); s32 audioGetBytesBuffered(void); s32 audioGetSamplesBuffered(void); -void audioSetNextBuffer(const s16 *buf, u32 len); -void audioEndFrame(void); +void audioSubmitBuffer(const s16 *buf, u32 size); #endif diff --git a/port/include/system.h b/port/include/system.h index 84d568382..b65690b47 100644 --- a/port/include/system.h +++ b/port/include/system.h @@ -35,7 +35,11 @@ void *sysMemZeroAlloc(const u32 size); void sysMemFree(void *ptr); // hns is specified in 100ns units -void sysSleep(const s64 hns); +// do not use sysFrameLimiterSleep on any thread other than the main one +void sysFrameLimiterSleep(const s64 hns); + +// us is specified in microseconds +void sysSleep(const s64 us); // yield CPU if supported (e.g. during a busy loop) void sysCpuRelax(void); diff --git a/port/include/thread.h b/port/include/thread.h new file mode 100644 index 000000000..7a9f6383f --- /dev/null +++ b/port/include/thread.h @@ -0,0 +1,27 @@ +#ifndef _IN_THREAD_H +#define _IN_THREAD_H + +#include +#include "platform.h" + +// TODO: backends +#ifndef PLATFORM_USE_PTHREAD +#error "No available thread backend." +#endif + +#include + +#define SYSMUTEX_STATIC_INIT PTHREAD_MUTEX_INITIALIZER + +typedef pthread_t systhread; +typedef pthread_mutex_t sysmutex; + +typedef void *(*systhreadfn)(void *); + +s32 sysThreadCreate(systhread *thread, systhreadfn func, void *arg); +s32 sysThreadJoin(systhread *thread, void **result); + +void sysMutexLock(sysmutex *mtx); +void sysMutexUnlock(sysmutex *mtx); + +#endif // _IN_THREAD_H diff --git a/port/src/audio.c b/port/src/audio.c index c66cf5912..f0f172de5 100644 --- a/port/src/audio.c +++ b/port/src/audio.c @@ -7,12 +7,13 @@ #include "system.h" static SDL_AudioDeviceID dev; -static const s16 *nextBuf; -static u32 nextSize = 0; static s32 bufferSize = 512; static s32 queueLimit = 8192; +static f32 offsetFrames = 0.5f; +static u32 offsetBytes; + s32 audioInit(void) { if (SDL_InitSubSystem(SDL_INIT_AUDIO) != 0) { @@ -28,7 +29,8 @@ s32 audioInit(void) want.samples = bufferSize; want.callback = NULL; - nextBuf = NULL; + const f32 spf = (f32)want.freq / (PAL ? 50.f : 60.f); + offsetBytes = offsetFrames * spf * (f32)sizeof(int16_t); dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0); if (dev == 0) { @@ -43,33 +45,39 @@ s32 audioInit(void) s32 audioGetBytesBuffered(void) { - return SDL_GetQueuedAudioSize(dev); + u32 count = SDL_GetQueuedAudioSize(dev); + + // pd's audio code decides how many samples of audio to produce based on the amount of audio + // currently buffered, so we adjust the reported count to be some number of frames in the future + // to counteract lag; idea shamelessly stolen from mm recomp + if (offsetBytes) { + if (count > offsetBytes) { + count -= offsetBytes; + } else { + count = 0; + } + } + + return count; } s32 audioGetSamplesBuffered(void) { - return audioGetBytesBuffered() / 4; + return audioGetBytesBuffered() / (2 * sizeof(s16)); } -void audioSetNextBuffer(const s16 *buf, u32 len) +void audioSubmitBuffer(const s16 *buf, u32 size) { - nextBuf = buf; - nextSize = len; -} - -void audioEndFrame(void) -{ - if (nextBuf && nextSize) { + if (buf && size) { if (audioGetSamplesBuffered() < queueLimit) { - SDL_QueueAudio(dev, nextBuf, nextSize); + SDL_QueueAudio(dev, buf, size); } - nextBuf = NULL; - nextSize = 0; } } PD_CONSTRUCTOR static void audioConfigInit(void) { configRegisterInt("Audio.BufferSize", &bufferSize, 0, 1 * 1024 * 1024); + configRegisterFloat("Audio.OffsetFrames", &offsetFrames, 0.f, 5.f); configRegisterInt("Audio.QueueLimit", &queueLimit, 0, 1 * 1024 * 1024); } diff --git a/port/src/libultra.c b/port/src/libultra.c index 74edd9782..3d749d211 100644 --- a/port/src/libultra.c +++ b/port/src/libultra.c @@ -166,7 +166,7 @@ u32 osAiGetLength(void) s32 osAiSetNextBuffer(void *bufPtr, u32 size) { - audioSetNextBuffer(bufPtr, size); + audioSubmitBuffer(bufPtr, size); return 0; } diff --git a/port/src/pdmain.c b/port/src/pdmain.c index 2cd9baffb..7faa21e31 100644 --- a/port/src/pdmain.c +++ b/port/src/pdmain.c @@ -501,7 +501,7 @@ void mainLoop(void) schedEndFrame(&g_Sched); } if (g_TickExtraSleep) { - sysSleep(EXTRA_SLEEP_TIME); + sysFrameLimiterSleep(EXTRA_SLEEP_TIME); } } diff --git a/port/src/pdsched.c b/port/src/pdsched.c index 1f8800565..37ecdc48f 100644 --- a/port/src/pdsched.c +++ b/port/src/pdsched.c @@ -244,13 +244,8 @@ void schedStartFrame(OSSched *sc) void schedAudioFrame(OSSched *sc) { - s32 i; - if (!g_SndDisabled) { - for (i = 0; i < g_Vars.diffframe60; i++) { - amgrFrame(); - audioEndFrame(); - } + amgrUpdateFrameCounter(g_Vars.thisframestart240); } } @@ -272,18 +267,6 @@ void schedEndFrame(OSSched *sc) { sc->frameCount++; -#if PAL - if (!g_Resetting && (sc->frameCount & 1)) { - // osStopTimer(&g_SchedRspTimer); - // osSetTimer(&g_SchedRspTimer, 280000, 0, amgrGetFrameMesgQueue(), &g_SchedRspMsg); - } -#else - if (!g_Resetting && ((sc->frameCount & 1) || IS4MB())) { - // osStopTimer(&g_SchedRspTimer); - // osSetTimer(&g_SchedRspTimer, 280000, 0, amgrGetFrameMesgQueue(), &g_SchedRspMsg); - } -#endif - if (!g_Resetting) { viHandleRetrace(); } diff --git a/port/src/system.c b/port/src/system.c index 16b689c47..8e06f8ed8 100644 --- a/port/src/system.c +++ b/port/src/system.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include "platform.h" @@ -32,8 +33,6 @@ __attribute__((dllexport)) u32 AmdPowerXpressRequestHighPerformance = 1; #else -#include - // figure out how to yield #if defined(PLATFORM_X86) || defined(PLATFORM_X86_64) // this should work even if the code is not built with SSE enabled, at least on gcc and clang, @@ -293,7 +292,7 @@ void sysMemFree(void *ptr) free(ptr); } -void sysSleep(const s64 hns) +void sysFrameLimiterSleep(const s64 hns) { #ifdef PLATFORM_WIN32 static LARGE_INTEGER li; @@ -306,6 +305,12 @@ void sysSleep(const s64 hns) #endif } +void sysSleep(const s64 us) +{ + const struct timespec spec = { 0, us * 1000 }; + nanosleep(&spec, NULL); +} + void sysCpuRelax(void) { DO_YIELD(); diff --git a/port/src/thread.c b/port/src/thread.c new file mode 100644 index 000000000..232c104ac --- /dev/null +++ b/port/src/thread.c @@ -0,0 +1,27 @@ +#include "thread.h" + +#ifndef PLATFORM_USE_PTHREAD +#error "No available thread backend." +#endif + +#include + +s32 sysThreadCreate(systhread *thread, systhreadfn func, void *arg) +{ + return pthread_create(thread, NULL, func, arg); +} + +s32 sysThreadJoin(systhread *thread, void **result) +{ + return pthread_join(*thread, result); +} + +void sysMutexLock(sysmutex *mtx) +{ + pthread_mutex_lock(mtx); +} + +void sysMutexUnlock(sysmutex *mtx) +{ + pthread_mutex_unlock(mtx); +} diff --git a/port/src/video.c b/port/src/video.c index 181af3ab5..901dcee79 100644 --- a/port/src/video.c +++ b/port/src/video.c @@ -114,7 +114,8 @@ void videoEndFrame(void) if (endTime >= fpsTime) { char tmp[128]; - snprintf(tmp, sizeof(tmp), "fps %3u frt %lf frm %u", framesPerSec, endTime - startTime, frames); + extern u32 g_AmgrFrame; + snprintf(tmp, sizeof(tmp), "fps %3u frt %lf frm %u afrm %u", framesPerSec, endTime - startTime, frames, g_AmgrFrame / 4); wmAPI->set_window_title(tmp); framesPerSec = 0; fpsTime = endTime + 1.0; diff --git a/src/game/chraicommands.c b/src/game/chraicommands.c index 9a5517348..b25d433ed 100644 --- a/src/game/chraicommands.c +++ b/src/game/chraicommands.c @@ -9840,20 +9840,14 @@ bool aiIfMusicEventQueueIsEmpty(void) { f32 value = (u64)osGetCount() * 64 / 3000; -#ifdef PLATFORM_N64 // will hang forever until the audio thread wakes it up if (g_MusicEventQueueLength) { -#else // HACK: will wait 1 frame and get on with it - static bool waited = false; - if (g_MusicEventQueueLength && !waited) { - waited = true; +#ifndef PLATFORM_N64 + musicTickEvents(); #endif g_Vars.aioffset += 4; } else { u8 *cmd = g_Vars.ailist + g_Vars.aioffset; g_Vars.aioffset = chraiGoToLabel(g_Vars.ailist, g_Vars.aioffset, cmd[3]); -#ifndef PLATFORM_N64 - waited = false; -#endif } return false; diff --git a/src/game/timing.c b/src/game/timing.c index 747c7ed24..7bf96eb75 100644 --- a/src/game/timing.c +++ b/src/game/timing.c @@ -47,7 +47,7 @@ void frametimeCalculate(void) #ifndef PLATFORM_N64 if (g_TickExtraSleep) { - sysSleep(EXTRA_SLEEP_TIME); + sysFrameLimiterSleep(EXTRA_SLEEP_TIME); } #endif } while (g_Vars.mininc60 && diffframe60 < g_Vars.mininc60); diff --git a/src/include/lib/audiomgr.h b/src/include/lib/audiomgr.h index ec1d6ba0a..c289776ff 100644 --- a/src/include/lib/audiomgr.h +++ b/src/include/lib/audiomgr.h @@ -17,7 +17,12 @@ OSMesgQueue *amgrGetFrameMesgQueue(void); void amgrStopThread(void); #ifndef PLATFORM_N64 -void amgrFrame(void); +void amgrLock(void); +void amgrUnlock(void); +void amgrUpdateFrameCounter(u32 framecount); +#else +#define amgrLock() do {} while(0) +#define amgrUnlock() do {} while(0) #endif #endif diff --git a/src/include/platform.h b/src/include/platform.h index 30615f750..5fc0ceca1 100644 --- a/src/include/platform.h +++ b/src/include/platform.h @@ -34,6 +34,9 @@ #error "64-bit platforms are currently not supported." #endif +// threading backend +#define PLATFORM_USE_PTHREAD 1 + // detect endianness #if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ diff --git a/src/lib/audiomgr.c b/src/lib/audiomgr.c index 7791798de..69e1d6fb4 100644 --- a/src/lib/audiomgr.c +++ b/src/lib/audiomgr.c @@ -10,6 +10,13 @@ #include "lib/libc/ll.h" #include "data.h" #include "types.h" +#ifndef PLATFORM_N64 +#include "lib/audiomgr.h" +#include "thread.h" +#include "audio.h" +#include "system.h" +#define AMGR_THREAD_SLEEP_US 2000 +#endif u32 var80091560; u32 var80091564; @@ -43,6 +50,14 @@ void *g_AudioSp; u32 var8005cf90 = 0x00000000; u8 var8005cf94 = 1; +#ifndef PLATFORM_N64 +systhread g_AmgrThread; +sysmutex g_AmgrMutex = SYSMUTEX_STATIC_INIT; +u32 g_AmgrFrame; +u32 g_AmgrFrameTarget; +void *amgrThread(void *arg); +#endif + void amgrHandleDoneMsg(AudioInfo *info); void amgrHandleFrameMsg(AudioInfo *info, AudioInfo *previnfo); void amgrMain(void *arg); @@ -155,6 +170,9 @@ void amgrStartThread(void) { osStartThread(&g_AudioManager.thread); g_AudioIsThreadRunning = true; +#ifndef PLATFORM_N64 + sysThreadCreate(&g_AmgrThread, &amgrThread, NULL); +#endif } OSMesgQueue *amgrGetFrameMesgQueue(void) @@ -171,6 +189,12 @@ void amgrStopThread(void) { if (g_AudioIsThreadRunning) { osStopThread(&g_AudioManager.thread); +#ifndef PLATFORM_N64 + amgrLock(); + g_AudioIsThreadRunning = false; + amgrUnlock(); + sysThreadJoin(&g_AmgrThread, NULL); +#endif } } @@ -321,11 +345,14 @@ void amgrHandleDoneMsg(AudioInfo *info) } #ifndef PLATFORM_N64 + void amgrFrame(void) { static AudioInfo *previnfo = NULL; static s32 count = 0; + amgrLock(); + var80091588 = osGetTime(); AudioInfo *info = g_AudioManager.audioInfo[g_AdmaCurFrame % 3]; @@ -363,6 +390,8 @@ void amgrFrame(void) count++; + amgrUnlock(); + var80091590 = osGetTime(); var80091570 = var80091590 - var80091588; @@ -377,4 +406,49 @@ void amgrFrame(void) var80091568 = var80091590 - var80091588; } } + +void amgrLock(void) +{ + sysMutexLock(&g_AmgrMutex); +} + +void amgrUnlock(void) +{ + sysMutexUnlock(&g_AmgrMutex); +} + +void amgrUpdateFrameCounter(u32 newframes) +{ + amgrLock(); + g_AmgrFrameTarget = newframes; + amgrUnlock(); +} + +void *amgrThread(void *arg) +{ + const f64 frametime = 1000000.0 / (PAL ? 50.0 : 60.0); + bool running = g_AudioIsThreadRunning; + f64 nexttick = sysGetMicroseconds(); + f64 tick; + + while (running) + { + tick = sysGetMicroseconds() + 0.01; + + while (nexttick < tick) { + amgrFrame(); + g_AmgrFrame++; + nexttick += frametime; + } + + sysSleep(AMGR_THREAD_SLEEP_US); + + amgrLock(); + running = g_AudioIsThreadRunning; + amgrUnlock(); + } + + return NULL; +} + #endif From ada20c526acd47a40e0f5c5acf141ae321f2c6a1 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sat, 18 May 2024 19:00:40 +0200 Subject: [PATCH 64/68] port: clean up previous commit --- port/src/pdsched.c | 8 -------- port/src/video.c | 3 +-- src/include/lib/audiomgr.h | 1 - src/lib/audiomgr.c | 7 ------- 4 files changed, 1 insertion(+), 18 deletions(-) diff --git a/port/src/pdsched.c b/port/src/pdsched.c index 37ecdc48f..a8493d769 100644 --- a/port/src/pdsched.c +++ b/port/src/pdsched.c @@ -242,13 +242,6 @@ void schedStartFrame(OSSched *sc) videoStartFrame(); } -void schedAudioFrame(OSSched *sc) -{ - if (!g_SndDisabled) { - amgrUpdateFrameCounter(g_Vars.thisframestart240); - } -} - /** * Handle a retrace (vsync) event. * @@ -278,7 +271,6 @@ void schedEndFrame(OSSched *sc) joy00014238(); sndHandleRetrace(); - schedAudioFrame(sc); schedRenderCrashPeriodically(sc->frameCount); videoEndFrame(); diff --git a/port/src/video.c b/port/src/video.c index 901dcee79..181af3ab5 100644 --- a/port/src/video.c +++ b/port/src/video.c @@ -114,8 +114,7 @@ void videoEndFrame(void) if (endTime >= fpsTime) { char tmp[128]; - extern u32 g_AmgrFrame; - snprintf(tmp, sizeof(tmp), "fps %3u frt %lf frm %u afrm %u", framesPerSec, endTime - startTime, frames, g_AmgrFrame / 4); + snprintf(tmp, sizeof(tmp), "fps %3u frt %lf frm %u", framesPerSec, endTime - startTime, frames); wmAPI->set_window_title(tmp); framesPerSec = 0; fpsTime = endTime + 1.0; diff --git a/src/include/lib/audiomgr.h b/src/include/lib/audiomgr.h index c289776ff..4e6f777bb 100644 --- a/src/include/lib/audiomgr.h +++ b/src/include/lib/audiomgr.h @@ -19,7 +19,6 @@ void amgrStopThread(void); #ifndef PLATFORM_N64 void amgrLock(void); void amgrUnlock(void); -void amgrUpdateFrameCounter(u32 framecount); #else #define amgrLock() do {} while(0) #define amgrUnlock() do {} while(0) diff --git a/src/lib/audiomgr.c b/src/lib/audiomgr.c index 69e1d6fb4..6d9250a01 100644 --- a/src/lib/audiomgr.c +++ b/src/lib/audiomgr.c @@ -417,13 +417,6 @@ void amgrUnlock(void) sysMutexUnlock(&g_AmgrMutex); } -void amgrUpdateFrameCounter(u32 newframes) -{ - amgrLock(); - g_AmgrFrameTarget = newframes; - amgrUnlock(); -} - void *amgrThread(void *arg) { const f64 frametime = 1000000.0 / (PAL ? 50.0 : 60.0); From bc5911bfba22004ab3ab13133ca845334faaa7d4 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sat, 18 May 2024 19:05:47 +0200 Subject: [PATCH 65/68] port: formatting --- src/lib/audiomgr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib/audiomgr.c b/src/lib/audiomgr.c index 6d9250a01..2f4d80021 100644 --- a/src/lib/audiomgr.c +++ b/src/lib/audiomgr.c @@ -424,8 +424,7 @@ void *amgrThread(void *arg) f64 nexttick = sysGetMicroseconds(); f64 tick; - while (running) - { + while (running) { tick = sysGetMicroseconds() + 0.01; while (nexttick < tick) { From 08b4d780b729ad544cb7f48dac071fc419aa4e86 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sat, 18 May 2024 19:18:27 +0200 Subject: [PATCH 66/68] port: temporary fix for the UI back button --- src/game/menu.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/game/menu.c b/src/game/menu.c index ffa389088..f45e97cc2 100644 --- a/src/game/menu.c +++ b/src/game/menu.c @@ -4746,8 +4746,9 @@ void menuProcessInput(void) inputs.select = 1; } - // don't back out on weapon back when using mouse because it's likely bound to wheel - if (!g_MenuMouseControl && (buttonsnow & BUTTON_WPNBACK)) { + // HACK: don't back out on weapon back when it's bound to wheel + const bool wheel = inputKeyPressed(VK_MOUSE_WHEEL_UP) || inputKeyPressed(VK_MOUSE_WHEEL_DN); + if ((buttonsnow & BUTTON_WPNBACK) && !wheel) { inputs.back = 1; } #endif @@ -4781,6 +4782,7 @@ void menuProcessInput(void) if ((sticky < 0 ? -sticky : sticky) < (thissticky < 0 ? -thissticky : thissticky)) { sticky = thissticky; } + #ifndef PLATFORM_N64 if ((sticky < 0 ? -sticky : sticky) < (thisrsticky < 0 ? -thisrsticky : thisrsticky)) { sticky = thisrsticky; From dce96a4a3dc34a0597fa48127f043e248a491330 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sat, 18 May 2024 19:32:34 +0200 Subject: [PATCH 67/68] port: add separate extra buttons for accept/cancel --- port/include/input.h | 4 ++-- port/src/input.c | 6 ++++-- port/src/optionsmenu.c | 4 ++++ src/game/menu.c | 8 +++----- src/include/constants.h | 6 ++++++ 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/port/include/input.h b/port/include/input.h index fcb9d962c..d09e1dbdf 100644 --- a/port/include/input.h +++ b/port/include/input.h @@ -66,8 +66,8 @@ enum contkey { CK_STICK_XPOS, CK_STICK_YNEG, CK_STICK_YPOS, - CK_0010, - CK_0020, + CK_ACCEPT, + CK_CANCEL, CK_0040, CK_0080, CK_0100, diff --git a/port/src/input.c b/port/src/input.c index 69e28508f..bf0ab413e 100644 --- a/port/src/input.c +++ b/port/src/input.c @@ -103,8 +103,8 @@ static const char *ckNames[CK_TOTAL_COUNT] = { "STICK_XPOS", "STICK_YNEG", "STICK_YPOS", - "CK_0010", - "CK_0020", + "ACCEPT_BUTTON", + "CANCEL_BUTTON", "CK_0040", "CK_0080", "CK_0100", @@ -211,6 +211,8 @@ void inputSetDefaultKeyBinds(s32 cidx, s32 n64mode) { CK_C_U, SDL_CONTROLLER_BUTTON_DPAD_UP }, { CK_C_R, SDL_CONTROLLER_BUTTON_DPAD_RIGHT }, { CK_C_L, SDL_CONTROLLER_BUTTON_DPAD_LEFT }, + { CK_ACCEPT, SDL_CONTROLLER_BUTTON_A }, + { CK_CANCEL, SDL_CONTROLLER_BUTTON_B }, { CK_8000, SDL_CONTROLLER_BUTTON_LEFTSTICK }, }; diff --git a/port/src/optionsmenu.c b/port/src/optionsmenu.c index 8d042de1b..92908711d 100644 --- a/port/src/optionsmenu.c +++ b/port/src/optionsmenu.c @@ -1337,6 +1337,8 @@ static const struct menubind menuBinds[] = { { CK_8000, "Cycle Crouch [+]\n", "N64 Ext 8000\n" }, { CK_4000, "Half Crouch [+]\n", "N64 Ext 4000\n" }, { CK_2000, "Full Crouch [+]\n", "N64 Ext 2000\n" }, + { CK_ACCEPT, "UI Accept [+]\n", "EXT UI Accept\n" }, + { CK_CANCEL, "UI Cancel [+]\n", "EXT UI Cancel\n" }, }; static const char *menutextBind(struct menuitem *item); @@ -1374,6 +1376,8 @@ struct menuitem g_ExtendedBindsMenuItems[] = { DEFINE_MENU_BIND(), DEFINE_MENU_BIND(), DEFINE_MENU_BIND(), + DEFINE_MENU_BIND(), + DEFINE_MENU_BIND(), { MENUITEMTYPE_SEPARATOR, 0, diff --git a/src/game/menu.c b/src/game/menu.c index f45e97cc2..db2a30001 100644 --- a/src/game/menu.c +++ b/src/game/menu.c @@ -4741,14 +4741,12 @@ void menuProcessInput(void) } #ifndef PLATFORM_N64 - // this seems sensible to achieve 1964 parity - if (buttonsnow & BUTTON_RADIAL) { + // separate buttons for UI accept/cancel + if (buttonsnow & BUTTON_UI_ACCEPT) { inputs.select = 1; } - // HACK: don't back out on weapon back when it's bound to wheel - const bool wheel = inputKeyPressed(VK_MOUSE_WHEEL_UP) || inputKeyPressed(VK_MOUSE_WHEEL_DN); - if ((buttonsnow & BUTTON_WPNBACK) && !wheel) { + if (buttonsnow & BUTTON_UI_CANCEL) { inputs.back = 1; } #endif diff --git a/src/include/constants.h b/src/include/constants.h index f6fea0f11..09152e169 100644 --- a/src/include/constants.h +++ b/src/include/constants.h @@ -4708,6 +4708,9 @@ enum weaponnum { #define BUTTON_ACCEPT BUTTON_ACCEPT_WPNFORWARD #define BUTTON_WPNFORWARD BUTTON_ACCEPT_WPNFORWARD +#define BUTTON_UI_ACCEPT BUTTON_ACCEPT_WPNFORWARD +#define BUTTON_UI_CANCEL BUTTON_CANCEL_USE + #else // xbla behavior @@ -4727,6 +4730,9 @@ enum weaponnum { #define BUTTON_HALF_CROUCH CONT_4000 #define BUTTON_FULL_CROUCH CONT_2000 +#define BUTTON_UI_ACCEPT CONT_0010 +#define BUTTON_UI_CANCEL CONT_0020 + #define MOUSEAIM_CLASSIC 0 // crosshair moves around the screen in aim mode #define MOUSEAIM_LOCKED 1 // crosshair locked to the center of the screen in aim mode From de3b8ff54876a2cc7fc7efde90ad68b67012f2d1 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sun, 19 May 2024 19:44:34 +0200 Subject: [PATCH 68/68] port: revert multithreaded audio experiments until I can figure out how to fix all the funny concurrency issues that cropped up --- Makefile.port | 4 +-- port/fast3d/gfx_sdl2.cpp | 2 +- port/include/audio.h | 3 +- port/include/system.h | 6 +--- port/include/thread.h | 27 ---------------- port/src/audio.c | 40 +++++++++-------------- port/src/libultra.c | 2 +- port/src/pdmain.c | 2 +- port/src/pdsched.c | 25 +++++++++++++++ port/src/system.c | 11 ++----- port/src/thread.c | 27 ---------------- src/game/chraicommands.c | 10 ++++-- src/game/timing.c | 2 +- src/include/lib/audiomgr.h | 6 +--- src/include/platform.h | 3 -- src/lib/audiomgr.c | 66 -------------------------------------- 16 files changed, 62 insertions(+), 174 deletions(-) delete mode 100644 port/include/thread.h delete mode 100644 port/src/thread.c diff --git a/Makefile.port b/Makefile.port index b3e3b953e..650f02474 100644 --- a/Makefile.port +++ b/Makefile.port @@ -150,7 +150,7 @@ B_DIR := build/$(ROMID)-port G_DIR := src/generated/$(ROMID) ifneq (,$(findstring windows,$(TARGET_PLATFORM))) - TARGET_CFLAGS := $(shell pkg-config sdl2 --cflags-only-I) -pthread + TARGET_CFLAGS := $(shell pkg-config sdl2 --cflags-only-I) TARGET_LDFLAGS := $(shell pkg-config sdl2 --libs) -lz -lopengl32 -ldbghelp # on windows/mingw we need this to be built with a 32-bit compiler so it finds the correct libs TOOLCHAIN ?= i686-w64-mingw32- @@ -161,7 +161,7 @@ ifneq (,$(findstring windows,$(TARGET_PLATFORM))) TARGET_LDFLAGS += -lstdc++ endif else # assume *nix - TARGET_CFLAGS := $(shell pkg-config sdl2 --cflags-only-I) -pthread + TARGET_CFLAGS := $(shell pkg-config sdl2 --cflags-only-I) TARGET_LDFLAGS := $(shell pkg-config sdl2 --libs) -lGL -lz -ldl ifneq (,$(findstring arm,$(TARGET_PLATFORM))$(findstring aarch,$(TARGET_PLATFORM))) # linux on arm or aarch64 diff --git a/port/fast3d/gfx_sdl2.cpp b/port/fast3d/gfx_sdl2.cpp index 537b4c52d..181038d26 100644 --- a/port/fast3d/gfx_sdl2.cpp +++ b/port/fast3d/gfx_sdl2.cpp @@ -261,7 +261,7 @@ static inline void sync_framerate_with_timer(void) { // We want to exit a bit early, so we can busy-wait the rest to never miss the deadline left -= 15000UL; if (left > 0) { - sysFrameLimiterSleep(left); + sysSleep(left); } do { diff --git a/port/include/audio.h b/port/include/audio.h index 8aa5a453c..32fc16cbe 100644 --- a/port/include/audio.h +++ b/port/include/audio.h @@ -6,6 +6,7 @@ s32 audioInit(void); s32 audioGetBytesBuffered(void); s32 audioGetSamplesBuffered(void); -void audioSubmitBuffer(const s16 *buf, u32 size); +void audioSetNextBuffer(const s16 *buf, u32 len); +void audioEndFrame(void); #endif diff --git a/port/include/system.h b/port/include/system.h index b65690b47..84d568382 100644 --- a/port/include/system.h +++ b/port/include/system.h @@ -35,11 +35,7 @@ void *sysMemZeroAlloc(const u32 size); void sysMemFree(void *ptr); // hns is specified in 100ns units -// do not use sysFrameLimiterSleep on any thread other than the main one -void sysFrameLimiterSleep(const s64 hns); - -// us is specified in microseconds -void sysSleep(const s64 us); +void sysSleep(const s64 hns); // yield CPU if supported (e.g. during a busy loop) void sysCpuRelax(void); diff --git a/port/include/thread.h b/port/include/thread.h deleted file mode 100644 index 7a9f6383f..000000000 --- a/port/include/thread.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef _IN_THREAD_H -#define _IN_THREAD_H - -#include -#include "platform.h" - -// TODO: backends -#ifndef PLATFORM_USE_PTHREAD -#error "No available thread backend." -#endif - -#include - -#define SYSMUTEX_STATIC_INIT PTHREAD_MUTEX_INITIALIZER - -typedef pthread_t systhread; -typedef pthread_mutex_t sysmutex; - -typedef void *(*systhreadfn)(void *); - -s32 sysThreadCreate(systhread *thread, systhreadfn func, void *arg); -s32 sysThreadJoin(systhread *thread, void **result); - -void sysMutexLock(sysmutex *mtx); -void sysMutexUnlock(sysmutex *mtx); - -#endif // _IN_THREAD_H diff --git a/port/src/audio.c b/port/src/audio.c index f0f172de5..c66cf5912 100644 --- a/port/src/audio.c +++ b/port/src/audio.c @@ -7,13 +7,12 @@ #include "system.h" static SDL_AudioDeviceID dev; +static const s16 *nextBuf; +static u32 nextSize = 0; static s32 bufferSize = 512; static s32 queueLimit = 8192; -static f32 offsetFrames = 0.5f; -static u32 offsetBytes; - s32 audioInit(void) { if (SDL_InitSubSystem(SDL_INIT_AUDIO) != 0) { @@ -29,8 +28,7 @@ s32 audioInit(void) want.samples = bufferSize; want.callback = NULL; - const f32 spf = (f32)want.freq / (PAL ? 50.f : 60.f); - offsetBytes = offsetFrames * spf * (f32)sizeof(int16_t); + nextBuf = NULL; dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0); if (dev == 0) { @@ -45,39 +43,33 @@ s32 audioInit(void) s32 audioGetBytesBuffered(void) { - u32 count = SDL_GetQueuedAudioSize(dev); - - // pd's audio code decides how many samples of audio to produce based on the amount of audio - // currently buffered, so we adjust the reported count to be some number of frames in the future - // to counteract lag; idea shamelessly stolen from mm recomp - if (offsetBytes) { - if (count > offsetBytes) { - count -= offsetBytes; - } else { - count = 0; - } - } - - return count; + return SDL_GetQueuedAudioSize(dev); } s32 audioGetSamplesBuffered(void) { - return audioGetBytesBuffered() / (2 * sizeof(s16)); + return audioGetBytesBuffered() / 4; } -void audioSubmitBuffer(const s16 *buf, u32 size) +void audioSetNextBuffer(const s16 *buf, u32 len) { - if (buf && size) { + nextBuf = buf; + nextSize = len; +} + +void audioEndFrame(void) +{ + if (nextBuf && nextSize) { if (audioGetSamplesBuffered() < queueLimit) { - SDL_QueueAudio(dev, buf, size); + SDL_QueueAudio(dev, nextBuf, nextSize); } + nextBuf = NULL; + nextSize = 0; } } PD_CONSTRUCTOR static void audioConfigInit(void) { configRegisterInt("Audio.BufferSize", &bufferSize, 0, 1 * 1024 * 1024); - configRegisterFloat("Audio.OffsetFrames", &offsetFrames, 0.f, 5.f); configRegisterInt("Audio.QueueLimit", &queueLimit, 0, 1 * 1024 * 1024); } diff --git a/port/src/libultra.c b/port/src/libultra.c index 3d749d211..74edd9782 100644 --- a/port/src/libultra.c +++ b/port/src/libultra.c @@ -166,7 +166,7 @@ u32 osAiGetLength(void) s32 osAiSetNextBuffer(void *bufPtr, u32 size) { - audioSubmitBuffer(bufPtr, size); + audioSetNextBuffer(bufPtr, size); return 0; } diff --git a/port/src/pdmain.c b/port/src/pdmain.c index 7faa21e31..2cd9baffb 100644 --- a/port/src/pdmain.c +++ b/port/src/pdmain.c @@ -501,7 +501,7 @@ void mainLoop(void) schedEndFrame(&g_Sched); } if (g_TickExtraSleep) { - sysFrameLimiterSleep(EXTRA_SLEEP_TIME); + sysSleep(EXTRA_SLEEP_TIME); } } diff --git a/port/src/pdsched.c b/port/src/pdsched.c index a8493d769..1f8800565 100644 --- a/port/src/pdsched.c +++ b/port/src/pdsched.c @@ -242,6 +242,18 @@ void schedStartFrame(OSSched *sc) videoStartFrame(); } +void schedAudioFrame(OSSched *sc) +{ + s32 i; + + if (!g_SndDisabled) { + for (i = 0; i < g_Vars.diffframe60; i++) { + amgrFrame(); + audioEndFrame(); + } + } +} + /** * Handle a retrace (vsync) event. * @@ -260,6 +272,18 @@ void schedEndFrame(OSSched *sc) { sc->frameCount++; +#if PAL + if (!g_Resetting && (sc->frameCount & 1)) { + // osStopTimer(&g_SchedRspTimer); + // osSetTimer(&g_SchedRspTimer, 280000, 0, amgrGetFrameMesgQueue(), &g_SchedRspMsg); + } +#else + if (!g_Resetting && ((sc->frameCount & 1) || IS4MB())) { + // osStopTimer(&g_SchedRspTimer); + // osSetTimer(&g_SchedRspTimer, 280000, 0, amgrGetFrameMesgQueue(), &g_SchedRspMsg); + } +#endif + if (!g_Resetting) { viHandleRetrace(); } @@ -271,6 +295,7 @@ void schedEndFrame(OSSched *sc) joy00014238(); sndHandleRetrace(); + schedAudioFrame(sc); schedRenderCrashPeriodically(sc->frameCount); videoEndFrame(); diff --git a/port/src/system.c b/port/src/system.c index 8e06f8ed8..16b689c47 100644 --- a/port/src/system.c +++ b/port/src/system.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include "platform.h" @@ -33,6 +32,8 @@ __attribute__((dllexport)) u32 AmdPowerXpressRequestHighPerformance = 1; #else +#include + // figure out how to yield #if defined(PLATFORM_X86) || defined(PLATFORM_X86_64) // this should work even if the code is not built with SSE enabled, at least on gcc and clang, @@ -292,7 +293,7 @@ void sysMemFree(void *ptr) free(ptr); } -void sysFrameLimiterSleep(const s64 hns) +void sysSleep(const s64 hns) { #ifdef PLATFORM_WIN32 static LARGE_INTEGER li; @@ -305,12 +306,6 @@ void sysFrameLimiterSleep(const s64 hns) #endif } -void sysSleep(const s64 us) -{ - const struct timespec spec = { 0, us * 1000 }; - nanosleep(&spec, NULL); -} - void sysCpuRelax(void) { DO_YIELD(); diff --git a/port/src/thread.c b/port/src/thread.c deleted file mode 100644 index 232c104ac..000000000 --- a/port/src/thread.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "thread.h" - -#ifndef PLATFORM_USE_PTHREAD -#error "No available thread backend." -#endif - -#include - -s32 sysThreadCreate(systhread *thread, systhreadfn func, void *arg) -{ - return pthread_create(thread, NULL, func, arg); -} - -s32 sysThreadJoin(systhread *thread, void **result) -{ - return pthread_join(*thread, result); -} - -void sysMutexLock(sysmutex *mtx) -{ - pthread_mutex_lock(mtx); -} - -void sysMutexUnlock(sysmutex *mtx) -{ - pthread_mutex_unlock(mtx); -} diff --git a/src/game/chraicommands.c b/src/game/chraicommands.c index b25d433ed..9a5517348 100644 --- a/src/game/chraicommands.c +++ b/src/game/chraicommands.c @@ -9840,14 +9840,20 @@ bool aiIfMusicEventQueueIsEmpty(void) { f32 value = (u64)osGetCount() * 64 / 3000; +#ifdef PLATFORM_N64 // will hang forever until the audio thread wakes it up if (g_MusicEventQueueLength) { -#ifndef PLATFORM_N64 - musicTickEvents(); +#else // HACK: will wait 1 frame and get on with it + static bool waited = false; + if (g_MusicEventQueueLength && !waited) { + waited = true; #endif g_Vars.aioffset += 4; } else { u8 *cmd = g_Vars.ailist + g_Vars.aioffset; g_Vars.aioffset = chraiGoToLabel(g_Vars.ailist, g_Vars.aioffset, cmd[3]); +#ifndef PLATFORM_N64 + waited = false; +#endif } return false; diff --git a/src/game/timing.c b/src/game/timing.c index 7bf96eb75..747c7ed24 100644 --- a/src/game/timing.c +++ b/src/game/timing.c @@ -47,7 +47,7 @@ void frametimeCalculate(void) #ifndef PLATFORM_N64 if (g_TickExtraSleep) { - sysFrameLimiterSleep(EXTRA_SLEEP_TIME); + sysSleep(EXTRA_SLEEP_TIME); } #endif } while (g_Vars.mininc60 && diffframe60 < g_Vars.mininc60); diff --git a/src/include/lib/audiomgr.h b/src/include/lib/audiomgr.h index 4e6f777bb..ec1d6ba0a 100644 --- a/src/include/lib/audiomgr.h +++ b/src/include/lib/audiomgr.h @@ -17,11 +17,7 @@ OSMesgQueue *amgrGetFrameMesgQueue(void); void amgrStopThread(void); #ifndef PLATFORM_N64 -void amgrLock(void); -void amgrUnlock(void); -#else -#define amgrLock() do {} while(0) -#define amgrUnlock() do {} while(0) +void amgrFrame(void); #endif #endif diff --git a/src/include/platform.h b/src/include/platform.h index 5fc0ceca1..30615f750 100644 --- a/src/include/platform.h +++ b/src/include/platform.h @@ -34,9 +34,6 @@ #error "64-bit platforms are currently not supported." #endif -// threading backend -#define PLATFORM_USE_PTHREAD 1 - // detect endianness #if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ diff --git a/src/lib/audiomgr.c b/src/lib/audiomgr.c index 2f4d80021..7791798de 100644 --- a/src/lib/audiomgr.c +++ b/src/lib/audiomgr.c @@ -10,13 +10,6 @@ #include "lib/libc/ll.h" #include "data.h" #include "types.h" -#ifndef PLATFORM_N64 -#include "lib/audiomgr.h" -#include "thread.h" -#include "audio.h" -#include "system.h" -#define AMGR_THREAD_SLEEP_US 2000 -#endif u32 var80091560; u32 var80091564; @@ -50,14 +43,6 @@ void *g_AudioSp; u32 var8005cf90 = 0x00000000; u8 var8005cf94 = 1; -#ifndef PLATFORM_N64 -systhread g_AmgrThread; -sysmutex g_AmgrMutex = SYSMUTEX_STATIC_INIT; -u32 g_AmgrFrame; -u32 g_AmgrFrameTarget; -void *amgrThread(void *arg); -#endif - void amgrHandleDoneMsg(AudioInfo *info); void amgrHandleFrameMsg(AudioInfo *info, AudioInfo *previnfo); void amgrMain(void *arg); @@ -170,9 +155,6 @@ void amgrStartThread(void) { osStartThread(&g_AudioManager.thread); g_AudioIsThreadRunning = true; -#ifndef PLATFORM_N64 - sysThreadCreate(&g_AmgrThread, &amgrThread, NULL); -#endif } OSMesgQueue *amgrGetFrameMesgQueue(void) @@ -189,12 +171,6 @@ void amgrStopThread(void) { if (g_AudioIsThreadRunning) { osStopThread(&g_AudioManager.thread); -#ifndef PLATFORM_N64 - amgrLock(); - g_AudioIsThreadRunning = false; - amgrUnlock(); - sysThreadJoin(&g_AmgrThread, NULL); -#endif } } @@ -345,14 +321,11 @@ void amgrHandleDoneMsg(AudioInfo *info) } #ifndef PLATFORM_N64 - void amgrFrame(void) { static AudioInfo *previnfo = NULL; static s32 count = 0; - amgrLock(); - var80091588 = osGetTime(); AudioInfo *info = g_AudioManager.audioInfo[g_AdmaCurFrame % 3]; @@ -390,8 +363,6 @@ void amgrFrame(void) count++; - amgrUnlock(); - var80091590 = osGetTime(); var80091570 = var80091590 - var80091588; @@ -406,41 +377,4 @@ void amgrFrame(void) var80091568 = var80091590 - var80091588; } } - -void amgrLock(void) -{ - sysMutexLock(&g_AmgrMutex); -} - -void amgrUnlock(void) -{ - sysMutexUnlock(&g_AmgrMutex); -} - -void *amgrThread(void *arg) -{ - const f64 frametime = 1000000.0 / (PAL ? 50.0 : 60.0); - bool running = g_AudioIsThreadRunning; - f64 nexttick = sysGetMicroseconds(); - f64 tick; - - while (running) { - tick = sysGetMicroseconds() + 0.01; - - while (nexttick < tick) { - amgrFrame(); - g_AmgrFrame++; - nexttick += frametime; - } - - sysSleep(AMGR_THREAD_SLEEP_US); - - amgrLock(); - running = g_AudioIsThreadRunning; - amgrUnlock(); - } - - return NULL; -} - #endif