Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/libpm-jp.a
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ pm_audio_set_mono = 0x80055E30;
pm_remove_effect = 0x8005A100;
nuPiReadRom = 0x8005F140;
nuContDataGet = 0x8005F300;
nuGfxTaskStart = 0x8002CF24;
nuGfxTaskAllEndWait = 0x8005EF80;
__osPiGetAccess = 0x80061474;
__osPiRelAccess = 0x800614E0;
osWritebackDCacheAll = 0x800618A0;
Expand All @@ -83,6 +85,7 @@ osStopThread = 0x80066110;
osGetTime = 0x80066270;
osSetTime = 0x80066300;
__osGetActiveQueue = 0x80066260;
osViGetNextFramebuffer = 0x800669C0;
osViSwapBuffer = 0x80066FF0;
osViBlack = 0x80067350;
osViRepeatLine = 0x800673B0;
Expand Down
3 changes: 3 additions & 0 deletions lib/libpm-us.a
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ pm_audio_set_mono = 0x80056180;
pm_remove_effect = 0x8005A450;
nuPiReadRom = 0x8005F490;
nuContDataGet = 0x8005F650;
nuGfxTaskStart = 0x8002CCC4;
nuGfxTaskAllEndWait = 0x8005F2D0;
__osPiGetAccess = 0x800614A4;
__osPiRelAccess = 0x80061510;
osWritebackDCacheAll = 0x800618D0;
Expand All @@ -83,6 +85,7 @@ osStopThread = 0x80066140;
osGetTime = 0x800662A0;
osSetTime = 0x80066330;
__osGetActiveQueue = 0x80066290;
osViGetNextFramebuffer = 0x800669F0;
osViSwapBuffer = 0x80067020;
osViBlack = 0x80067380;
osViRepeatLine = 0x800673E0;
Expand Down
26 changes: 26 additions & 0 deletions src/commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ struct Command fpCommands[COMMAND_MAX] = {
{"store ability", COMMAND_PRESS_ONCE, 0, commandStoreAbility },
{"ignore walls", COMMAND_PRESS_ONCE, 0, commandIgnoreWalls },
{"floor clip", COMMAND_PRESS_ONCE, 0, commandFloorClip },
{"pause", COMMAND_PRESS_ONCE, 0, commandPauseProc },
{"frame advance", COMMAND_PRESS, 0, commandFrameAdvanceProc },
};

void showMenu(void) {
Expand Down Expand Up @@ -77,6 +79,11 @@ void fpSetInputMask(u32 pad, s8 x, s8 y) {
}

bool fpWarp(enum Areas area, u16 map, u16 entrance) {
if (pm_CurGameMode < 4 || pm_CurGameMode >= 12 || pm_gGameStatus.demoState) {
fpLog("can't warp right now");
return FALSE;
}

pm_bgm_set_song(1, -1, 0, 0, 8); // clear secondary songs
pm_snd_ambient_stop_all(0);
pm_au_sfx_reset_players(pm_gSoundManager);
Expand Down Expand Up @@ -334,3 +341,22 @@ void commandFloorClip(void) {
}
}
}

void commandPauseProc(void) {
if (fp.pendingFrames == 0) {
fp.pendingFrames = -1;
fpLog("unpaused");
} else {
fp.pendingFrames = 0;
fpLog("paused");
}
}

void commandFrameAdvanceProc(void) {
if (fp.pendingFrames == 0) {
fp.pendingFrames++;
} else {
fp.pendingFrames = 0;
fpLog("paused");
}
}
4 changes: 4 additions & 0 deletions src/commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ enum Commands {
COMMAND_STORE_ABILITY,
COMMAND_IGNORE_WALLS,
COMMAND_FLOOR_CLIP,
COMMAND_PAUSE,
COMMAND_FRAME_ADVANCE,
COMMAND_MAX
};

Expand Down Expand Up @@ -63,6 +65,8 @@ void commandClippyProc(void);
void commandStoreAbility(void);
void commandIgnoreWalls(void);
void commandFloorClip(void);
void commandPauseProc(void);
void commandFrameAdvanceProc(void);

extern struct Command fpCommands[COMMAND_MAX];

Expand Down
8 changes: 8 additions & 0 deletions src/enums.h
Original file line number Diff line number Diff line change
Expand Up @@ -993,4 +993,12 @@ enum GameContext {
CONTEXT_PAUSE = 2,
};

enum GlobalOverrides {
GLOBAL_OVERRIDES_DISABLE_DRAW_FRAME = 0x00000008,
};

enum BackgroundRenderState {
BACKGROUND_RENDER_STATE_MASK = 0xF0,
};

#endif
129 changes: 121 additions & 8 deletions src/fp.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,18 @@
#include "util/geometry.h"
#include "util/watchlist.h"
#include <math.h>
#include <mips.h>
#include <n64.h>
#include <startup.h>
#include <stdlib.h>
#include <string.h>

FpCtxt fp = {.savedArea = 0x1c, .camDistMin = 100, .camDistMax = 1000, .freeCamMoveSpeed = 250, .freeCamPanSpeed = 70};
FpCtxt fp = {.savedArea = 0x1c,
.camDistMin = 100,
.camDistMax = 1000,
.freeCamMoveSpeed = 250,
.freeCamPanSpeed = 70,
.pendingFrames = -1};

// Initializes and uses new stack instead of using games main thread stack.
static void initStack(void (*func)(void)) {
Expand All @@ -29,8 +35,13 @@ static void initStack(void (*func)(void)) {
"jalr %0;"
"nop;"
"lw $ra, 0($sp);"
"lw $sp, 4($sp);" ::"r"(func),
"i"(&stack[sizeof(stack)]));
"lw $sp, 4($sp);"
:
: "r"(func), "i"(&stack[sizeof(stack)])
// assume that `func` clobbers every caller-saved register
: "memory", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
"t8", "t9", "ra", "hi", "lo", "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8",
"$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", "$f16", "$f17", "$f18", "$f19");
}

