Work on new save menu

This commit is contained in:
James Lambert 2023-05-02 20:12:03 -06:00
parent 37723bc35a
commit 42caf31ea8
8 changed files with 148 additions and 56 deletions

View file

@ -1,6 +1,7 @@
materials: materials:
default_ui: default_ui:
gDPSetCycleType: G_CYC_1CYCLE
gSPGeometryMode: gSPGeometryMode:
clear: [G_ZBUFFER, G_LIGHTING, G_SHADE] clear: [G_ZBUFFER, G_LIGHTING, G_SHADE]
gDPSetTextureLUT: G_TT_NONE gDPSetTextureLUT: G_TT_NONE
@ -91,3 +92,11 @@ materials:
b: 0 b: 0
a: 85 a: 85
image_copy:
gDPSetRenderMode: G_RM_OPA_SURF
gDPSetCombineMode:
color: ["0", "0", "0", TEXEL0]
alpha: ["0", "0", "0", TEXEL0]
gDPSetTextureFilter: G_TF_BILERP
gDPSetTextureLUT: G_TT_NONE
gDPSetTexturePersp: G_TP_NONE

View file

@ -12,22 +12,6 @@ void loadGamePopulate(struct LoadGameMenu* loadGame) {
int numberOfSaves = savefileListSaves(saveSlots, 1); int numberOfSaves = savefileListSaves(saveSlots, 1);
saveSlots[0].saveSlot = 0;
saveSlots[0].testChamber = 0;
saveSlots[1].saveSlot = 1;
saveSlots[1].testChamber = 4;
saveSlots[2].saveSlot = 2;
saveSlots[2].testChamber = 5;
saveSlots[3].saveSlot = 3;
saveSlots[3].testChamber = 3;
saveSlots[4].saveSlot = 4;
saveSlots[4].testChamber = 0;
numberOfSaves = 5;
for (int i = 0; i < numberOfSaves; ++i) { for (int i = 0; i < numberOfSaves; ++i) {
savefileInfo[i].slotIndex = saveSlots[i].saveSlot; savefileInfo[i].slotIndex = saveSlots[i].saveSlot;
savefileInfo[i].testchamberIndex = saveSlots[i].testChamber; savefileInfo[i].testchamberIndex = saveSlots[i].testChamber;

View file

@ -13,33 +13,20 @@ void saveGamePopulate(struct SaveGameMenu* saveGame) {
int numberOfSaves = savefileListSaves(saveSlots, 0); int numberOfSaves = savefileListSaves(saveSlots, 0);
saveSlots[0].saveSlot = 0;
saveSlots[0].testChamber = 0;
saveSlots[1].saveSlot = 1;
saveSlots[1].testChamber = 4;
saveSlots[2].saveSlot = 2;
saveSlots[2].testChamber = 5;
saveSlots[3].saveSlot = 3;
saveSlots[3].testChamber = 3;
saveSlots[4].saveSlot = 4;
saveSlots[4].testChamber = 0;
numberOfSaves = 5;
for (int i = 0; i < numberOfSaves; ++i) { for (int i = 0; i < numberOfSaves; ++i) {
savefileInfo[i].slotIndex = saveSlots[i].saveSlot; savefileInfo[i].slotIndex = saveSlots[i].saveSlot;
savefileInfo[i].testchamberIndex = saveSlots[i].testChamber; savefileInfo[i].testchamberIndex = saveSlots[i].testChamber;
savefileInfo[i].savefileName = NULL; savefileInfo[i].savefileName = NULL;
savefileInfo[i].screenshot = (u16*)SCREEN_SHOT_SRAM(saveSlots[i].saveSlot);
} }
if (numberOfSaves < MAX_USER_SAVE_SLOTS) { int freeSlot = savefileFirstFreeSlot();
// TODO
savefileInfo[numberOfSaves].slotIndex = 0; if (freeSlot != SAVEFILE_NO_SLOT) {
savefileInfo[numberOfSaves].slotIndex = freeSlot;
savefileInfo[numberOfSaves].savefileName = "NEW SAVE"; savefileInfo[numberOfSaves].savefileName = "NEW SAVE";
savefileInfo[numberOfSaves].testchamberIndex = gCurrentLevelIndex; savefileInfo[numberOfSaves].testchamberIndex = gCurrentLevelIndex;
savefileInfo[numberOfSaves].screenshot = gScreenGrabBuffer;
++numberOfSaves; ++numberOfSaves;
} }

View file

@ -8,8 +8,12 @@
#include "../build/assets/materials/ui.h" #include "../build/assets/materials/ui.h"
#define BORDER_WIDTH 92 #define SAVE_SLOT_RENDER_W (SAVE_SLOT_IMAGE_W * 2)
#define BORDER_HEIGHT 58 #define SAVE_SLOT_RENDER_H (SAVE_SLOT_IMAGE_H * 2)
#define BORDER_THICKNESS 5
#define BORDER_WIDTH (SAVE_SLOT_RENDER_W + BORDER_THICKNESS * 2)
#define BORDER_HEIGHT (SAVE_SLOT_RENDER_H + BORDER_THICKNESS * 2)
#define ROW_HEIGHT (BORDER_HEIGHT + 8) #define ROW_HEIGHT (BORDER_HEIGHT + 8)
@ -17,28 +21,42 @@ void savefileListSlotUseInfo(struct SavefileListSlot* savefileListSlot, struct S
char message[16]; char message[16];
sprintf(message, "Testchamber %02d", savefileInfo->testchamberIndex); sprintf(message, "Testchamber %02d", savefileInfo->testchamberIndex);
fontRender(&gDejaVuSansFont, message, x + BORDER_WIDTH + 8, y, savefileListSlot->testChamberText); fontRender(&gDejaVuSansFont, message, x + BORDER_WIDTH + 8, y, savefileListSlot->testChamberText);
if (savefileListSlot->gameId) {
free(savefileListSlot->gameId);
}
if (savefileInfo->savefileName) {
strcpy(message, savefileInfo->savefileName);
} else {
sprintf(message, "Subject %02d", gSaveData.saveSlotMetadata[savefileInfo->slotIndex].testSubjectNumber);
}
savefileListSlot->gameId = menuBuildText(&gDejaVuSansFont, message, x + BORDER_WIDTH + 8, y + 16);
menuRerenderSolidBorder( menuRerenderSolidBorder(
x, y, BORDER_WIDTH, BORDER_HEIGHT, x, y,
x + 5, y + 5, 82, 48, BORDER_WIDTH, BORDER_HEIGHT,
x + BORDER_THICKNESS, y + BORDER_THICKNESS,
SAVE_SLOT_IMAGE_W * 2, SAVE_SLOT_IMAGE_H * 2,
savefileListSlot->border savefileListSlot->border
); );
savefileListSlot->slotIndex = savefileInfo->slotIndex; savefileListSlot->slotIndex = savefileInfo->slotIndex;
struct Chapter* chapter = chapterFindForChamber(savefileInfo->testchamberIndex);
romCopy(chapter->imageData, savefileListSlot->imageData, CHAPTER_IMAGE_SIZE); savefileLoadScreenshot(savefileListSlot->imageData, savefileInfo->screenshot);
savefileListSlot->x = x;
savefileListSlot->y = y;
} }
void savefileListSlotInit(struct SavefileListSlot* savefileListSlot, int x, int y) { void savefileListSlotInit(struct SavefileListSlot* savefileListSlot, int x, int y) {
savefileListSlot->testChamberText = menuBuildText(&gDejaVuSansFont, "Testchamber 00", x + BORDER_WIDTH + 8, y); savefileListSlot->testChamberText = menuBuildText(&gDejaVuSansFont, "Testchamber 00", x + BORDER_WIDTH + 8, y);
savefileListSlot->gameId = NULL;
savefileListSlot->border = menuBuildSolidBorder( savefileListSlot->border = menuBuildSolidBorder(
x, y, BORDER_WIDTH, BORDER_HEIGHT, x, y, BORDER_WIDTH, BORDER_HEIGHT,
x + 5, y + 5, 82, 48 x + BORDER_THICKNESS, y + BORDER_THICKNESS, 82, 48
); );
savefileListSlot->x = x; savefileListSlot->x = x;
savefileListSlot->y = y; savefileListSlot->y = y;
savefileListSlot->imageData = malloc(CHAPTER_IMAGE_SIZE); savefileListSlot->imageData = malloc(THUMBANIL_IMAGE_SIZE);
savefileListSlot->slotIndex = -1; savefileListSlot->slotIndex = -1;
} }
@ -208,28 +226,67 @@ void savefileListRender(struct SavefileListMenu* savefileList, struct RenderStat
menuSetRenderColor(renderState, savefileList->indexOffset + i == savefileList->selectedSave, &gSelectionOrange, &gColorWhite); menuSetRenderColor(renderState, savefileList->indexOffset + i == savefileList->selectedSave, &gSelectionOrange, &gColorWhite);
renderStateInlineBranch(renderState, slot->testChamberText); renderStateInlineBranch(renderState, slot->testChamberText);
renderStateInlineBranch(renderState, slot->gameId);
} }
gSPDisplayList(renderState->dl++, ui_material_revert_list[DEJAVU_SANS_INDEX]); gSPDisplayList(renderState->dl++, ui_material_revert_list[DEJAVU_SANS_INDEX]);
gSPDisplayList(renderState->dl++, ui_material_list[IMAGE_COPY_INDEX]);
for (int i = 0; i < MAX_VISIBLE_SLOTS; ++i) { for (int i = 0; i < MAX_VISIBLE_SLOTS; ++i) {
struct SavefileListSlot* slot = &savefileList->slots[i]; struct SavefileListSlot* slot = &savefileList->slots[i];
if (slot->slotIndex < 0) { if (slot->slotIndex < 0) {
continue; continue;
} }
graphicsCopyImage( gDPLoadTextureTile(
renderState, renderState->dl++,
slot->imageData, K0_TO_PHYS(slot->imageData),
CHAPTER_IMAGE_WIDTH, CHAPTER_IMAGE_HEIGHT, G_IM_FMT_RGBA, G_IM_SIZ_16b,
SAVE_SLOT_IMAGE_W, SAVE_SLOT_IMAGE_H,
0, 0, 0, 0,
slot->x + 5, slot->y + 5, SAVE_SLOT_IMAGE_W-1, SAVE_SLOT_IMAGE_H-1,
CHAPTER_IMAGE_WIDTH, CHAPTER_IMAGE_HEIGHT, 0,
gColorWhite G_TX_CLAMP, G_TX_CLAMP,
G_TX_NOMASK, G_TX_NOMASK,
G_TX_NOLOD, G_TX_NOLOD
);
gSPTextureRectangle(
renderState->dl++,
(slot->x + BORDER_THICKNESS) << 2, (slot->y + BORDER_THICKNESS) << 2,
(slot->x + BORDER_THICKNESS + SAVE_SLOT_RENDER_W) << 2,
(slot->y + BORDER_THICKNESS + SAVE_SLOT_RENDER_H) << 2,
G_TX_RENDERTILE,
0, 0,
(SAVE_SLOT_IMAGE_W << 10) / SAVE_SLOT_RENDER_W, (SAVE_SLOT_IMAGE_H << 10) / SAVE_SLOT_RENDER_H
); );
} }
gSPDisplayList(renderState->dl++, ui_material_revert_list[IMAGE_COPY_INDEX]);
gDPPipeSync(renderState->dl++); gDPPipeSync(renderState->dl++);
gDPSetScissor(renderState->dl++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WD, SCREEN_HT); gDPSetScissor(renderState->dl++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WD, SCREEN_HT);
} }
u16 gScreenGrabBuffer[SAVE_SLOT_IMAGE_W * SAVE_SLOT_IMAGE_H];
#define IMAGE_SCALE_FACTOR (int)((SCREEN_WD << 16) / SAVE_SLOT_IMAGE_W)
#define SCALE_TO_SOURCE(value) ((IMAGE_SCALE_FACTOR * (value)) >> 16)
void savefileGrabScreenshot() {
u16* cfb = osViGetCurrentFramebuffer();
u16* dst = gScreenGrabBuffer;
for (int y = 0; y < SAVE_SLOT_IMAGE_H; ++y) {
for (int x = 0; x < SAVE_SLOT_IMAGE_W; ++x) {
int srcX = SCALE_TO_SOURCE(x);
int srcY = SCALE_TO_SOURCE(y);
*dst = cfb[srcX + srcY * SCREEN_WD];
++dst;
}
}
}

View file

@ -6,10 +6,13 @@
#include "../savefile/savefile.h" #include "../savefile/savefile.h"
#include "./new_game_menu.h" #include "./new_game_menu.h"
extern u16 gScreenGrabBuffer[SAVE_SLOT_IMAGE_W * SAVE_SLOT_IMAGE_H];
struct SavefileInfo { struct SavefileInfo {
short slotIndex; short slotIndex;
short testchamberIndex; short testchamberIndex;
char* savefileName; char* savefileName;
u16* screenshot;
}; };
struct SavefileListSlot { struct SavefileListSlot {
@ -39,5 +42,6 @@ void savefileUseList(struct SavefileListMenu* savefileList, char* title, struct
enum MenuDirection savefileListUpdate(struct SavefileListMenu* savefileList); enum MenuDirection savefileListUpdate(struct SavefileListMenu* savefileList);
void savefileListRender(struct SavefileListMenu* savefileList, struct RenderState* renderState, struct GraphicsTask* task); void savefileListRender(struct SavefileListMenu* savefileList, struct RenderState* renderState, struct GraphicsTask* task);
void savefileGrabScreenshot();
#endif #endif

View file

@ -39,7 +39,6 @@ void savefileNew() {
gSaveData.audio.musicVolume = 0xFF; gSaveData.audio.musicVolume = 0xFF;
} }
#define SRAM_START_ADDR 0x08000000
#define SRAM_latency 0x5 #define SRAM_latency 0x5
#define SRAM_pulse 0x0c #define SRAM_pulse 0x0c
#define SRAM_pageSize 0xd #define SRAM_pageSize 0xd
@ -297,6 +296,16 @@ int savefileOldestSlot() {
return result; return result;
} }
int savefileFirstFreeSlot() {
for (int i = 1; i < MAX_SAVE_SLOTS; ++i) {
if (gSaveData.saveSlotMetadata[i].testChamber == NO_TEST_CHAMBER) {
return i;
}
}
return SAVEFILE_NO_SLOT;
}
void savefileLoadGame(int slot, Checkpoint checkpoint) { void savefileLoadGame(int slot, Checkpoint checkpoint) {
OSTimer timer; OSTimer timer;
@ -318,4 +327,31 @@ void savefileLoadGame(int slot, Checkpoint checkpoint) {
osSetTimer(&timer, SRAM_CHUNK_DELAY, 0, &timerQueue, 0); osSetTimer(&timer, SRAM_CHUNK_DELAY, 0, &timerQueue, 0);
(void) osRecvMesg(&timerQueue, NULL, OS_MESG_BLOCK); (void) osRecvMesg(&timerQueue, NULL, OS_MESG_BLOCK);
}
void savefileLoadScreenshot(u16* target, u16* location) {
if ((int)location >= SRAM_START_ADDR && (int)location <= (SRAM_START_ADDR + SRAM_SIZE)) {
OSTimer timer;
OSIoMesg dmaIoMesgBuf;
dmaIoMesgBuf.hdr.pri = OS_MESG_PRI_HIGH;
dmaIoMesgBuf.hdr.retQueue = &dmaMessageQ;
dmaIoMesgBuf.dramAddr = target;
dmaIoMesgBuf.devAddr = (u32)location;
dmaIoMesgBuf.size = THUMBANIL_IMAGE_SIZE;
osInvalDCache(target, THUMBANIL_IMAGE_SIZE);
if (osEPiStartDma(&gSramHandle, &dmaIoMesgBuf, OS_READ) == -1)
{
savefileNew();
return;
}
(void) osRecvMesg(&dmaMessageQ, NULL, OS_MESG_BLOCK);
osSetTimer(&timer, SRAM_CHUNK_DELAY, 0, &timerQueue, 0);
(void) osRecvMesg(&timerQueue, NULL, OS_MESG_BLOCK);
} else {
memCopy(target, location, THUMBANIL_IMAGE_SIZE);
}
} }

View file

@ -4,11 +4,21 @@
#include "./checkpoint.h" #include "./checkpoint.h"
#include "../controls/controller_actions.h" #include "../controls/controller_actions.h"
#define SRAM_START_ADDR 0x08000000
#define SRAM_SIZE 0x8000 #define SRAM_SIZE 0x8000
#define THUMBNAIL_IMAGE_SIZE 2048 #define SAVEFILE_NO_SLOT -1
#define SAVE_SLOT_SIZE (MAX_CHECKPOINT_SIZE + THUMBNAIL_IMAGE_SIZE) #define SAVE_SLOT_IMAGE_W 36
#define SAVE_SLOT_IMAGE_H 27
#define THUMBANIL_IMAGE_SIZE (SAVE_SLOT_IMAGE_W * SAVE_SLOT_IMAGE_H * sizeof(u16))
#define THUMBNAIL_IMAGE_SPACE 2048
#define SAVE_SLOT_SIZE (MAX_CHECKPOINT_SIZE + THUMBNAIL_IMAGE_SPACE)
#define SCREEN_SHOT_SRAM(slotIndex) (((slotIndex) + 1) * SAVE_SLOT_SIZE + MAX_CHECKPOINT_SIZE)
#define SAVEFILE_HEADER 0xDEAE #define SAVEFILE_HEADER 0xDEAE
@ -74,6 +84,10 @@ int savefileListSaves(struct SaveSlotInfo* slots, int includeAuto);
int savefileNextTestSubject(); int savefileNextTestSubject();
int savefileSuggestedSlot(int testSubject); int savefileSuggestedSlot(int testSubject);
int savefileOldestSlot(); int savefileOldestSlot();
int savefileFirstFreeSlot();
void savefileLoadGame(int slot, Checkpoint checkpoint); void savefileLoadGame(int slot, Checkpoint checkpoint);
void savefileLoadScreenshot(u16* target, u16* location);
#endif #endif

View file

@ -474,6 +474,7 @@ void sceneUpdate(struct Scene* scene) {
return; return;
} else if (controllerActionGet(ControllerActionPause)) { } else if (controllerActionGet(ControllerActionPause)) {
savefileGrabScreenshot();
gGameMenu.state = GameMenuStateLanding; gGameMenu.state = GameMenuStateLanding;
gGameMenu.landingMenu.selectedItem = 0; gGameMenu.landingMenu.selectedItem = 0;
} }