mirror of https://github.com/mgba-emu/mgba.git
GBA: Move screenshot functionality from Thread to Serialize
This commit is contained in:
parent
03d97baeec
commit
532261af2c
|
@ -432,3 +432,25 @@ int GBARewind(struct GBAThread* thread, int nStates) {
|
||||||
void GBARewindAll(struct GBAThread* thread) {
|
void GBARewindAll(struct GBAThread* thread) {
|
||||||
GBARewind(thread, thread->rewindBufferSize);
|
GBARewind(thread, thread->rewindBufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GBATakeScreenshot(struct GBA* gba, struct VDir* dir) {
|
||||||
|
#ifdef USE_PNG
|
||||||
|
unsigned stride;
|
||||||
|
const void* pixels = 0;
|
||||||
|
struct VFile* vf = VDirOptionalOpenIncrementFile(dir, gba->activeFile, "screenshot", "-", ".png", O_CREAT | O_TRUNC | O_WRONLY);
|
||||||
|
bool success = false;
|
||||||
|
if (vf) {
|
||||||
|
gba->video.renderer->getPixels(gba->video.renderer, &stride, &pixels);
|
||||||
|
png_structp png = PNGWriteOpen(vf);
|
||||||
|
png_infop info = PNGWriteHeader(png, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS);
|
||||||
|
success = PNGWritePixels(png, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, stride, pixels);
|
||||||
|
PNGWriteClose(png, info);
|
||||||
|
vf->close(vf);
|
||||||
|
}
|
||||||
|
if (success) {
|
||||||
|
GBALog(gba, GBA_LOG_STATUS, "Screenshot saved");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
GBALog(gba, GBA_LOG_STATUS, "Failed to take screenshot");
|
||||||
|
}
|
||||||
|
|
|
@ -345,4 +345,6 @@ void GBARewindSettingsChanged(struct GBAThread* thread, int newCapacity, int new
|
||||||
int GBARewind(struct GBAThread* thread, int nStates);
|
int GBARewind(struct GBAThread* thread, int nStates);
|
||||||
void GBARewindAll(struct GBAThread* thread);
|
void GBARewindAll(struct GBAThread* thread);
|
||||||
|
|
||||||
|
void GBATakeScreenshot(struct GBA* gba, struct VDir* dir);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#include "debugger/debugger.h"
|
#include "debugger/debugger.h"
|
||||||
|
|
||||||
#include "util/patch.h"
|
#include "util/patch.h"
|
||||||
#include "util/png-io.h"
|
|
||||||
#include "util/vfs.h"
|
#include "util/vfs.h"
|
||||||
|
|
||||||
#include "platform/commandline.h"
|
#include "platform/commandline.h"
|
||||||
|
@ -754,22 +753,9 @@ struct GBAThread* GBAThreadGetContext(void) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_PNG
|
|
||||||
void GBAThreadTakeScreenshot(struct GBAThread* threadContext) {
|
void GBAThreadTakeScreenshot(struct GBAThread* threadContext) {
|
||||||
unsigned stride;
|
GBATakeScreenshot(threadContext->gba, threadContext->stateDir);
|
||||||
const void* pixels = 0;
|
|
||||||
struct VFile* vf = VDirOptionalOpenIncrementFile(threadContext->stateDir, threadContext->gba->activeFile, "screenshot", "-", ".png", O_CREAT | O_TRUNC | O_WRONLY);
|
|
||||||
threadContext->gba->video.renderer->getPixels(threadContext->gba->video.renderer, &stride, &pixels);
|
|
||||||
png_structp png = PNGWriteOpen(vf);
|
|
||||||
png_infop info = PNGWriteHeader(png, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS);
|
|
||||||
bool success = PNGWritePixels(png, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, stride, pixels);
|
|
||||||
PNGWriteClose(png, info);
|
|
||||||
vf->close(vf);
|
|
||||||
if (success) {
|
|
||||||
GBALog(threadContext->gba, GBA_LOG_STATUS, "Screenshot saved");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
struct GBAThread* GBAThreadGetContext(void) {
|
struct GBAThread* GBAThreadGetContext(void) {
|
||||||
|
|
|
@ -167,3 +167,95 @@ struct VFile* VDirOptionalOpenFile(struct VDir* dir, const char* realPath, const
|
||||||
}
|
}
|
||||||
return vf;
|
return vf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct VFile* VDirOptionalOpenIncrementFile(struct VDir* dir, const char* realPath, const char* prefix, const char* infix, const char* suffix, int mode) {
|
||||||
|
char path[PATH_MAX];
|
||||||
|
path[PATH_MAX - 1] = '\0';
|
||||||
|
char realPrefix[PATH_MAX];
|
||||||
|
realPrefix[PATH_MAX - 1] = '\0';
|
||||||
|
if (!dir) {
|
||||||
|
if (!realPath) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const char* separatorPoint = strrchr(realPath, '/');
|
||||||
|
const char* dotPoint;
|
||||||
|
size_t len;
|
||||||
|
if (!separatorPoint) {
|
||||||
|
strcpy(path, "./");
|
||||||
|
separatorPoint = realPath;
|
||||||
|
dotPoint = strrchr(realPath, '.');
|
||||||
|
} else {
|
||||||
|
path[0] = '\0';
|
||||||
|
dotPoint = strrchr(separatorPoint, '.');
|
||||||
|
|
||||||
|
if (separatorPoint - realPath + 1 >= PATH_MAX - 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = separatorPoint - realPath;
|
||||||
|
strncat(path, realPath, len);
|
||||||
|
path[len] = '\0';
|
||||||
|
++separatorPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dotPoint - realPath + 1 >= PATH_MAX - 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dotPoint >= separatorPoint) {
|
||||||
|
len = dotPoint - separatorPoint;
|
||||||
|
} else {
|
||||||
|
len = PATH_MAX - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(realPrefix, separatorPoint, len);
|
||||||
|
realPrefix[len] = '\0';
|
||||||
|
|
||||||
|
prefix = realPrefix;
|
||||||
|
dir = VDirOpen(path);
|
||||||
|
}
|
||||||
|
if (!dir) {
|
||||||
|
// This shouldn't be possible
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
dir->rewind(dir);
|
||||||
|
struct VDirEntry* dirent;
|
||||||
|
size_t prefixLen = strlen(prefix);
|
||||||
|
size_t infixLen = strlen(infix);
|
||||||
|
unsigned next = 0;
|
||||||
|
while ((dirent = dir->listNext(dir))) {
|
||||||
|
const char* filename = dirent->name(dirent);
|
||||||
|
char* dotPoint = strrchr(filename, '.');
|
||||||
|
size_t len = strlen(filename);
|
||||||
|
if (dotPoint) {
|
||||||
|
len = (dotPoint - filename);
|
||||||
|
}
|
||||||
|
const char* separator = strnrstr(filename, infix, len);
|
||||||
|
if (!separator) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
len = separator - filename;
|
||||||
|
if (len != prefixLen) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strncmp(filename, prefix, prefixLen) == 0) {
|
||||||
|
int nlen;
|
||||||
|
separator += infixLen;
|
||||||
|
snprintf(path, PATH_MAX - 1, "%%u%s%%n", suffix);
|
||||||
|
unsigned increment;
|
||||||
|
if (sscanf(separator, path, &increment, &nlen) < 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
len = strlen(separator);
|
||||||
|
if (nlen < (ssize_t) len) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (next <= increment) {
|
||||||
|
next = increment + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
snprintf(path, PATH_MAX - 1, "%s%s%u%s", prefix, infix, next, suffix);
|
||||||
|
path[PATH_MAX - 1] = '\0';
|
||||||
|
return dir->openFile(dir, path, mode);
|
||||||
|
}
|
||||||
|
|
|
@ -58,98 +58,6 @@ struct VDir* VDirOpen(const char* path) {
|
||||||
return &vd->d;
|
return &vd->d;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VFile* VDirOptionalOpenIncrementFile(struct VDir* dir, const char* realPath, const char* prefix, const char* infix, const char* suffix, int mode) {
|
|
||||||
char path[PATH_MAX];
|
|
||||||
path[PATH_MAX - 1] = '\0';
|
|
||||||
char realPrefix[PATH_MAX];
|
|
||||||
realPrefix[PATH_MAX - 1] = '\0';
|
|
||||||
if (!dir) {
|
|
||||||
if (!realPath) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
const char* separatorPoint = strrchr(realPath, '/');
|
|
||||||
const char* dotPoint;
|
|
||||||
size_t len;
|
|
||||||
if (!separatorPoint) {
|
|
||||||
strcpy(path, "./");
|
|
||||||
separatorPoint = realPath;
|
|
||||||
dotPoint = strrchr(realPath, '.');
|
|
||||||
} else {
|
|
||||||
path[0] = '\0';
|
|
||||||
dotPoint = strrchr(separatorPoint, '.');
|
|
||||||
|
|
||||||
if (separatorPoint - realPath + 1 >= PATH_MAX - 1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = separatorPoint - realPath;
|
|
||||||
strncat(path, realPath, len);
|
|
||||||
path[len] = '\0';
|
|
||||||
++separatorPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dotPoint - realPath + 1 >= PATH_MAX - 1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dotPoint >= separatorPoint) {
|
|
||||||
len = dotPoint - separatorPoint;
|
|
||||||
} else {
|
|
||||||
len = PATH_MAX - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
strncpy(realPrefix, separatorPoint, len);
|
|
||||||
realPrefix[len] = '\0';
|
|
||||||
|
|
||||||
prefix = realPrefix;
|
|
||||||
dir = VDirOpen(path);
|
|
||||||
}
|
|
||||||
if (!dir) {
|
|
||||||
// This shouldn't be possible
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
dir->rewind(dir);
|
|
||||||
struct VDirEntry* dirent;
|
|
||||||
size_t prefixLen = strlen(prefix);
|
|
||||||
size_t infixLen = strlen(infix);
|
|
||||||
unsigned next = 0;
|
|
||||||
while ((dirent = dir->listNext(dir))) {
|
|
||||||
const char* filename = dirent->name(dirent);
|
|
||||||
char* dotPoint = strrchr(filename, '.');
|
|
||||||
size_t len = strlen(filename);
|
|
||||||
if (dotPoint) {
|
|
||||||
len = (dotPoint - filename);
|
|
||||||
}
|
|
||||||
const char* separator = strnrstr(filename, infix, len);
|
|
||||||
if (!separator) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
len = separator - filename;
|
|
||||||
if (len != prefixLen) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (strncmp(filename, prefix, prefixLen) == 0) {
|
|
||||||
int nlen;
|
|
||||||
separator += infixLen;
|
|
||||||
snprintf(path, PATH_MAX - 1, "%%u%s%%n", suffix);
|
|
||||||
unsigned increment;
|
|
||||||
if (sscanf(separator, path, &increment, &nlen) < 1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
len = strlen(separator);
|
|
||||||
if (nlen < (ssize_t) len) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (next <= increment) {
|
|
||||||
next = increment + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
snprintf(path, PATH_MAX - 1, "%s%s%u%s", prefix, infix, next, suffix);
|
|
||||||
path[PATH_MAX - 1] = '\0';
|
|
||||||
return dir->openFile(dir, path, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _vdClose(struct VDir* vd) {
|
bool _vdClose(struct VDir* vd) {
|
||||||
struct VDirDE* vdde = (struct VDirDE*) vd;
|
struct VDirDE* vdde = (struct VDirDE*) vd;
|
||||||
if (closedir(vdde->de) < 0) {
|
if (closedir(vdde->de) < 0) {
|
||||||
|
|
Loading…
Reference in New Issue