static void mainReturnProc(struct MenuItem *item, void *data) {
Expand Down Expand Up @@ -196,9 +207,9 @@ void fpDrawVersion(struct GfxFont *font, s32 cellWidth, s32 cellHeight, u8 menuA
}

void fpDrawInputDisplay(struct GfxFont *font, s32 cellWidth, s32 cellHeight, u8 menuAlpha) {
u16 dPad = pm_gGameStatus.currentButtons[0].buttons;
s8 dX = pm_gGameStatus.stickX[0];
s8 dY = pm_gGameStatus.stickY[0];
u16 dPad = inputPad().buttons;
s8 dX = inputX();
s8 dY = inputY();

struct GfxTexture *texture = resourceGet(RES_ICON_BUTTONS);
struct GfxTexture *controlStick = resourceGet(RES_TEXTURE_CONTROL_STICK);
Expand Down Expand Up @@ -572,6 +583,91 @@ void fpDraw(void) {
gfxFlush();
}

#define PAUSE_DL_LENGTH 1024
#define PAUSE_BLIT_ROWS 6 // 4KB tmem / (320 * 2) ~= 6

static struct {
bool frozen;
bool captured;
bool overrideWasSet;
s16 bgRenderState;
u16 *frame;
s32 dlIdx;
Gfx dl[2][PAUSE_DL_LENGTH];
} pauseFrame;

static void fpPauseBlit(const u16 *src, u16 *dst) {
gDPPipeSync(pm_gMainGfxPos++);
gSPTexture(pm_gMainGfxPos++, -1, -1, 0, G_TX_RENDERTILE, G_ON);
gDPSetScissor(pm_gMainGfxPos++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
gDPSetColorImage(pm_gMainGfxPos++, G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_WIDTH, MIPS_KSEG0_TO_PHYS(dst));
gDPSetCycleType(pm_gMainGfxPos++, G_CYC_COPY);
gDPSetRenderMode(pm_gMainGfxPos++, G_RM_NOOP, G_RM_NOOP2);
gDPSetTexturePersp(pm_gMainGfxPos++, G_TP_NONE);
gDPSetTextureLUT(pm_gMainGfxPos++, G_TT_NONE);
gDPSetAlphaCompare(pm_gMainGfxPos++, G_AC_NONE);
for (s32 y = 0; y < SCREEN_HEIGHT; y += PAUSE_BLIT_ROWS) {
gDPLoadTextureTile(pm_gMainGfxPos++, &src[y * SCREEN_WIDTH], G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_WIDTH,
PAUSE_BLIT_ROWS, 0, 0, SCREEN_WIDTH - 1, PAUSE_BLIT_ROWS - 1, 0, G_TX_NOMIRROR | G_TX_CLAMP,
G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
gSPTextureRectangle(pm_gMainGfxPos++, qu102(0), qu102(y), qu102(SCREEN_WIDTH - 1),
qu102(y + PAUSE_BLIT_ROWS - 1), G_TX_RENDERTILE, 0, 0, 4 << 10, 1 << 10);
}
}

// emitted into display list before fp so frozen frame doesn't contain stale fp overlay
static void fpPauseCapture(void) {
u16 *cfb = nuGfxCfb_ptr;
if (pauseFrame.frame == NULL) {
pauseFrame.frame = malloc(SCREEN_WIDTH * SCREEN_HEIGHT * sizeof(*pauseFrame.frame));
}
fpPauseBlit(cfb, pauseFrame.frame);
gDPPipeSync(pm_gMainGfxPos++);
gDPSetColorImage(pm_gMainGfxPos++, G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_WIDTH, MIPS_KSEG0_TO_PHYS(cfb));
pauseFrame.captured = TRUE;
}

static void fpPauseFreeze(void) {
nuGfxTaskAllEndWait();
if (!pauseFrame.captured) {
// game skipped draw pass so copy the fb ourselves
if (pauseFrame.frame == NULL) {
pauseFrame.frame = malloc(SCREEN_WIDTH * SCREEN_HEIGHT * sizeof(*pauseFrame.frame));
}
memcpy(pauseFrame.frame, osViGetNextFramebuffer(), SCREEN_WIDTH * SCREEN_HEIGHT * sizeof(*pauseFrame.frame));
}
pauseFrame.overrideWasSet = (pm_gOverrideFlags & GLOBAL_OVERRIDES_DISABLE_DRAW_FRAME) != 0;
pm_gOverrideFlags |= GLOBAL_OVERRIDES_DISABLE_DRAW_FRAME;
pauseFrame.bgRenderState = pm_gGameStatus.backgroundFlags & BACKGROUND_RENDER_STATE_MASK;
pm_gGameStatus.backgroundFlags &= ~BACKGROUND_RENDER_STATE_MASK;
pauseFrame.frozen = TRUE;
}

static void fpPauseUnfreeze(void) {
if (!pauseFrame.overrideWasSet) {
pm_gOverrideFlags &= ~GLOBAL_OVERRIDES_DISABLE_DRAW_FRAME;
}
pm_gGameStatus.backgroundFlags |= pauseFrame.bgRenderState;
pauseFrame.frozen = FALSE;
pauseFrame.captured = FALSE;
}

static void fpPauseDrawFrame(void) {
Gfx *dl = pauseFrame.dl[pauseFrame.dlIdx];
pauseFrame.dlIdx ^= 1;
u16 *cfb = nuGfxCfb_ptr;
pm_gMainGfxPos = dl;

gSPSegment(pm_gMainGfxPos++, 0x00, 0x0);
fpPauseBlit(pauseFrame.frame, cfb);

initStack(fpDraw);

gDPFullSync(pm_gMainGfxPos++);
gSPEndDisplayList(pm_gMainGfxPos++);
nuGfxTaskStart(dl, (u32)(pm_gMainGfxPos - dl) * sizeof(*dl), NU_GFX_UCODE_F3DEX2, NU_SC_SWAPBUFFER);
}

/* ========================== HOOK ENTRY POINTS ========================== */

ENTRY void fpUpdateEntry(void) {
Expand All @@ -582,13 +678,30 @@ ENTRY void fpUpdateEntry(void) {
PRINTF("\n**** fp initialized ****\n\n");
}

pm_step_game_loop();
initStack(fpUpdate);
if (fp.pendingFrames) {
if (fp.pendingFrames > 0) {
fp.pendingFrames--;
}
if (pauseFrame.frozen) {
fpPauseUnfreeze();
}
pm_step_game_loop();
initStack(fpUpdate);
} else {
if (!pauseFrame.frozen) {
fpPauseFreeze();
}
initStack(fpUpdate);
fpPauseDrawFrame();
}
}

ENTRY void fpDrawEntry(void) {
init_gp();
pm_state_render_frontUI();
if (fp.pendingFrames == 0 && !pauseFrame.frozen) {
fpPauseCapture();
}
initStack(fpDraw);
}

Expand Down
1 change: 1 addition & 0 deletions src/fp.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ typedef struct {
u16 freeCamMoveSpeed;
u16 freeCamPanSpeed;
bool ignoreWalls;
s8 pendingFrames;
} FpCtxt;

extern FpCtxt fp;
Expand Down
6 changes: 6 additions & 0 deletions src/pm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@
#define SCRIPT_BOWSER_FINAL_2_WAVE 0x8023226C
#define SCRIPT_BOWSER_FINAL_2_LIGHTNING 0x802339F4

#define NU_GFX_UCODE_F3DEX2 0
#define NU_SC_SWAPBUFFER 1

// NOLINTBEGIN
typedef struct OSContPad {
u16 button;
Expand Down Expand Up @@ -1439,11 +1442,14 @@ void pm_audio_set_mono(void);
void pm_remove_effect(pm_EffectInstance *effect);
void nuPiReadRom(u32 rom_addr, void *buf_ptr, u32 size);
void nuContDataGet(OSContPad *contpad, u32 cont_no);
void nuGfxTaskStart(Gfx *gfxListPtr, u32 gfxListSize, u32 ucode, u32 flags);
void nuGfxTaskAllEndWait(void);
void osWritebackDCacheAll(void);
s32 _Printf(PrintCallback pfn, void *arg, const char *fmt, va_list ap);
u64 osGetTime(void);
void osSetTime(u64 time);
OSThread *__osGetActiveQueue(void);
void *osViGetNextFramebuffer(void);
void osViSwapBuffer(void *vaddr);
void osViBlack(u8 active);
void osViRepeatLine(u8 active);
Expand Down
2 changes: 2 additions & 0 deletions src/sys/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ void settingsLoadDefault(void) {
d->binds[COMMAND_STORE_ABILITY] = bindMake(2, BUTTON_B, BUTTON_D_LEFT);
d->binds[COMMAND_IGNORE_WALLS] = bindMake(2, BUTTON_B, BUTTON_D_UP);
d->binds[COMMAND_FLOOR_CLIP] = bindMake(2, BUTTON_L, BUTTON_D_DOWN);
d->binds[COMMAND_PAUSE] = bindMake(0);
d->binds[COMMAND_FRAME_ADVANCE] = bindMake(0);
d->cheatEnemyContact = 0;
d->controlStickRange = 90;
d->controlStick = 2;
Expand Down
2 changes: 1 addition & 1 deletion src/sys/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

#define SETTINGS_SAVE_FILE_SIZE 0x1380
#define SETTINGS_PROFILE_MAX 4
#define SETTINGS_VERSION 9
#define SETTINGS_VERSION 10
#define SETTINGS_FIO_PAGE 7

#define SETTINGS_WATCHES_MAX 18
Expand Down
Loading