GUI: Make savestate screens show the relevant savestate picture

This commit is contained in:
Jeffrey Pfau 2015-09-03 01:58:50 -07:00
parent 9b14cc607d
commit cb8d60e211
5 changed files with 72 additions and 5 deletions

View File

@ -10,6 +10,8 @@
#include "util/gui/file-select.h"
#include "util/gui/font.h"
#include "util/gui/menu.h"
#include "util/memory.h"
#include "util/png-io.h"
#include "util/vfs.h"
enum {
@ -30,13 +32,46 @@ enum {
RUNNER_STATE_9 = 0x90000,
};
static void _drawBackground(struct GUIBackground* background) {
static void _drawBackground(struct GUIBackground* background, void* context) {
UNUSED(context);
struct GBAGUIBackground* gbaBackground = (struct GBAGUIBackground*) background;
if (gbaBackground->p->drawFrame) {
gbaBackground->p->drawFrame(gbaBackground->p, true);
}
}
static void _drawState(struct GUIBackground* background, void* id) {
struct GBAGUIBackground* gbaBackground = (struct GBAGUIBackground*) background;
int stateId = ((int) id) >> 16;
if (gbaBackground->p->drawScreenshot) {
struct VFile* vf = GBAGetState(gbaBackground->p->context.gba, 0, stateId, false);
uint32_t* pixels = anonymousMemoryMap(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4);
bool success = false;
if (vf && isPNG(vf) && pixels) {
png_structp png = PNGReadOpen(vf, PNG_HEADER_BYTES);
png_infop info = png_create_info_struct(png);
png_infop end = png_create_info_struct(png);
if (png && info && end) {
success = PNGReadHeader(png, info);
success = success && PNGReadPixels(png, info, pixels, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, VIDEO_HORIZONTAL_PIXELS);
success = success && PNGReadFooter(png, end);
}
PNGReadClose(png, info, end);
}
if (vf) {
vf->close(vf);
}
if (success) {
gbaBackground->p->drawScreenshot(gbaBackground->p, pixels, true);
} else if (gbaBackground->p->drawFrame) {
gbaBackground->p->drawFrame(gbaBackground->p, true);
}
if (pixels) {
mappedMemoryFree(pixels, VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4);
}
}
}
static void _updateLux(struct GBALuminanceSource* lux) {
UNUSED(lux);
}
@ -72,6 +107,12 @@ void GBAGUIDeinit(struct GBAGUIRunner* runner) {
}
void GBAGUIRunloop(struct GBAGUIRunner* runner) {
struct GBAGUIBackground drawState = {
.d = {
.draw = _drawState
},
.p = runner
};
struct GUIMenu pauseMenu = {
.title = "Game Paused",
.index = 0,
@ -80,12 +121,12 @@ void GBAGUIRunloop(struct GBAGUIRunner* runner) {
struct GUIMenu stateSaveMenu = {
.title = "Save state",
.index = 0,
.background = &runner->background.d
.background = &drawState.d
};
struct GUIMenu stateLoadMenu = {
.title = "Load state",
.index = 0,
.background = &runner->background.d
.background = &drawState.d
};
GUIMenuItemListInit(&pauseMenu.items, 0);
GUIMenuItemListInit(&stateSaveMenu.items, 9);

View File

@ -37,6 +37,7 @@ struct GBAGUIRunner {
void (*gameUnloaded)(struct GBAGUIRunner*);
void (*prepareForFrame)(struct GBAGUIRunner*);
void (*drawFrame)(struct GBAGUIRunner*, bool faded);
void (*drawScreenshot)(struct GBAGUIRunner*, const uint32_t* pixels, bool faded);
void (*paused)(struct GBAGUIRunner*);
void (*unpaused)(struct GBAGUIRunner*);
uint16_t (*pollGameInput)(struct GBAGUIRunner*);

View File

@ -112,15 +112,39 @@ static void _gameUnloaded(struct GBAGUIRunner* runner) {
}
static void _drawFrame(struct GBAGUIRunner* runner, bool faded) {
UNUSED(runner);
GSPGPU_FlushDataCache(0, renderer.outputBuffer, 256 * VIDEO_VERTICAL_PIXELS * 2);
GX_SetDisplayTransfer(0, renderer.outputBuffer, GX_BUFFER_DIM(256, VIDEO_VERTICAL_PIXELS), tex->data, GX_BUFFER_DIM(256, VIDEO_VERTICAL_PIXELS), 0x000002202);
gspWaitForPPF();
GSPGPU_FlushDataCache(0, tex->data, 256 * VIDEO_VERTICAL_PIXELS * 2);
sf2d_draw_texture_scale_blend(tex, 40, 296, 1, -1, 0xFFFFFF3F | (faded ? 0 : 0xC0));
#if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF
if (!hasSound) {
blip_clear(runner->context.gba->audio.left);
blip_clear(runner->context.gba->audio.right);
}
#endif
}
static void _drawScreenshot(struct GBAGUIRunner* runner, const uint32_t* pixels, bool faded) {
UNUSED(runner);
u16* newPixels = linearMemAlign(256 * VIDEO_VERTICAL_PIXELS * 2, 0x80);
unsigned y, x;
for (y = 0; y < VIDEO_VERTICAL_PIXELS; ++y) {
for (x = 0; x < VIDEO_HORIZONTAL_PIXELS; ++x) {
u16 pixel = (*pixels >> 19) & 0x1F;
pixel |= (*pixels >> 5) & 0x7C0;
pixel |= (*pixels << 8) & 0xF800;
newPixels[y * 256 + x] = pixel;
++pixels;
}
memset(&newPixels[y * 256 + VIDEO_HORIZONTAL_PIXELS], 0, 32);
}
GSPGPU_FlushDataCache(0, (void*) newPixels, VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 2);
GX_SetDisplayTransfer(0, (void*) newPixels, GX_BUFFER_DIM(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS), tex->data, GX_BUFFER_DIM(256, VIDEO_VERTICAL_PIXELS), 0x000002202);
gspWaitForPPF();
linearFree(newPixels);
GSPGPU_FlushDataCache(0, (void*) tex->data, 256 * VIDEO_VERTICAL_PIXELS * 2);
sf2d_draw_texture_scale_blend(tex, 40, 296, 1, -1, 0xFFFFFF3F | (faded ? 0 : 0xC0));
}
@ -264,6 +288,7 @@ int main() {
.gameUnloaded = _gameUnloaded,
.prepareForFrame = 0,
.drawFrame = _drawFrame,
.drawScreenshot = _drawScreenshot,
.paused = _gameUnloaded,
.unpaused = _gameLoaded,
.pollGameInput = _pollGameInput

View File

@ -29,7 +29,7 @@ enum GUIInput {
};
struct GUIBackground {
void (*draw)(struct GUIBackground*);
void (*draw)(struct GUIBackground*, void* context);
};
struct GUIParams {

View File

@ -71,7 +71,7 @@ enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* men
params->drawStart();
if (menu->background) {
menu->background->draw(menu->background);
menu->background->draw(menu->background, GUIMenuItemListGetPointer(&menu->items, menu->index)->data);
}
if (params->guiPrepare) {
params->guiPrepare();