GBA: Add savestte creation time to a savestate

This commit is contained in:
Jeffrey Pfau 2015-12-28 04:27:30 -05:00
parent 5c007289e4
commit 63e1875f6b
5 changed files with 60 additions and 14 deletions

View File

@ -15,6 +15,7 @@
#include "util/vfs.h"
#include <fcntl.h>
#include <sys/time.h>
#ifdef USE_PNG
#include "util/png-io.h"
@ -24,10 +25,6 @@
const uint32_t GBA_SAVESTATE_MAGIC = 0x01000000;
struct GBAExtdata {
struct GBAExtdataItem data[EXTDATA_MAX];
};
struct GBABundledState {
struct GBASerializedState* state;
struct GBAExtdata* extdata;
@ -78,6 +75,14 @@ void GBASerialize(struct GBA* gba, struct GBASerializedState* state) {
GBAAudioSerialize(&gba->audio, state);
GBASavedataSerialize(&gba->memory.savedata, state);
struct timeval tv;
if (!gettimeofday(&tv, 0)) {
uint64_t usec = tv.tv_usec;
usec += tv.tv_sec * 1000000LL;
STORE_64(usec, 0, &state->creationUsec);
} else {
state->creationUsec = 0;
}
state->associatedStreamId = 0;
if (gba->rr) {
gba->rr->stateSaved(gba->rr, state);
@ -324,7 +329,7 @@ static struct GBASerializedState* _loadPNGState(struct VFile* vf, struct GBAExtd
success = success && PNGReadFooter(png, end);
PNGReadClose(png, info, end);
if (success && extdata) {
if (success) {
struct GBAExtdataItem item = {
.size = VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4,
.data = pixels,

View File

@ -174,7 +174,9 @@ extern const uint32_t GBA_SAVESTATE_MAGIC;
* | 0x002F8 - 0x002FB: CPU prefecth (decode slot)
* | 0x002FC - 0x002FF: CPU prefetch (fetch slot)
* 0x00300 - 0x00303: Associated movie stream ID for record/replay (or 0 if no stream)
* 0x00304 - 0x003FF: Reserved (leave zero)
* 0x00304 - 0x0030F: Reserved (leave zero)
* 0x00310 - 0x00317: Savestate creation time (usec since 1970)
* 0x00318 - 0x003FF: Reserved (leave zero)
* 0x00400 - 0x007FF: I/O memory
* 0x00800 - 0x00BFF: Palette
* 0x00C00 - 0x00FFF: OAM
@ -319,8 +321,11 @@ struct GBASerializedState {
uint32_t cpuPrefetch[2];
uint32_t associatedStreamId;
uint32_t reservedRr[3];
uint32_t reserved[63];
uint64_t creationUsec;
uint32_t reserved[58];
uint16_t io[SIZE_IO >> 1];
uint16_t pram[SIZE_PALETTE_RAM >> 1];
@ -340,13 +345,16 @@ enum GBAExtdataTag {
#define SAVESTATE_SCREENSHOT 1
#define SAVESTATE_SAVEDATA 2
struct GBAExtdata;
struct GBAExtdataItem {
int32_t size;
void* data;
void (*clean)(void*);
};
struct GBAExtdata {
struct GBAExtdataItem data[EXTDATA_MAX];
};
struct VDir;
struct GBAThread;

View File

@ -10,6 +10,7 @@
#include "GamepadButtonEvent.h"
#include "VFileDevice.h"
#include <QDateTime>
#include <QKeyEvent>
#include <QPainter>
@ -174,17 +175,39 @@ void LoadSaveState::loadState(int slot) {
m_slots[slot - 1]->setText(tr("Empty"));
return;
}
VFileDevice vdev(vf);
GBAExtdata extdata;
GBAExtdataInit(&extdata);
GBASerializedState* state = GBAExtractState(vf, &extdata);
vf->seek(vf, 0, SEEK_SET);
if (!state) {
m_slots[slot - 1]->setText(tr("Corrupted"));
GBAExtdataDeinit(&extdata);
return;
}
QDateTime creation(QDateTime::fromMSecsSinceEpoch(state->creationUsec / 1000LL));
QImage stateImage;
stateImage.load(&vdev, "PNG");
GBAExtdataItem item;
if (GBAExtdataGet(&extdata, EXTDATA_SCREENSHOT, &item) && item.size >= VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4) {
stateImage = QImage((uchar*) item.data, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, QImage::Format_ARGB32).rgbSwapped();
}
if (!stateImage.isNull()) {
QPixmap statePixmap;
statePixmap.convertFromImage(stateImage);
m_slots[slot - 1]->setIcon(statePixmap);
m_slots[slot - 1]->setText(QString());
} else {
m_slots[slot - 1]->setText(tr("Slot %1").arg(slot));
}
if (creation.toMSecsSinceEpoch()) {
m_slots[slot - 1]->setText(creation.toString(Qt::DefaultLocaleShortDate));
} else if (stateImage.isNull()) {
m_slots[slot - 1]->setText(tr("Slot %1").arg(slot));
} else {
m_slots[slot - 1]->setText(QString());
}
vf->close(vf);
GBADeallocateState(state);
}
void LoadSaveState::triggerState(int slot) {

View File

@ -42,5 +42,13 @@ void SavestateButton::paintEvent(QPaintEvent*) {
painter.fillRect(full, highlight);
}
painter.setPen(QPen(palette.text(), 0));
painter.drawText(full, Qt::AlignCenter, text());
if (icon().isNull()) {
painter.drawText(full, Qt::AlignCenter, text());
} else {
if (!hasFocus()) {
painter.setPen(QPen(palette.light(), 0));
painter.setCompositionMode(QPainter::CompositionMode_Exclusion);
}
painter.drawText(full, Qt::AlignHCenter | Qt::AlignBottom, text());
}
}

View File

@ -186,10 +186,12 @@ bool PNGReadPixels(png_structp png, png_infop info, void* pixels, unsigned width
pixelData[stride * i * 4 + x * 4 + 3] = row[x * 3];
pixelData[stride * i * 4 + x * 4 + 2] = row[x * 3 + 1];
pixelData[stride * i * 4 + x * 4 + 1] = row[x * 3 + 2];
pixelData[stride * i * 4 + x * 4] = 0xFF;
#else
pixelData[stride * i * 4 + x * 4] = row[x * 3];
pixelData[stride * i * 4 + x * 4 + 1] = row[x * 3 + 1];
pixelData[stride * i * 4 + x * 4 + 2] = row[x * 3 + 2];
pixelData[stride * i * 4 + x * 4 + 3] = 0xFF;
#endif
}
}