GUI: Add fast-forward key

This commit is contained in:
Jeffrey Pfau 2016-08-16 23:24:07 -07:00
parent 400ac04d42
commit 9eb8faf1ba
8 changed files with 62 additions and 10 deletions

View File

@ -7,6 +7,7 @@ Features:
- Threaded rendering mode - Threaded rendering mode
- Libretro: Memory map and achievement support (leiradel) - Libretro: Memory map and achievement support (leiradel)
- GUI: Add UI control remapping - GUI: Add UI control remapping
- GUI: Add fast-forward
Bugfixes: Bugfixes:
- SDL: Fix axes being mapped wrong - SDL: Fix axes being mapped wrong
- GBA Memory: Fix mirror on non-overdumped Classic NES games - GBA Memory: Fix mirror on non-overdumped Classic NES games

View File

@ -63,7 +63,9 @@ static const struct mInputPlatformInfo _mGUIKeyInfo = {
"Right", "Right",
[mGUI_INPUT_INCREASE_BRIGHTNESS] = "Increase solar brightness", [mGUI_INPUT_INCREASE_BRIGHTNESS] = "Increase solar brightness",
[mGUI_INPUT_DECREASE_BRIGHTNESS] = "Decrease solar brightness", [mGUI_INPUT_DECREASE_BRIGHTNESS] = "Decrease solar brightness",
[mGUI_INPUT_SCREEN_MODE] = "Screen mode" [mGUI_INPUT_SCREEN_MODE] = "Screen mode",
[mGUI_INPUT_SCREENSHOT] = "Take screenshot",
[mGUI_INPUT_FAST_FORWARD] = "Fast forward",
}, },
.nKeys = GUI_INPUT_MAX .nKeys = GUI_INPUT_MAX
}; };
@ -344,7 +346,8 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
} }
#endif #endif
uint32_t guiKeys; uint32_t guiKeys;
GUIPollInput(&runner->params, &guiKeys, 0); uint32_t heldKeys;
GUIPollInput(&runner->params, &guiKeys, &heldKeys);
if (guiKeys & (1 << GUI_INPUT_CANCEL)) { if (guiKeys & (1 << GUI_INPUT_CANCEL)) {
break; break;
} }
@ -361,6 +364,14 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
if (guiKeys & (1 << mGUI_INPUT_SCREEN_MODE) && runner->incrementScreenMode) { if (guiKeys & (1 << mGUI_INPUT_SCREEN_MODE) && runner->incrementScreenMode) {
runner->incrementScreenMode(runner); runner->incrementScreenMode(runner);
} }
if (guiKeys & (1 << mGUI_INPUT_SCREENSHOT)) {
mCoreTakeScreenshot(runner->core);
}
if (heldKeys & (1 << mGUI_INPUT_FAST_FORWARD)) {
runner->setFrameLimiter(runner, false);
} else {
runner->setFrameLimiter(runner, true);
}
uint16_t keys = runner->pollGameInput(runner); uint16_t keys = runner->pollGameInput(runner);
if (runner->prepareForFrame) { if (runner->prepareForFrame) {
runner->prepareForFrame(runner); runner->prepareForFrame(runner);

View File

@ -18,6 +18,8 @@ enum mGUIInput {
mGUI_INPUT_INCREASE_BRIGHTNESS = GUI_INPUT_USER_START, mGUI_INPUT_INCREASE_BRIGHTNESS = GUI_INPUT_USER_START,
mGUI_INPUT_DECREASE_BRIGHTNESS, mGUI_INPUT_DECREASE_BRIGHTNESS,
mGUI_INPUT_SCREEN_MODE, mGUI_INPUT_SCREEN_MODE,
mGUI_INPUT_SCREENSHOT,
mGUI_INPUT_FAST_FORWARD,
}; };
struct mGUIBackground { struct mGUIBackground {
@ -64,6 +66,7 @@ struct mGUIRunner {
void (*paused)(struct mGUIRunner*); void (*paused)(struct mGUIRunner*);
void (*unpaused)(struct mGUIRunner*); void (*unpaused)(struct mGUIRunner*);
void (*incrementScreenMode)(struct mGUIRunner*); void (*incrementScreenMode)(struct mGUIRunner*);
void (*setFrameLimiter)(struct mGUIRunner*, bool limit);
uint16_t (*pollGameInput)(struct mGUIRunner*); uint16_t (*pollGameInput)(struct mGUIRunner*);
}; };

View File

@ -64,6 +64,7 @@ static size_t audioPos = 0;
static C3D_Tex outputTexture; static C3D_Tex outputTexture;
static ndspWaveBuf dspBuffer[DSP_BUFFERS]; static ndspWaveBuf dspBuffer[DSP_BUFFERS];
static int bufferId = 0; static int bufferId = 0;
static bool frameLimiter = true;
static C3D_RenderBuf bottomScreen; static C3D_RenderBuf bottomScreen;
static C3D_RenderBuf topScreen; static C3D_RenderBuf topScreen;
@ -182,7 +183,9 @@ static void _drawEnd(void) {
C3D_RenderBufTransfer(&topScreen, (u32*) gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGB8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8)); C3D_RenderBufTransfer(&topScreen, (u32*) gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGB8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8));
C3D_RenderBufTransfer(&bottomScreen, (u32*) gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL), GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGB8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8)); C3D_RenderBufTransfer(&bottomScreen, (u32*) gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL), GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGB8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8));
gfxSwapBuffersGpu(); gfxSwapBuffersGpu();
gspWaitForEvent(GSPGPU_EVENT_VBlank0, false); if (frameLimiter) {
gspWaitForEvent(GSPGPU_EVENT_VBlank0, false);
}
} }
static int _batteryState(void) { static int _batteryState(void) {
@ -245,6 +248,7 @@ static void _setup(struct mGUIRunner* runner) {
if (mCoreConfigGetUIntValue(&runner->config, "screenMode", &mode) && mode < SM_MAX) { if (mCoreConfigGetUIntValue(&runner->config, "screenMode", &mode) && mode < SM_MAX) {
screenMode = mode; screenMode = mode;
} }
frameLimiter = true;
runner->core->setAudioBufferSize(runner->core, AUDIO_SAMPLES); runner->core->setAudioBufferSize(runner->core, AUDIO_SAMPLES);
} }
@ -300,6 +304,7 @@ static void _gameUnloaded(struct mGUIRunner* runner) {
csndExecCmds(false); csndExecCmds(false);
} }
osSetSpeedupEnable(false); osSetSpeedupEnable(false);
frameLimiter = true;
switch (runner->core->platform(runner->core)) { switch (runner->core->platform(runner->core)) {
#ifdef M_CORE_GBA #ifdef M_CORE_GBA
@ -460,6 +465,11 @@ static void _incrementScreenMode(struct mGUIRunner* runner) {
C3D_RenderBufClear(&topScreen); C3D_RenderBufClear(&topScreen);
} }
static void _setFrameLimiter(struct mGUIRunner* runner, bool limit) {
UNUSED(runner);
frameLimiter = limit;
}
static uint32_t _pollInput(const struct mInputMap* map) { static uint32_t _pollInput(const struct mInputMap* map) {
hidScanInput(); hidScanInput();
int activeKeys = hidKeysHeld(); int activeKeys = hidKeysHeld();
@ -689,6 +699,7 @@ int main() {
.paused = _gameUnloaded, .paused = _gameUnloaded,
.unpaused = _gameLoaded, .unpaused = _gameLoaded,
.incrementScreenMode = _incrementScreenMode, .incrementScreenMode = _incrementScreenMode,
.setFrameLimiter = _setFrameLimiter,
.pollGameInput = _pollGameInput .pollGameInput = _pollGameInput
}; };

View File

@ -31,10 +31,11 @@ static void _drawStart(void) {
static void _drawEnd(void) { static void _drawEnd(void) {
static int oldVCount = 0; static int oldVCount = 0;
extern bool frameLimiter;
int vcount = oldVCount; int vcount = oldVCount;
vita2d_end_drawing(); vita2d_end_drawing();
oldVCount = sceDisplayGetVcount(); oldVCount = sceDisplayGetVcount();
vita2d_set_vblank_wait(oldVCount + 1 >= vcount); vita2d_set_vblank_wait(frameLimiter && oldVCount + 1 >= vcount);
vita2d_swap_buffers(); vita2d_swap_buffers();
} }
@ -146,6 +147,7 @@ int main() {
.paused = mPSP2Paused, .paused = mPSP2Paused,
.unpaused = mPSP2Unpaused, .unpaused = mPSP2Unpaused,
.incrementScreenMode = mPSP2IncrementScreenMode, .incrementScreenMode = mPSP2IncrementScreenMode,
.setFrameLimiter = mPSP2SetFrameLimiter,
.pollGameInput = mPSP2PollInput .pollGameInput = mPSP2PollInput
}; };

View File

@ -58,11 +58,12 @@ static struct mSceRumble {
struct CircleBuffer history; struct CircleBuffer history;
int current; int current;
} rumble; } rumble;
bool frameLimiter = true;
extern const uint8_t _binary_backdrop_png_start[]; extern const uint8_t _binary_backdrop_png_start[];
static vita2d_texture* backdrop = 0; static vita2d_texture* backdrop = 0;
#define PSP2_SAMPLES 64 #define PSP2_SAMPLES 128
#define PSP2_AUDIO_BUFFER_SIZE (PSP2_SAMPLES * 40) #define PSP2_AUDIO_BUFFER_SIZE (PSP2_SAMPLES * 40)
static struct mPSP2AudioContext { static struct mPSP2AudioContext {
@ -89,6 +90,7 @@ static THREAD_ENTRY _audioThread(void* context) {
struct GBAStereoSample* buffer = audio->buffer.readPtr; struct GBAStereoSample* buffer = audio->buffer.readPtr;
RingFIFORead(&audio->buffer, NULL, len * 4); RingFIFORead(&audio->buffer, NULL, len * 4);
audio->samples -= len; audio->samples -= len;
ConditionWake(&audio->cond);
MutexUnlock(&audio->mutex); MutexUnlock(&audio->mutex);
sceAudioOutOutput(audioPort, buffer); sceAudioOutOutput(audioPort, buffer);
@ -163,6 +165,11 @@ uint16_t mPSP2PollInput(struct mGUIRunner* runner) {
return activeKeys; return activeKeys;
} }
void mPSP2SetFrameLimiter(struct mGUIRunner* runner, bool limit) {
UNUSED(runner);
frameLimiter = limit;
}
void mPSP2Setup(struct mGUIRunner* runner) { void mPSP2Setup(struct mGUIRunner* runner) {
mCoreConfigSetDefaultIntValue(&runner->config, "threadedVideo", 1); mCoreConfigSetDefaultIntValue(&runner->config, "threadedVideo", 1);
mCoreLoadForeignConfig(runner->core, &runner->config); mCoreLoadForeignConfig(runner->core, &runner->config);
@ -200,6 +207,7 @@ void mPSP2Setup(struct mGUIRunner* runner) {
CircleBufferInit(&rumble.history, RUMBLE_PWM); CircleBufferInit(&rumble.history, RUMBLE_PWM);
runner->core->setRumble(runner->core, &rumble.d); runner->core->setRumble(runner->core, &rumble.d);
frameLimiter = true;
backdrop = vita2d_load_PNG_buffer(_binary_backdrop_png_start); backdrop = vita2d_load_PNG_buffer(_binary_backdrop_png_start);
unsigned mode; unsigned mode;
@ -210,7 +218,7 @@ void mPSP2Setup(struct mGUIRunner* runner) {
void mPSP2LoadROM(struct mGUIRunner* runner) { void mPSP2LoadROM(struct mGUIRunner* runner) {
scePowerSetArmClockFrequency(444); scePowerSetArmClockFrequency(444);
double ratio = GBAAudioCalculateRatio(1, 60, 1); double ratio = GBAAudioCalculateRatio(1, 60.0 / 1.001, 1);
blip_set_rates(runner->core->getAudioChannel(runner->core, 0), runner->core->frequency(runner->core), 48000 * ratio); blip_set_rates(runner->core->getAudioChannel(runner->core, 0), runner->core->frequency(runner->core), 48000 * ratio);
blip_set_rates(runner->core->getAudioChannel(runner->core, 1), runner->core->frequency(runner->core), 48000 * ratio); blip_set_rates(runner->core->getAudioChannel(runner->core, 1), runner->core->frequency(runner->core), 48000 * ratio);
@ -246,7 +254,9 @@ void mPSP2PrepareForFrame(struct mGUIRunner* runner) {
struct GBAStereoSample* samples = audioContext.buffer.writePtr; struct GBAStereoSample* samples = audioContext.buffer.writePtr;
blip_read_samples(runner->core->getAudioChannel(runner->core, 0), &samples[0].left, PSP2_SAMPLES, true); blip_read_samples(runner->core->getAudioChannel(runner->core, 0), &samples[0].left, PSP2_SAMPLES, true);
blip_read_samples(runner->core->getAudioChannel(runner->core, 1), &samples[0].right, PSP2_SAMPLES, true); blip_read_samples(runner->core->getAudioChannel(runner->core, 1), &samples[0].right, PSP2_SAMPLES, true);
RingFIFOWrite(&audioContext.buffer, NULL, PSP2_SAMPLES * 4); if (!RingFIFOWrite(&audioContext.buffer, NULL, PSP2_SAMPLES * 4)) {
break;
}
audioContext.samples += PSP2_SAMPLES; audioContext.samples += PSP2_SAMPLES;
} }
ConditionWake(&audioContext.cond); ConditionWake(&audioContext.cond);
@ -295,9 +305,9 @@ void mPSP2Teardown(struct mGUIRunner* runner) {
CircleBufferDeinit(&rumble.history); CircleBufferDeinit(&rumble.history);
vita2d_free_texture(tex); vita2d_free_texture(tex);
vita2d_free_texture(screenshot); vita2d_free_texture(screenshot);
frameLimiter = true;
} }
void _drawTex(vita2d_texture* t, unsigned width, unsigned height, bool faded) { void _drawTex(vita2d_texture* t, unsigned width, unsigned height, bool faded) {
unsigned w = width; unsigned w = width;
unsigned h = height; unsigned h = height;

View File

@ -22,6 +22,7 @@ void mPSP2Unpaused(struct mGUIRunner* runner);
void mPSP2Draw(struct mGUIRunner* runner, bool faded); void mPSP2Draw(struct mGUIRunner* runner, bool faded);
void mPSP2DrawScreenshot(struct mGUIRunner* runner, const uint32_t* pixels, unsigned width, unsigned height, bool faded); void mPSP2DrawScreenshot(struct mGUIRunner* runner, const uint32_t* pixels, unsigned width, unsigned height, bool faded);
void mPSP2IncrementScreenMode(struct mGUIRunner* runner); void mPSP2IncrementScreenMode(struct mGUIRunner* runner);
void mPSP2SetFrameLimiter(struct mGUIRunner* runner, bool limit);
uint16_t mPSP2PollInput(struct mGUIRunner* runner); uint16_t mPSP2PollInput(struct mGUIRunner* runner);
#endif #endif

View File

@ -71,6 +71,7 @@ static void _gameUnloaded(struct mGUIRunner* runner);
static void _unpaused(struct mGUIRunner* runner); static void _unpaused(struct mGUIRunner* runner);
static void _drawFrame(struct mGUIRunner* runner, bool faded); static void _drawFrame(struct mGUIRunner* runner, bool faded);
static uint16_t _pollGameInput(struct mGUIRunner* runner); static uint16_t _pollGameInput(struct mGUIRunner* runner);
static void _setFrameLimiter(struct mGUIRunner* runner, bool limit);
static void _incrementScreenMode(struct mGUIRunner* runner); static void _incrementScreenMode(struct mGUIRunner* runner);
static s8 WPAD_StickX(u8 chan, u8 right); static s8 WPAD_StickX(u8 chan, u8 right);
@ -88,6 +89,7 @@ static int32_t tiltY;
static int32_t gyroZ; static int32_t gyroZ;
static uint32_t retraceCount; static uint32_t retraceCount;
static uint32_t referenceRetraceCount; static uint32_t referenceRetraceCount;
static bool frameLimiter = true;
static int scaleFactor; static int scaleFactor;
static unsigned corew, coreh; static unsigned corew, coreh;
@ -363,6 +365,7 @@ int main(int argc, char* argv[]) {
.paused = _gameUnloaded, .paused = _gameUnloaded,
.unpaused = _unpaused, .unpaused = _unpaused,
.incrementScreenMode = _incrementScreenMode, .incrementScreenMode = _incrementScreenMode,
.setFrameLimiter = _setFrameLimiter,
.pollGameInput = _pollGameInput .pollGameInput = _pollGameInput
}; };
mGUIInit(&runner, "wii"); mGUIInit(&runner, "wii");
@ -429,9 +432,11 @@ static void _drawStart(void) {
u32 level = 0; u32 level = 0;
_CPU_ISR_Disable(level); _CPU_ISR_Disable(level);
if (referenceRetraceCount >= retraceCount) { if (referenceRetraceCount >= retraceCount) {
VIDEO_WaitVSync(); if (frameLimiter) {
VIDEO_WaitVSync();
}
referenceRetraceCount = retraceCount;
} }
referenceRetraceCount = retraceCount;
_CPU_ISR_Restore(level); _CPU_ISR_Restore(level);
GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE); GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
@ -454,6 +459,11 @@ static void _drawEnd(void) {
_CPU_ISR_Restore(level); _CPU_ISR_Restore(level);
} }
static void _setFrameLimiter(struct mGUIRunner* runner, bool limit) {
UNUSED(runner);
frameLimiter = limit;
}
static uint32_t _pollInput(const struct mInputMap* map) { static uint32_t _pollInput(const struct mInputMap* map) {
PAD_ScanPads(); PAD_ScanPads();
u16 padkeys = PAD_ButtonsHeld(0); u16 padkeys = PAD_ButtonsHeld(0);
@ -585,11 +595,14 @@ void _setup(struct mGUIRunner* runner) {
double ratio = GBAAudioCalculateRatio(1, 60 / 1.001, 1); double ratio = GBAAudioCalculateRatio(1, 60 / 1.001, 1);
blip_set_rates(runner->core->getAudioChannel(runner->core, 0), runner->core->frequency(runner->core), 48000 * ratio); blip_set_rates(runner->core->getAudioChannel(runner->core, 0), runner->core->frequency(runner->core), 48000 * ratio);
blip_set_rates(runner->core->getAudioChannel(runner->core, 1), runner->core->frequency(runner->core), 48000 * ratio); blip_set_rates(runner->core->getAudioChannel(runner->core, 1), runner->core->frequency(runner->core), 48000 * ratio);
frameLimiter = true;
} }
void _gameUnloaded(struct mGUIRunner* runner) { void _gameUnloaded(struct mGUIRunner* runner) {
UNUSED(runner); UNUSED(runner);
AUDIO_StopDMA(); AUDIO_StopDMA();
frameLimiter = true;
} }
void _gameLoaded(struct mGUIRunner* runner) { void _gameLoaded(struct mGUIRunner* runner) {