mirror of
https://github.com/perfect-dark-pc-port/perfect_dark.git
synced 2026-10-24 00:02:43 +02:00
Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-debugger
This commit is contained in:
commit
aa6ac4b5cc
16 files changed
+124
-39
No files matched your search
+61
-16
@@ -1,19 +1,31 @@
|
||||
#include <stdio.h>
|
||||
#include <SDL.h>
|
||||
#ifdef __MINGW32__
|
||||
// mingw has its nanosleep implementation in pthread.h for some reson
|
||||
#include <pthread.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#include "platform.h"
|
||||
#include "system.h"
|
||||
|
||||
#include "gfx_window_manager_api.h"
|
||||
#include "gfx_screen_config.h"
|
||||
|
||||
#define GFX_BACKEND_NAME "SDL"
|
||||
// define a way to yield the cpu when in a busy wait
|
||||
#ifdef PLATFORM_WIN32
|
||||
// winapi provides a yield macro
|
||||
#include <windows.h>
|
||||
#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 <immintrin.h>
|
||||
#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;
|
||||
@@ -27,15 +39,32 @@ static bool fullscreen_state;
|
||||
static bool is_running = true;
|
||||
static void (*on_fullscreen_changed_callback)(bool is_now_fullscreen);
|
||||
|
||||
static uint64_t previous_time;
|
||||
|
||||
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;
|
||||
@@ -55,11 +84,6 @@ static void gfx_sdl_get_active_window_refresh_rate(uint32_t* refresh_rate) {
|
||||
*refresh_rate = mode.refresh_rate;
|
||||
}
|
||||
|
||||
static inline void do_sleep(const uint64_t ns) {
|
||||
const timespec spec = { 0, ns };
|
||||
nanosleep(&spec, nullptr);
|
||||
}
|
||||
|
||||
static void gfx_sdl_init(const char* game_name, const char* gfx_api_name, bool start_in_fullscreen, uint32_t width,
|
||||
uint32_t height, int32_t posX, int32_t posY) {
|
||||
window_width = width;
|
||||
@@ -143,6 +167,20 @@ 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_fullscreen(start_in_fullscreen, false);
|
||||
}
|
||||
|
||||
@@ -211,11 +249,18 @@ static inline void sync_framerate_with_timer(void) {
|
||||
t = qpc_to_100ns(SDL_GetPerformanceCounter());
|
||||
|
||||
const int64_t next = previous_time + 10 * FRAME_INTERVAL_US_NUMERATOR / FRAME_INTERVAL_US_DENOMINATOR;
|
||||
const int64_t left = next - t;
|
||||
int64_t left = next - t;
|
||||
// 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 * 100);
|
||||
do_sleep(left);
|
||||
}
|
||||
|
||||
do {
|
||||
DO_YIELD();
|
||||
t = qpc_to_100ns(SDL_GetPerformanceCounter());
|
||||
} while ((int64_t)t < next);
|
||||
|
||||
t = qpc_to_100ns(SDL_GetPerformanceCounter());
|
||||
if (left > 0 && t - next < 10000) {
|
||||
// In case it takes some time for the application to wake up after sleep,
|
||||
|
||||
@@ -35,6 +35,8 @@ u32 g_VmNumPageMisses = 0;
|
||||
u32 g_VmNumPageReplaces = 0;
|
||||
u8 g_VmShowStats = 0;
|
||||
|
||||
s32 g_TickRateDiv = 1;
|
||||
|
||||
extern s32 g_StageNum;
|
||||
|
||||
s32 bootGetMemSize(void)
|
||||
@@ -136,6 +138,7 @@ PD_CONSTRUCTOR static void gameConfigInit(void)
|
||||
configRegisterInt("Game.MemorySize", &g_OsMemSizeMb, 4, 2048);
|
||||
configRegisterInt("Game.CenterHUD", &g_HudCenter, 0, 1);
|
||||
configRegisterFloat("Game.ScreenShakeIntensity", &g_ViShakeIntensityMult, 0.f, 10.f);
|
||||
configRegisterInt("Game.TickRateDivisor", &g_TickRateDiv, 0, 10);
|
||||
for (s32 j = 0; j < MAX_PLAYERS; ++j) {
|
||||
const s32 i = j + 1;
|
||||
configRegisterFloat(strFmt("Game.Player%d.FovY", i), &g_PlayerExtCfg[j].fovy, 5.f, 175.f);
|
||||
|
||||
+1
-1
@@ -495,7 +495,7 @@ void mainLoop(void)
|
||||
|
||||
while (g_MainChangeToStageNum < 0) {
|
||||
const s32 cycles = osGetCount() - g_Vars.thisframestartt;
|
||||
if (cycles >= g_Vars.mininc60 * CYCLES_PER_FRAME - CYCLES_PER_FRAME / 2) {
|
||||
if (!g_Vars.mininc60 || (cycles >= g_Vars.mininc60 * CYCLES_PER_FRAME - CYCLES_PER_FRAME / 2)) {
|
||||
schedStartFrame(&g_Sched);
|
||||
mainTick();
|
||||
schedEndFrame(&g_Sched);
|
||||
|
||||
@@ -411,7 +411,7 @@ void amTick(void)
|
||||
|
||||
// Update alpha of slots so they fade in
|
||||
if (g_AmMenus[g_AmIndex].alphafrac < 1) {
|
||||
g_AmMenus[g_AmIndex].alphafrac += LVUPDATE60FREAL() / 30.0f;
|
||||
g_AmMenus[g_AmIndex].alphafrac += (f32)g_Vars.lvupdate240 / (4.f * 30.0f);
|
||||
}
|
||||
|
||||
if (g_AmMenus[g_AmIndex].alphafrac > 1) {
|
||||
@@ -419,7 +419,7 @@ void amTick(void)
|
||||
}
|
||||
|
||||
// Make selection border pulsate
|
||||
g_AmMenus[g_AmIndex].selpulse += LVUPDATE60FREAL() / 5.0f;
|
||||
g_AmMenus[g_AmIndex].selpulse += (f32)g_Vars.lvupdate240 / (4.f * 5.0f);
|
||||
|
||||
if (g_AmMenus[g_AmIndex].selpulse > 18.849555969238f) {
|
||||
g_AmMenus[g_AmIndex].selpulse -= 18.849555969238f;
|
||||
|
||||
@@ -922,8 +922,6 @@ void eyespyProcessInput(bool allowbuttons)
|
||||
f32 mdx, mdy;
|
||||
inputMouseGetScaledDelta(&mdx, &mdy);
|
||||
if (mdx || mdy) {
|
||||
mdx *= g_Vars.lvupdate60freal;
|
||||
mdy *= g_Vars.lvupdate60freal;
|
||||
if (g_Vars.currentplayerstats && !optionsGetForwardPitch(g_Vars.currentplayerstats->mpindex)) {
|
||||
mdy = -mdy;
|
||||
}
|
||||
|
||||
+12
-1
@@ -10918,6 +10918,7 @@ void bgunRender(Gfx **gdlptr)
|
||||
struct modelrenderdata renderdata = {NULL, true, 3}; // 10c
|
||||
struct player *player;
|
||||
s32 i;
|
||||
const u32 wnorm = mtx00016dcc(0, 300);
|
||||
|
||||
static bool renderhand = true; // var800702dc
|
||||
|
||||
@@ -10983,7 +10984,7 @@ void bgunRender(Gfx **gdlptr)
|
||||
gSPLookAt(gdl++, camGetLookAt());
|
||||
}
|
||||
|
||||
gSPPerspNormalize(gdl++, mtx00016dcc(0, 300));
|
||||
gSPPerspNormalize(gdl++, wnorm);
|
||||
|
||||
// There is support for guns having a TV screen on them
|
||||
// but no guns have this model part so it's not used.
|
||||
@@ -11158,7 +11159,17 @@ void bgunRender(Gfx **gdlptr)
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
// put the casings into the same Z range as the gun
|
||||
gSPPerspNormalize(gdl++, wnorm);
|
||||
#endif
|
||||
|
||||
casingsRender(&gdl);
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
gSPPerspNormalize(gdl++, viGetPerspScale());
|
||||
#endif
|
||||
|
||||
zbufSwap();
|
||||
|
||||
gdl = zbufConfigureRdp(gdl);
|
||||
|
||||
+3
-2
@@ -714,6 +714,7 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
|
||||
#ifndef PLATFORM_N64
|
||||
const bool allowmlook = (g_Vars.currentplayernum == 0) && (allowc1x || allowc1y);
|
||||
bool allowmcross = false;
|
||||
const f32 mlookscale = g_Vars.lvupdate240 ? (4.f / (f32)g_Vars.lvupdate240) : 4.f;
|
||||
#endif
|
||||
|
||||
controlmode = optionsGetControlMode(g_Vars.currentplayerstats->mpindex);
|
||||
@@ -2017,7 +2018,7 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
fVar25 += movedata.freelookdy;
|
||||
fVar25 += movedata.freelookdy * mlookscale;
|
||||
#endif
|
||||
|
||||
g_Vars.currentplayer->speedverta = -fVar25 * tmp;
|
||||
@@ -2058,7 +2059,7 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
fVar25 += movedata.freelookdx;
|
||||
fVar25 += movedata.freelookdx * mlookscale;
|
||||
#endif
|
||||
|
||||
g_Vars.currentplayer->speedthetacontrol = fVar25 * tmp;
|
||||
|
||||
+4
-3
@@ -177,9 +177,10 @@ void footstepCheckDefault(struct chrdata *chr)
|
||||
chr->footstep = 2;
|
||||
}
|
||||
} else {
|
||||
#ifndef PLATFORM_N64 // fix spamming footsteps for 60fps port
|
||||
if (g_Vars.lvupdate240 == LV_SLOMO_TICK_CAP) {
|
||||
s32 roundedframe = (s32)(frame*2);
|
||||
#ifndef PLATFORM_N64
|
||||
// fix spamming footsteps at >= 60fps
|
||||
if (g_Vars.lvupdate240 < 4) {
|
||||
const s32 roundedframe = (s32)(frame * (4.f / (f32)g_Vars.lvupdate240));
|
||||
if (roundedframe == (g_FootstepAnims[i].frame1*2) && prevframe < g_FootstepAnims[i].frame1) {
|
||||
chr->footstep = 1;
|
||||
} else if (roundedframe == (g_FootstepAnims[i].frame2*2) && prevframe < g_FootstepAnims[i].frame2) {
|
||||
|
||||
+5
-5
@@ -2057,7 +2057,7 @@ void lvTick(void)
|
||||
g_Vars.lvupdate240 = 0;
|
||||
|
||||
for (j = 0; j < PLAYERCOUNT(); j++) {
|
||||
g_Vars.players[j]->joybutinhibit = 0xefffffff;
|
||||
g_Vars.players[j]->joybutinhibit = 0xffffefff;
|
||||
}
|
||||
} else {
|
||||
s32 slowmo = lvGetSlowMotionType();
|
||||
@@ -2066,7 +2066,7 @@ void lvTick(void)
|
||||
if (slowmo == SLOWMOTION_ON) {
|
||||
if (g_Vars.speedpillon == false || g_Vars.in_cutscene) {
|
||||
if (g_Vars.lvupdate240 > LV_SLOMO_TICK_CAP) {
|
||||
g_Vars.lvupdate240 = LV_SLOMO_TICK_CAP;
|
||||
g_Vars.lvupdate240 = LV_SLOMO_TICK_RATE;
|
||||
}
|
||||
}
|
||||
} else if (slowmo == SLOWMOTION_SMART) {
|
||||
@@ -2097,7 +2097,7 @@ void lvTick(void)
|
||||
|
||||
if (foundnearbychr) {
|
||||
if (g_Vars.lvupdate240 > LV_SLOMO_TICK_CAP) {
|
||||
g_Vars.lvupdate240 = LV_SLOMO_TICK_CAP;
|
||||
g_Vars.lvupdate240 = LV_SLOMO_TICK_RATE;
|
||||
}
|
||||
} else {
|
||||
if (g_Vars.lvupdate240 > TICKS(8)) {
|
||||
@@ -2106,7 +2106,7 @@ void lvTick(void)
|
||||
}
|
||||
} else {
|
||||
if (g_Vars.lvupdate240 > LV_SLOMO_TICK_CAP) {
|
||||
g_Vars.lvupdate240 = LV_SLOMO_TICK_CAP;
|
||||
g_Vars.lvupdate240 = LV_SLOMO_TICK_RATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2114,7 +2114,7 @@ void lvTick(void)
|
||||
// Slow motion settings are off
|
||||
if (g_Vars.speedpillon && g_Vars.in_cutscene == false) {
|
||||
if (g_Vars.lvupdate240 > LV_SLOMO_TICK_CAP) {
|
||||
g_Vars.lvupdate240 = LV_SLOMO_TICK_CAP;
|
||||
g_Vars.lvupdate240 = LV_SLOMO_TICK_RATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -3593,8 +3593,8 @@ void playerTick(bool arg0)
|
||||
if (g_Vars.currentplayerstats && !optionsGetForwardPitch(g_Vars.currentplayerstats->mpindex)) {
|
||||
mdy = -mdy;
|
||||
}
|
||||
sp178 += mdy * LVUPDATE60FREAL() * 0.00025f;
|
||||
sp174 -= mdx * LVUPDATE60FREAL() * 0.00025f;
|
||||
sp178 += mdy * 0.00025f;
|
||||
sp174 -= mdx * 0.00025f;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -7679,7 +7679,12 @@ void doorTick(struct prop *doorprop)
|
||||
}
|
||||
|
||||
// Update frac
|
||||
#ifdef PLATFORM_N64
|
||||
if (door->lastcalc60 < g_Vars.lvframe60 || g_Vars.lvupdate240 == 0) {
|
||||
#else
|
||||
// lastcalc60 actually stores lvframe240
|
||||
if (door->lastcalc60 < g_Vars.lvframe240 || g_Vars.lvupdate240 == 0) {
|
||||
#endif
|
||||
doorsCalcFrac(door);
|
||||
}
|
||||
|
||||
@@ -9010,6 +9015,12 @@ void autogunInitMatrices(struct prop *prop, Mtxf *mtx)
|
||||
|
||||
void autogunTickShoot(struct prop *autogunprop)
|
||||
{
|
||||
#ifndef PLATFORM_N64
|
||||
// HACK: fire every other tick at 60+ fps and every tick at <60 fps
|
||||
if (g_Vars.lvupdate240 <= TICKS(4) && (g_Vars.lvframe60 & 1)) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (!lvIsPaused()) {
|
||||
struct autogunobj *autogun = (struct autogunobj *) autogunprop->obj;
|
||||
struct defaultobj *obj = autogunprop->obj;
|
||||
@@ -20345,7 +20356,11 @@ void doorsCalcFrac(struct doorobj *door)
|
||||
func0f08d460(loopdoor);
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
loopdoor->lastcalc60 = g_Vars.lvframe60;
|
||||
#else
|
||||
loopdoor->lastcalc60 = g_Vars.lvframe240; // actually use the 240hz counter for higher framerates
|
||||
#endif
|
||||
loopdoor = loopdoor->sibling;
|
||||
|
||||
if (loopdoor == door) {
|
||||
|
||||
+5
-1
@@ -41,12 +41,16 @@ 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);
|
||||
} while (diffframe60 < g_Vars.mininc60);
|
||||
} while (g_Vars.mininc60 && diffframe60 < g_Vars.mininc60);
|
||||
|
||||
g_Vars.lostframetime60t = g_Vars.lostframetime60t + diffframet - diffframe60 * CYCLES_PER_FRAME;
|
||||
g_Vars.lostframetime240t = g_Vars.lostframetime240t + diffframet - diffframe240 * (CYCLES_PER_FRAME / 4);
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
g_Vars.mininc60 = 1;
|
||||
#else
|
||||
g_Vars.mininc60 = g_TickRateDiv;
|
||||
#endif
|
||||
|
||||
frametimeApply(diffframe60, diffframe240, count);
|
||||
}
|
||||
|
||||
@@ -545,6 +545,7 @@ extern u32 g_HudAlignModeR;
|
||||
extern s32 g_PrevFrameFb;
|
||||
extern s32 g_BlurFb;
|
||||
extern s32 g_BlurFbCapTimer;
|
||||
extern s32 g_TickRateDiv;
|
||||
|
||||
#define PLAYER_EXTCFG() g_PlayerExtCfg[g_Vars.currentplayerstats->mpindex & 3]
|
||||
#define PLAYER_DEFAULT_FOV (PLAYER_EXTCFG().fovy)
|
||||
|
||||
@@ -6,10 +6,12 @@
|
||||
|
||||
#ifdef PLATFORM_N64
|
||||
// game runs at ~30, so slomo = 1/2 of 30fps
|
||||
#define LV_SLOMO_TICK_CAP TICKS(4)
|
||||
#define LV_SLOMO_TICK_CAP 4
|
||||
#define LV_SLOMO_TICK_RATE LV_SLOMO_TICK_CAP
|
||||
#else
|
||||
// game runs at 60+, so slomo = 1/2 of 60fps
|
||||
#define LV_SLOMO_TICK_CAP TICKS(2)
|
||||
// game runs at 60+, so slomo = 1/2 of whatever framerate we're running at
|
||||
#define LV_SLOMO_TICK_CAP 1 // capping at >= 240fps would make it explode
|
||||
#define LV_SLOMO_TICK_RATE (g_Vars.lvupdate240 / 2)
|
||||
#endif
|
||||
|
||||
u32 getVar80084040(void);
|
||||
|
||||
+1
-1
@@ -1523,7 +1523,7 @@ struct doorobj { // objtype 0x01
|
||||
/*0xc4*/ s16 portalnum;
|
||||
/*0xc6*/ s8 soundtype;
|
||||
/*0xc7*/ s8 fadetime60; // counts down
|
||||
/*0xc8*/ s32 lastcalc60;
|
||||
/*0xc8*/ s32 lastcalc60; // port: actually stores 240hz frame number
|
||||
/*0xcc*/ u8 laserfade;
|
||||
/*0xcd*/ u8 unusedmaybe[3];
|
||||
/*0xd0*/ u8 shadeinfo1[4]; // player 1
|
||||
|
||||
@@ -28,7 +28,11 @@ void varsInit(void)
|
||||
g_Vars.lostframetime60t = 0;
|
||||
g_Vars.lostframetime240t = 0;
|
||||
g_Vars.lvupdate240rem = 2;
|
||||
#ifdef PLATFORM_N64
|
||||
g_Vars.mininc60 = 1;
|
||||
#else
|
||||
g_Vars.mininc60 = g_TickRateDiv;
|
||||
#endif
|
||||
g_Vars.roomportalrecursionlimit = 254;
|
||||
g_Vars.diffframe240f = 4;
|
||||
g_Vars.diffframe240freal = 4;
|
||||
|
||||
Reference in new issue
Block a user