mirror of https://github.com/mgba-emu/mgba.git
Libretro: Add rumble support
This commit is contained in:
parent
386da2accd
commit
18ec3de2e2
|
@ -12,9 +12,11 @@
|
||||||
#include "gba/serialize.h"
|
#include "gba/serialize.h"
|
||||||
#include "gba/supervisor/overrides.h"
|
#include "gba/supervisor/overrides.h"
|
||||||
#include "gba/video.h"
|
#include "gba/video.h"
|
||||||
|
#include "util/circle-buffer.h"
|
||||||
#include "util/vfs.h"
|
#include "util/vfs.h"
|
||||||
|
|
||||||
#define SAMPLES 1024
|
#define SAMPLES 1024
|
||||||
|
#define RUMBLE_PWM 35
|
||||||
|
|
||||||
static retro_environment_t environCallback;
|
static retro_environment_t environCallback;
|
||||||
static retro_video_refresh_t videoCallback;
|
static retro_video_refresh_t videoCallback;
|
||||||
|
@ -22,11 +24,13 @@ static retro_audio_sample_batch_t audioCallback;
|
||||||
static retro_input_poll_t inputPollCallback;
|
static retro_input_poll_t inputPollCallback;
|
||||||
static retro_input_state_t inputCallback;
|
static retro_input_state_t inputCallback;
|
||||||
static retro_log_printf_t logCallback;
|
static retro_log_printf_t logCallback;
|
||||||
|
static retro_set_rumble_state_t rumbleCallback;
|
||||||
|
|
||||||
static void GBARetroLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args);
|
static void GBARetroLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args);
|
||||||
|
|
||||||
static void _postAudioBuffer(struct GBAAVStream*, struct GBAAudio* audio);
|
static void _postAudioBuffer(struct GBAAVStream*, struct GBAAudio* audio);
|
||||||
static void _postVideoFrame(struct GBAAVStream*, struct GBAVideoRenderer* renderer);
|
static void _postVideoFrame(struct GBAAVStream*, struct GBAVideoRenderer* renderer);
|
||||||
|
static void _setRumble(struct GBARumble* rumble, int enable);
|
||||||
|
|
||||||
static struct GBA gba;
|
static struct GBA gba;
|
||||||
static struct ARMCore cpu;
|
static struct ARMCore cpu;
|
||||||
|
@ -36,6 +40,9 @@ static void* data;
|
||||||
static struct VFile* save;
|
static struct VFile* save;
|
||||||
static void* savedata;
|
static void* savedata;
|
||||||
static struct GBAAVStream stream;
|
static struct GBAAVStream stream;
|
||||||
|
static int rumbleLevel;
|
||||||
|
static struct CircleBuffer rumbleHistory;
|
||||||
|
static struct GBARumble rumble;
|
||||||
|
|
||||||
unsigned retro_api_version(void) {
|
unsigned retro_api_version(void) {
|
||||||
return RETRO_API_VERSION;
|
return RETRO_API_VERSION;
|
||||||
|
@ -112,7 +119,15 @@ void retro_init(void) {
|
||||||
environCallback(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, &inputDescriptors);
|
environCallback(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, &inputDescriptors);
|
||||||
|
|
||||||
// TODO: RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME when BIOS booting is supported
|
// TODO: RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME when BIOS booting is supported
|
||||||
// TODO: RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE
|
|
||||||
|
struct retro_rumble_interface rumbleInterface;
|
||||||
|
if (environCallback(RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE, &rumbleInterface)) {
|
||||||
|
rumbleCallback = rumbleInterface.set_rumble_state;
|
||||||
|
CircleBufferInit(&rumbleHistory, RUMBLE_PWM);
|
||||||
|
rumble.setRumble = _setRumble;
|
||||||
|
} else {
|
||||||
|
rumbleCallback = 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct retro_log_callback log;
|
struct retro_log_callback log;
|
||||||
if (environCallback(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log)) {
|
if (environCallback(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log)) {
|
||||||
|
@ -132,6 +147,9 @@ void retro_init(void) {
|
||||||
gba.logHandler = GBARetroLog;
|
gba.logHandler = GBARetroLog;
|
||||||
gba.stream = &stream;
|
gba.stream = &stream;
|
||||||
gba.idleOptimization = IDLE_LOOP_REMOVE; // TODO: Settings
|
gba.idleOptimization = IDLE_LOOP_REMOVE; // TODO: Settings
|
||||||
|
if (rumbleCallback) {
|
||||||
|
gba.rumble = &rumble;
|
||||||
|
}
|
||||||
rom = 0;
|
rom = 0;
|
||||||
|
|
||||||
GBAVideoSoftwareRendererCreate(&renderer);
|
GBAVideoSoftwareRendererCreate(&renderer);
|
||||||
|
@ -176,6 +194,10 @@ void retro_run(void) {
|
||||||
|
|
||||||
void retro_reset(void) {
|
void retro_reset(void) {
|
||||||
ARMReset(&cpu);
|
ARMReset(&cpu);
|
||||||
|
|
||||||
|
if (rumbleCallback) {
|
||||||
|
CircleBufferClear(&rumbleHistory);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool retro_load_game(const struct retro_game_info* game) {
|
bool retro_load_game(const struct retro_game_info* game) {
|
||||||
|
@ -219,6 +241,7 @@ void retro_unload_game(void) {
|
||||||
save = 0;
|
save = 0;
|
||||||
free(savedata);
|
free(savedata);
|
||||||
savedata = 0;
|
savedata = 0;
|
||||||
|
CircleBufferDeinit(&rumbleHistory);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t retro_serialize_size(void) {
|
size_t retro_serialize_size(void) {
|
||||||
|
@ -317,10 +340,12 @@ void GBARetroLog(struct GBAThread* thread, enum GBALogLevel level, const char* f
|
||||||
case GBA_LOG_INFO:
|
case GBA_LOG_INFO:
|
||||||
case GBA_LOG_GAME_ERROR:
|
case GBA_LOG_GAME_ERROR:
|
||||||
case GBA_LOG_SWI:
|
case GBA_LOG_SWI:
|
||||||
|
case GBA_LOG_STATUS:
|
||||||
retroLevel = RETRO_LOG_INFO;
|
retroLevel = RETRO_LOG_INFO;
|
||||||
break;
|
break;
|
||||||
case GBA_LOG_DEBUG:
|
case GBA_LOG_DEBUG:
|
||||||
case GBA_LOG_STUB:
|
case GBA_LOG_STUB:
|
||||||
|
case GBA_LOG_SIO:
|
||||||
retroLevel = RETRO_LOG_DEBUG;
|
retroLevel = RETRO_LOG_DEBUG;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -352,3 +377,18 @@ static void _postVideoFrame(struct GBAAVStream* stream, struct GBAVideoRenderer*
|
||||||
renderer->getPixels(renderer, &stride, &pixels);
|
renderer->getPixels(renderer, &stride, &pixels);
|
||||||
videoCallback(pixels, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, BYTES_PER_PIXEL * stride);
|
videoCallback(pixels, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, BYTES_PER_PIXEL * stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _setRumble(struct GBARumble* rumble, int enable) {
|
||||||
|
UNUSED(rumble);
|
||||||
|
if (!rumbleCallback) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rumbleLevel += enable;
|
||||||
|
if (CircleBufferSize(&rumbleHistory) == RUMBLE_PWM) {
|
||||||
|
int8_t oldLevel;
|
||||||
|
CircleBufferRead8(&rumbleHistory, &oldLevel);
|
||||||
|
rumbleLevel -= oldLevel;
|
||||||
|
}
|
||||||
|
CircleBufferWrite8(&rumbleHistory, enable);
|
||||||
|
rumbleCallback(0, RETRO_RUMBLE_STRONG, rumbleLevel * 0xFFFF / RUMBLE_PWM);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue