Work on new save menu
This commit is contained in:
parent
37723bc35a
commit
42caf31ea8
|
@ -1,6 +1,7 @@
|
|||
|
||||
materials:
|
||||
default_ui:
|
||||
gDPSetCycleType: G_CYC_1CYCLE
|
||||
gSPGeometryMode:
|
||||
clear: [G_ZBUFFER, G_LIGHTING, G_SHADE]
|
||||
gDPSetTextureLUT: G_TT_NONE
|
||||
|
@ -91,3 +92,11 @@ materials:
|
|||
b: 0
|
||||
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
|
||||
|
|
|
@ -12,22 +12,6 @@ void loadGamePopulate(struct LoadGameMenu* loadGame) {
|
|||
|
||||
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) {
|
||||
savefileInfo[i].slotIndex = saveSlots[i].saveSlot;
|
||||
savefileInfo[i].testchamberIndex = saveSlots[i].testChamber;
|
||||
|
|
|
@ -13,33 +13,20 @@ void saveGamePopulate(struct SaveGameMenu* saveGame) {
|
|||
|
||||
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) {
|
||||
savefileInfo[i].slotIndex = saveSlots[i].saveSlot;
|
||||
savefileInfo[i].testchamberIndex = saveSlots[i].testChamber;
|
||||
savefileInfo[i].savefileName = NULL;
|
||||
savefileInfo[i].screenshot = (u16*)SCREEN_SHOT_SRAM(saveSlots[i].saveSlot);
|
||||
}
|
||||
|
||||
if (numberOfSaves < MAX_USER_SAVE_SLOTS) {
|
||||
// TODO
|
||||
savefileInfo[numberOfSaves].slotIndex = 0;
|
||||
int freeSlot = savefileFirstFreeSlot();
|
||||
|
||||
if (freeSlot != SAVEFILE_NO_SLOT) {
|
||||
savefileInfo[numberOfSaves].slotIndex = freeSlot;
|
||||
savefileInfo[numberOfSaves].savefileName = "NEW SAVE";
|
||||
savefileInfo[numberOfSaves].testchamberIndex = gCurrentLevelIndex;
|
||||
savefileInfo[numberOfSaves].screenshot = gScreenGrabBuffer;
|
||||
++numberOfSaves;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,12 @@
|
|||
|
||||
#include "../build/assets/materials/ui.h"
|
||||
|
||||
#define BORDER_WIDTH 92
|
||||
#define BORDER_HEIGHT 58
|
||||
#define SAVE_SLOT_RENDER_W (SAVE_SLOT_IMAGE_W * 2)
|
||||
#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)
|
||||
|
||||
|
@ -17,28 +21,42 @@ void savefileListSlotUseInfo(struct SavefileListSlot* savefileListSlot, struct S
|
|||
char message[16];
|
||||
sprintf(message, "Testchamber %02d", savefileInfo->testchamberIndex);
|
||||
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(
|
||||
x, y, BORDER_WIDTH, BORDER_HEIGHT,
|
||||
x + 5, y + 5, 82, 48,
|
||||
x, y,
|
||||
BORDER_WIDTH, BORDER_HEIGHT,
|
||||
x + BORDER_THICKNESS, y + BORDER_THICKNESS,
|
||||
SAVE_SLOT_IMAGE_W * 2, SAVE_SLOT_IMAGE_H * 2,
|
||||
savefileListSlot->border
|
||||
);
|
||||
savefileListSlot->slotIndex = savefileInfo->slotIndex;
|
||||
struct Chapter* chapter = chapterFindForChamber(savefileInfo->testchamberIndex);
|
||||
romCopy(chapter->imageData, savefileListSlot->imageData, CHAPTER_IMAGE_SIZE);
|
||||
savefileListSlot->x = x;
|
||||
savefileListSlot->y = y;
|
||||
|
||||
savefileLoadScreenshot(savefileListSlot->imageData, savefileInfo->screenshot);
|
||||
}
|
||||
|
||||
void savefileListSlotInit(struct SavefileListSlot* savefileListSlot, int x, int y) {
|
||||
savefileListSlot->testChamberText = menuBuildText(&gDejaVuSansFont, "Testchamber 00", x + BORDER_WIDTH + 8, y);
|
||||
savefileListSlot->gameId = NULL;
|
||||
savefileListSlot->border = menuBuildSolidBorder(
|
||||
x, y, BORDER_WIDTH, BORDER_HEIGHT,
|
||||
x + 5, y + 5, 82, 48
|
||||
x + BORDER_THICKNESS, y + BORDER_THICKNESS, 82, 48
|
||||
);
|
||||
|
||||
savefileListSlot->x = x;
|
||||
savefileListSlot->y = y;
|
||||
savefileListSlot->imageData = malloc(CHAPTER_IMAGE_SIZE);
|
||||
savefileListSlot->imageData = malloc(THUMBANIL_IMAGE_SIZE);
|
||||
savefileListSlot->slotIndex = -1;
|
||||
}
|
||||
|
||||
|
@ -208,28 +226,67 @@ void savefileListRender(struct SavefileListMenu* savefileList, struct RenderStat
|
|||
menuSetRenderColor(renderState, savefileList->indexOffset + i == savefileList->selectedSave, &gSelectionOrange, &gColorWhite);
|
||||
|
||||
renderStateInlineBranch(renderState, slot->testChamberText);
|
||||
renderStateInlineBranch(renderState, slot->gameId);
|
||||
}
|
||||
|
||||
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) {
|
||||
struct SavefileListSlot* slot = &savefileList->slots[i];
|
||||
|
||||
if (slot->slotIndex < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
graphicsCopyImage(
|
||||
renderState,
|
||||
slot->imageData,
|
||||
CHAPTER_IMAGE_WIDTH, CHAPTER_IMAGE_HEIGHT,
|
||||
|
||||
gDPLoadTextureTile(
|
||||
renderState->dl++,
|
||||
K0_TO_PHYS(slot->imageData),
|
||||
G_IM_FMT_RGBA, G_IM_SIZ_16b,
|
||||
SAVE_SLOT_IMAGE_W, SAVE_SLOT_IMAGE_H,
|
||||
0, 0,
|
||||
slot->x + 5, slot->y + 5,
|
||||
CHAPTER_IMAGE_WIDTH, CHAPTER_IMAGE_HEIGHT,
|
||||
gColorWhite
|
||||
SAVE_SLOT_IMAGE_W-1, SAVE_SLOT_IMAGE_H-1,
|
||||
0,
|
||||
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++);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,10 +6,13 @@
|
|||
#include "../savefile/savefile.h"
|
||||
#include "./new_game_menu.h"
|
||||
|
||||
extern u16 gScreenGrabBuffer[SAVE_SLOT_IMAGE_W * SAVE_SLOT_IMAGE_H];
|
||||
|
||||
struct SavefileInfo {
|
||||
short slotIndex;
|
||||
short testchamberIndex;
|
||||
char* savefileName;
|
||||
u16* screenshot;
|
||||
};
|
||||
|
||||
struct SavefileListSlot {
|
||||
|
@ -39,5 +42,6 @@ void savefileUseList(struct SavefileListMenu* savefileList, char* title, struct
|
|||
enum MenuDirection savefileListUpdate(struct SavefileListMenu* savefileList);
|
||||
void savefileListRender(struct SavefileListMenu* savefileList, struct RenderState* renderState, struct GraphicsTask* task);
|
||||
|
||||
void savefileGrabScreenshot();
|
||||
|
||||
#endif
|
|
@ -39,7 +39,6 @@ void savefileNew() {
|
|||
gSaveData.audio.musicVolume = 0xFF;
|
||||
}
|
||||
|
||||
#define SRAM_START_ADDR 0x08000000
|
||||
#define SRAM_latency 0x5
|
||||
#define SRAM_pulse 0x0c
|
||||
#define SRAM_pageSize 0xd
|
||||
|
@ -297,6 +296,16 @@ int savefileOldestSlot() {
|
|||
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) {
|
||||
OSTimer timer;
|
||||
|
||||
|
@ -318,4 +327,31 @@ void savefileLoadGame(int slot, Checkpoint checkpoint) {
|
|||
|
||||
osSetTimer(&timer, SRAM_CHUNK_DELAY, 0, &timerQueue, 0);
|
||||
(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);
|
||||
}
|
||||
}
|
|
@ -4,11 +4,21 @@
|
|||
#include "./checkpoint.h"
|
||||
#include "../controls/controller_actions.h"
|
||||
|
||||
#define SRAM_START_ADDR 0x08000000
|
||||
#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
|
||||
|
||||
|
@ -74,6 +84,10 @@ int savefileListSaves(struct SaveSlotInfo* slots, int includeAuto);
|
|||
int savefileNextTestSubject();
|
||||
int savefileSuggestedSlot(int testSubject);
|
||||
int savefileOldestSlot();
|
||||
|
||||
int savefileFirstFreeSlot();
|
||||
|
||||
void savefileLoadGame(int slot, Checkpoint checkpoint);
|
||||
void savefileLoadScreenshot(u16* target, u16* location);
|
||||
|
||||
#endif
|
|
@ -474,6 +474,7 @@ void sceneUpdate(struct Scene* scene) {
|
|||
|
||||
return;
|
||||
} else if (controllerActionGet(ControllerActionPause)) {
|
||||
savefileGrabScreenshot();
|
||||
gGameMenu.state = GameMenuStateLanding;
|
||||
gGameMenu.landingMenu.selectedItem = 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue