mirror of
https://github.com/libretro/RetroArch.git
synced 2025-04-02 10:51:52 -04:00
libretro fixups.
This commit is contained in:
parent
cb3a65a358
commit
5d51942f69
15 changed files with 427 additions and 525 deletions
50
config.def.h
50
config.def.h
|
@ -23,7 +23,7 @@
|
|||
#define __CONFIG_DEF_H
|
||||
|
||||
#include "boolean.h"
|
||||
#include "libsnes.hpp"
|
||||
#include "libretro.h"
|
||||
#include "driver.h"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
@ -293,18 +293,18 @@ static const float axis_threshold = 0.5;
|
|||
// Player 1
|
||||
static const struct snes_keybind snes_keybinds_1[] = {
|
||||
// SNES button | keyboard key | js btn | js axis |
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_B, SK_z, NO_BTN, AXIS_NONE },
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_Y, SK_a, NO_BTN, AXIS_NONE },
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_SELECT, SK_RSHIFT, NO_BTN, AXIS_NONE },
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_START, SK_RETURN, NO_BTN, AXIS_NONE },
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_UP, SK_UP, NO_BTN, AXIS_NONE },
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_DOWN, SK_DOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_LEFT, SK_LEFT, NO_BTN, AXIS_NONE },
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_RIGHT, SK_RIGHT, NO_BTN, AXIS_NONE },
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_A, SK_x, NO_BTN, AXIS_NONE },
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_X, SK_s, NO_BTN, AXIS_NONE },
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_L, SK_q, NO_BTN, AXIS_NONE },
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_R, SK_w, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_B, SK_z, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_Y, SK_a, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_SELECT, SK_RSHIFT, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_START, SK_RETURN, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_UP, SK_UP, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_DOWN, SK_DOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_LEFT, SK_LEFT, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_RIGHT, SK_RIGHT, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_A, SK_x, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_X, SK_s, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_L, SK_q, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_R, SK_w, NO_BTN, AXIS_NONE },
|
||||
|
||||
{ true, SSNES_FAST_FORWARD_KEY, SK_SPACE, NO_BTN, AXIS_NONE },
|
||||
{ true, SSNES_FAST_FORWARD_HOLD_KEY, SK_l, NO_BTN, AXIS_NONE },
|
||||
|
@ -335,18 +335,18 @@ static const struct snes_keybind snes_keybinds_1[] = {
|
|||
|
||||
// Player 2-5
|
||||
static const struct snes_keybind snes_keybinds_rest[] = {
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_B, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_Y, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_SELECT, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_START, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_UP, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_DOWN, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_LEFT, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_RIGHT, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_A, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_X, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_L, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, SNES_DEVICE_ID_JOYPAD_R, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_B, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_Y, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_SELECT, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_START, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_UP, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_DOWN, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_LEFT, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_RIGHT, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_A, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_X, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_L, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, RETRO_DEVICE_ID_JOYPAD_R, SK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
49
driver.c
49
driver.c
|
@ -265,29 +265,20 @@ static void deinit_dsp_plugin(void)
|
|||
|
||||
static void adjust_audio_input_rate(void)
|
||||
{
|
||||
if (g_extern.system.timing_set)
|
||||
{
|
||||
float timing_skew = fabs(1.0f - g_extern.system.timing.fps / g_settings.video.refresh_rate);
|
||||
if (timing_skew > 0.05f) // We don't want to adjust pitch too much. If we have extreme cases, just don't readjust at all.
|
||||
{
|
||||
SSNES_LOG("Timings deviate too much. Will not adjust. (Display = %.2f Hz, Game = %.2f Hz)\n",
|
||||
g_settings.video.refresh_rate,
|
||||
(float)g_extern.system.timing.fps);
|
||||
const struct retro_system_timing *info = &g_extern.system.av_info.timing;
|
||||
|
||||
g_settings.video.refresh_rate = g_extern.system.timing.fps;
|
||||
}
|
||||
float timing_skew = fabs(1.0f - info->fps / g_settings.video.refresh_rate);
|
||||
if (timing_skew > 0.05f) // We don't want to adjust pitch too much. If we have extreme cases, just don't readjust at all.
|
||||
{
|
||||
SSNES_LOG("Timings deviate too much. Will not adjust. (Display = %.2f Hz, Game = %.2f Hz)\n",
|
||||
g_settings.video.refresh_rate,
|
||||
(float)info->fps);
|
||||
|
||||
g_settings.video.refresh_rate = info->fps;
|
||||
}
|
||||
|
||||
if (g_extern.system.timing_set)
|
||||
{
|
||||
g_settings.audio.in_rate = g_extern.system.timing.sample_rate *
|
||||
(g_settings.video.refresh_rate / g_extern.system.timing.fps);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_settings.audio.in_rate = 32040.5 *
|
||||
(g_settings.video.refresh_rate / (21477272.0 / 357366.0)); // SNES metrics.
|
||||
}
|
||||
g_settings.audio.in_rate = info->sample_rate *
|
||||
(g_settings.video.refresh_rate / info->fps);
|
||||
|
||||
SSNES_LOG("Set audio input rate to: %.2f Hz.\n", g_settings.audio.in_rate);
|
||||
}
|
||||
|
@ -426,8 +417,9 @@ static void init_filter(void)
|
|||
|
||||
g_extern.filter.active = true;
|
||||
|
||||
unsigned width = g_extern.system.geom.max_width;
|
||||
unsigned height = g_extern.system.geom.max_height;
|
||||
struct retro_game_geometry *geom = &g_extern.system.av_info.geometry;
|
||||
unsigned width = geom->max_width;
|
||||
unsigned height = geom->max_height;
|
||||
g_extern.filter.psize(&width, &height);
|
||||
|
||||
unsigned pow2_x = next_pow2(width);
|
||||
|
@ -508,7 +500,8 @@ void init_video_input(void)
|
|||
init_shader_dir();
|
||||
#endif
|
||||
|
||||
unsigned max_dim = max(g_extern.system.geom.max_width, g_extern.system.geom.max_height);
|
||||
struct retro_game_geometry *geom = &g_extern.system.av_info.geometry;
|
||||
unsigned max_dim = max(geom->max_width, geom->max_height);
|
||||
unsigned scale = max_dim / SSNES_SCALE_BASE;
|
||||
scale = max(scale, 1);
|
||||
|
||||
|
@ -526,19 +519,19 @@ void init_video_input(void)
|
|||
{
|
||||
if (g_settings.video.force_aspect && (g_settings.video.aspect_ratio > 0.0f))
|
||||
{
|
||||
width = roundf(g_extern.system.geom.base_height * g_settings.video.xscale * g_settings.video.aspect_ratio);
|
||||
height = roundf(g_extern.system.geom.base_height * g_settings.video.yscale);
|
||||
width = roundf(geom->base_height * g_settings.video.xscale * g_settings.video.aspect_ratio);
|
||||
height = roundf(geom->base_height * g_settings.video.yscale);
|
||||
}
|
||||
else
|
||||
{
|
||||
width = roundf(g_extern.system.geom.base_width * g_settings.video.xscale);
|
||||
height = roundf(g_extern.system.geom.base_height * g_settings.video.yscale);
|
||||
width = roundf(geom->base_width * g_settings.video.xscale);
|
||||
height = roundf(geom->base_height * g_settings.video.yscale);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_settings.video.aspect_ratio < 0.0f)
|
||||
{
|
||||
g_settings.video.aspect_ratio = (float)g_extern.system.geom.base_width / g_extern.system.geom.base_height;
|
||||
g_settings.video.aspect_ratio = (float)geom->base_width / geom->base_height;
|
||||
SSNES_LOG("Adjusting aspect ratio to %.2f\n", g_settings.video.aspect_ratio);
|
||||
}
|
||||
|
||||
|
|
27
dynamic.c
27
dynamic.c
|
@ -29,7 +29,7 @@
|
|||
#endif
|
||||
|
||||
#include "boolean.h"
|
||||
#include "libsnes.hpp"
|
||||
#include "libretro.h"
|
||||
|
||||
#ifdef NEED_DYNAMIC
|
||||
#ifdef _WIN32
|
||||
|
@ -41,7 +41,7 @@
|
|||
|
||||
#ifdef HAVE_DYNAMIC
|
||||
#define SYM(x) do { \
|
||||
function_t func = dylib_proc(lib, #x); \
|
||||
function_t func = dylib_proc(lib_handle, #x); \
|
||||
memcpy(&p##x, &func, sizeof(func)); \
|
||||
if (p##x == NULL) { SSNES_ERR("Failed to load symbol: \"%s\"\n", #x); ssnes_fail(1, "init_libsnes_sym()"); } \
|
||||
} while (0)
|
||||
|
@ -78,8 +78,8 @@ bool (*pretro_unserialize)(const void*, size_t);
|
|||
void (*pretro_cheat_reset)(void);
|
||||
void (*pretro_cheat_set)(unsigned, bool, const char*);
|
||||
|
||||
bool (*pretro_load_game)(const retro_game_info*);
|
||||
bool (*pretro_load_game_special)(unsigned, const retro_game_info*, size_t);
|
||||
bool (*pretro_load_game)(const struct retro_game_info*);
|
||||
bool (*pretro_load_game_special)(unsigned, const struct retro_game_info*, size_t);
|
||||
|
||||
void (*pretro_unload_game)(void);
|
||||
|
||||
|
@ -236,12 +236,12 @@ static bool environment_cb(unsigned cmd, void *data)
|
|||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case SNES_ENVIRONMENT_GET_OVERSCAN:
|
||||
case RETRO_ENVIRONMENT_GET_OVERSCAN:
|
||||
*(bool*)data = !g_settings.video.crop_overscan;
|
||||
SSNES_LOG("Environ GET_OVERSCAN: %u\n", (unsigned)!g_settings.video.crop_overscan);
|
||||
break;
|
||||
|
||||
case SNES_ENVIRONMENT_GET_CAN_DUPE:
|
||||
case RETRO_ENVIRONMENT_GET_CAN_DUPE:
|
||||
#ifdef HAVE_FFMPEG
|
||||
*(bool*)data = true;
|
||||
SSNES_LOG("Environ GET_CAN_DUPE: true\n");
|
||||
|
@ -251,9 +251,9 @@ static bool environment_cb(unsigned cmd, void *data)
|
|||
#endif
|
||||
break;
|
||||
|
||||
case SNES_ENVIRONMENT_GET_VARIABLE:
|
||||
case RETRO_ENVIRONMENT_GET_VARIABLE:
|
||||
{
|
||||
struct snes_variable *var = (struct snes_variable*)data;
|
||||
struct retro_variable *var = (struct retro_variable*)data;
|
||||
if (var->key)
|
||||
{
|
||||
// Split string has '\0' delimiters so we have to find the position in original string,
|
||||
|
@ -278,11 +278,11 @@ static bool environment_cb(unsigned cmd, void *data)
|
|||
break;
|
||||
}
|
||||
|
||||
case SNES_ENVIRONMENT_SET_VARIABLES:
|
||||
case RETRO_ENVIRONMENT_SET_VARIABLES:
|
||||
{
|
||||
SSNES_LOG("Environ SET_VARIABLES:\n");
|
||||
SSNES_LOG("=======================\n");
|
||||
const struct snes_variable *vars = (const struct snes_variable*)data;
|
||||
const struct retro_variable *vars = (const struct retro_variable*)data;
|
||||
while (vars->key)
|
||||
{
|
||||
SSNES_LOG("\t%s :: %s\n",
|
||||
|
@ -295,16 +295,16 @@ static bool environment_cb(unsigned cmd, void *data)
|
|||
break;
|
||||
}
|
||||
|
||||
case SNES_ENVIRONMENT_SET_MESSAGE:
|
||||
case RETRO_ENVIRONMENT_SET_MESSAGE:
|
||||
{
|
||||
const struct snes_message *msg = (const struct snes_message*)data;
|
||||
const struct retro_message *msg = (const struct retro_message*)data;
|
||||
SSNES_LOG("Environ SET_MESSAGE: %s\n", msg->msg);
|
||||
if (g_extern.msg_queue)
|
||||
msg_queue_push(g_extern.msg_queue, msg->msg, 1, msg->frames);
|
||||
break;
|
||||
}
|
||||
|
||||
case SNES_ENVIRONMENT_SET_ROTATION:
|
||||
case RETRO_ENVIRONMENT_SET_ROTATION:
|
||||
{
|
||||
unsigned rotation = *(const unsigned*)data;
|
||||
SSNES_LOG("Environ SET_ROTATION: %u\n", rotation);
|
||||
|
@ -330,7 +330,6 @@ static bool environment_cb(unsigned cmd, void *data)
|
|||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void set_environment(void)
|
||||
{
|
||||
|
|
338
file.c
338
file.c
|
@ -19,7 +19,7 @@
|
|||
#include "general.h"
|
||||
#include <stdlib.h>
|
||||
#include "boolean.h"
|
||||
#include "libsnes.hpp"
|
||||
#include "libretro.h"
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "dynamic.h"
|
||||
|
@ -325,21 +325,21 @@ static const char *ramtype2str(int type)
|
|||
{
|
||||
switch (type)
|
||||
{
|
||||
case SNES_MEMORY_CARTRIDGE_RAM:
|
||||
case SNES_MEMORY_GAME_BOY_RAM:
|
||||
case SNES_MEMORY_BSX_RAM:
|
||||
case RETRO_MEMORY_SAVE_RAM:
|
||||
case RETRO_MEMORY_SNES_GAME_BOY_RAM:
|
||||
case RETRO_MEMORY_SNES_BSX_RAM:
|
||||
return ".srm";
|
||||
|
||||
case SNES_MEMORY_CARTRIDGE_RTC:
|
||||
case SNES_MEMORY_GAME_BOY_RTC:
|
||||
case RETRO_MEMORY_RTC:
|
||||
case RETRO_MEMORY_SNES_GAME_BOY_RTC:
|
||||
return ".rtc";
|
||||
|
||||
case SNES_MEMORY_BSX_PRAM:
|
||||
case RETRO_MEMORY_SNES_BSX_PRAM:
|
||||
return ".pram";
|
||||
|
||||
case SNES_MEMORY_SUFAMI_TURBO_A_RAM:
|
||||
case RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM:
|
||||
return ".aram";
|
||||
case SNES_MEMORY_SUFAMI_TURBO_B_RAM:
|
||||
case RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM:
|
||||
return ".bram";
|
||||
|
||||
default:
|
||||
|
@ -385,7 +385,7 @@ error:
|
|||
bool save_state(const char *path)
|
||||
{
|
||||
SSNES_LOG("Saving state: \"%s\".\n", path);
|
||||
size_t size = psnes_serialize_size();
|
||||
size_t size = pretro_serialize_size();
|
||||
if (size == 0)
|
||||
return false;
|
||||
|
||||
|
@ -397,7 +397,7 @@ bool save_state(const char *path)
|
|||
}
|
||||
|
||||
SSNES_LOG("State size: %d bytes.\n", (int)size);
|
||||
bool ret = psnes_serialize((uint8_t*)data, size);
|
||||
bool ret = pretro_serialize(data, size);
|
||||
if (ret)
|
||||
ret = dump_to_file(path, data, size);
|
||||
|
||||
|
@ -421,11 +421,11 @@ bool load_state(const char *path)
|
|||
}
|
||||
|
||||
bool ret = true;
|
||||
SSNES_LOG("State size: %d bytes.\n", (int)size);
|
||||
SSNES_LOG("State size: %u bytes.\n", (unsigned)size);
|
||||
|
||||
uint8_t *block_buf[2] = {NULL, NULL};
|
||||
void *block_buf[2] = {NULL, NULL};
|
||||
int block_type[2] = {-1, -1};
|
||||
unsigned block_size[2] = {0};
|
||||
size_t block_size[2] = {0};
|
||||
|
||||
if (g_settings.block_sram_overwrite)
|
||||
{
|
||||
|
@ -433,55 +433,55 @@ bool load_state(const char *path)
|
|||
switch (g_extern.game_type)
|
||||
{
|
||||
case SSNES_CART_NORMAL:
|
||||
block_type[0] = SNES_MEMORY_CARTRIDGE_RAM;
|
||||
block_type[1] = SNES_MEMORY_CARTRIDGE_RTC;
|
||||
block_type[0] = RETRO_MEMORY_SAVE_RAM;
|
||||
block_type[1] = RETRO_MEMORY_RTC;
|
||||
break;
|
||||
|
||||
case SSNES_CART_BSX:
|
||||
case SSNES_CART_BSX_SLOTTED:
|
||||
block_type[0] = SNES_MEMORY_BSX_RAM;
|
||||
block_type[1] = SNES_MEMORY_BSX_PRAM;
|
||||
block_type[0] = RETRO_MEMORY_SNES_BSX_RAM;
|
||||
block_type[1] = RETRO_MEMORY_SNES_BSX_PRAM;
|
||||
break;
|
||||
|
||||
case SSNES_CART_SUFAMI:
|
||||
block_type[0] = SNES_MEMORY_SUFAMI_TURBO_A_RAM;
|
||||
block_type[1] = SNES_MEMORY_SUFAMI_TURBO_B_RAM;
|
||||
block_type[0] = RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM;
|
||||
block_type[1] = RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM;
|
||||
break;
|
||||
|
||||
case SSNES_CART_SGB:
|
||||
block_type[0] = SNES_MEMORY_GAME_BOY_RAM;
|
||||
block_type[1] = SNES_MEMORY_GAME_BOY_RTC;
|
||||
block_type[0] = RETRO_MEMORY_SNES_GAME_BOY_RAM;
|
||||
block_type[1] = RETRO_MEMORY_SNES_GAME_BOY_RTC;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < 2; i++)
|
||||
if (block_type[i] != -1)
|
||||
block_size[i] = psnes_get_memory_size(block_type[i]);
|
||||
block_size[i] = pretro_get_memory_size(block_type[i]);
|
||||
|
||||
for (unsigned i = 0; i < 2; i++)
|
||||
if (block_size[i])
|
||||
block_buf[i] = (uint8_t*)malloc(block_size[i]);
|
||||
block_buf[i] = malloc(block_size[i]);
|
||||
|
||||
// Backup current SRAM which is overwritten by unserialize.
|
||||
for (unsigned i = 0; i < 2; i++)
|
||||
{
|
||||
if (block_buf[i])
|
||||
{
|
||||
const uint8_t *ptr = psnes_get_memory_data(block_type[i]);
|
||||
const void *ptr = pretro_get_memory_data(block_type[i]);
|
||||
if (ptr)
|
||||
memcpy(block_buf[i], ptr, block_size[i]);
|
||||
}
|
||||
}
|
||||
|
||||
ret = psnes_unserialize((uint8_t*)buf, size);
|
||||
ret = pretro_unserialize(buf, size);
|
||||
|
||||
// Flush back :D
|
||||
for (unsigned i = 0; i < 2 && ret; i++)
|
||||
{
|
||||
if (block_buf[i])
|
||||
{
|
||||
uint8_t *ptr = psnes_get_memory_data(block_type[i]);
|
||||
void *ptr = pretro_get_memory_data(block_type[i]);
|
||||
if (ptr)
|
||||
memcpy(ptr, block_buf[i], block_size[i]);
|
||||
}
|
||||
|
@ -497,8 +497,8 @@ bool load_state(const char *path)
|
|||
|
||||
void load_ram_file(const char *path, int type)
|
||||
{
|
||||
size_t size = psnes_get_memory_size(type);
|
||||
uint8_t *data = psnes_get_memory_data(type);
|
||||
size_t size = pretro_get_memory_size(type);
|
||||
uint8_t *data = pretro_get_memory_data(type);
|
||||
|
||||
if (size == 0 || !data)
|
||||
return;
|
||||
|
@ -513,14 +513,14 @@ void load_ram_file(const char *path, int type)
|
|||
|
||||
void save_ram_file(const char *path, int type)
|
||||
{
|
||||
size_t size = psnes_get_memory_size(type);
|
||||
uint8_t *data = psnes_get_memory_data(type);
|
||||
size_t size = pretro_get_memory_size(type);
|
||||
uint8_t *data = pretro_get_memory_data(type);
|
||||
|
||||
if (data && size > 0)
|
||||
{
|
||||
if (!dump_to_file(path, data, size))
|
||||
{
|
||||
SSNES_ERR("Failed to save SNES RAM.\n");
|
||||
SSNES_ERR("Failed to save SRAM.\n");
|
||||
SSNES_WARN("Attempting to recover ...\n");
|
||||
dump_to_file_desperate(data, size, type);
|
||||
}
|
||||
|
@ -539,190 +539,25 @@ static char *load_xml_map(const char *path)
|
|||
return xml_buf;
|
||||
}
|
||||
|
||||
static bool load_sgb_rom(void)
|
||||
{
|
||||
void *rom_buf = NULL;
|
||||
ssize_t rom_len = 0;
|
||||
#define MAX_ROMS 4
|
||||
|
||||
FILE *extra_rom = NULL;
|
||||
void *extra_rom_buf = NULL;
|
||||
ssize_t extra_rom_len = 0;
|
||||
char *xml_buf = 0;
|
||||
static bool load_roms(unsigned rom_type, const char **rom_paths, size_t roms)
|
||||
{
|
||||
bool ret = true;
|
||||
|
||||
if ((rom_len = read_rom_file(g_extern.rom_file, &rom_buf)) == -1)
|
||||
if (roms == 0)
|
||||
return false;
|
||||
|
||||
if (roms > MAX_ROMS)
|
||||
return false;
|
||||
|
||||
void *rom_buf[MAX_ROMS] = {NULL};
|
||||
ssize_t rom_len[MAX_ROMS] = {0};
|
||||
struct retro_game_info info[MAX_ROMS] = {{NULL}};
|
||||
|
||||
if (!g_extern.system.info.need_fullpath)
|
||||
{
|
||||
SSNES_ERR("Could not read ROM file.\n");
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((extra_rom_len = read_file(g_extern.gb_rom_path, &extra_rom_buf)) == -1)
|
||||
{
|
||||
SSNES_ERR("Cannot read GameBoy rom.\n");
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
xml_buf = load_xml_map(g_extern.xml_name);
|
||||
|
||||
if (!psnes_load_cartridge_super_game_boy(
|
||||
xml_buf, (const uint8_t*)rom_buf, rom_len,
|
||||
NULL, (const uint8_t*)extra_rom_buf, extra_rom_len))
|
||||
{
|
||||
SSNES_ERR("Cannot load SGB/GameBoy rom.\n");
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (xml_buf)
|
||||
free(xml_buf);
|
||||
|
||||
end:
|
||||
if (g_extern.rom_file)
|
||||
fclose(g_extern.rom_file);
|
||||
if (extra_rom)
|
||||
fclose(extra_rom);
|
||||
free(rom_buf);
|
||||
free(extra_rom_buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool load_bsx_rom(bool slotted)
|
||||
{
|
||||
void *rom_buf = NULL;
|
||||
ssize_t rom_len = 0;
|
||||
|
||||
FILE *extra_rom = NULL;
|
||||
void *extra_rom_buf = NULL;
|
||||
ssize_t extra_rom_len = 0;
|
||||
char *xml_buf = 0;
|
||||
bool ret = true;
|
||||
|
||||
if ((rom_len = read_rom_file(g_extern.rom_file, &rom_buf)) == -1)
|
||||
{
|
||||
SSNES_ERR("Could not read ROM file.\n");
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((extra_rom_len = read_file(g_extern.bsx_rom_path, &extra_rom_buf)) == -1)
|
||||
{
|
||||
SSNES_ERR("Cannot read BSX game rom.\n");
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
xml_buf = load_xml_map(g_extern.xml_name);
|
||||
|
||||
if (slotted)
|
||||
{
|
||||
if (!psnes_load_cartridge_bsx_slotted(
|
||||
xml_buf, (const uint8_t*)rom_buf, rom_len,
|
||||
NULL, (const uint8_t*)extra_rom_buf, extra_rom_len))
|
||||
{
|
||||
SSNES_ERR("Cannot load BSX slotted rom.\n");
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!psnes_load_cartridge_bsx(
|
||||
NULL, (const uint8_t*)rom_buf, rom_len,
|
||||
NULL, (const uint8_t*)extra_rom_buf, extra_rom_len))
|
||||
{
|
||||
SSNES_ERR("Cannot load BSX rom.\n");
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (xml_buf)
|
||||
free(xml_buf);
|
||||
|
||||
end:
|
||||
if (g_extern.rom_file)
|
||||
fclose(g_extern.rom_file);
|
||||
if (extra_rom)
|
||||
fclose(extra_rom);
|
||||
free(rom_buf);
|
||||
free(extra_rom_buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool load_sufami_rom(void)
|
||||
{
|
||||
void *rom_buf = NULL;
|
||||
ssize_t rom_len = 0;
|
||||
|
||||
FILE *extra_rom[2] = {NULL};
|
||||
void *extra_rom_buf[2] = {NULL};
|
||||
ssize_t extra_rom_len[2] = {0};
|
||||
char *xml_buf = 0;
|
||||
const char *roms[2] = {0};
|
||||
bool ret = true;
|
||||
|
||||
if ((rom_len = read_rom_file(g_extern.rom_file, &rom_buf)) == -1)
|
||||
{
|
||||
SSNES_ERR("Could not read ROM file.\n");
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
roms[0] = g_extern.sufami_rom_path[0];
|
||||
roms[1] = g_extern.sufami_rom_path[1];
|
||||
|
||||
for (unsigned i = 0; i < 2; i++)
|
||||
{
|
||||
if (*(roms[i]))
|
||||
{
|
||||
if ((extra_rom_len[i] = read_file(roms[i], &extra_rom_buf[i])) == -1)
|
||||
{
|
||||
SSNES_ERR("Cannot read Sufami game rom.\n");
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xml_buf = load_xml_map(g_extern.xml_name);
|
||||
|
||||
if (!psnes_load_cartridge_sufami_turbo(
|
||||
xml_buf, (const uint8_t*)rom_buf, rom_len,
|
||||
NULL, (const uint8_t*)extra_rom_buf[0], extra_rom_len[0],
|
||||
NULL, (const uint8_t*)extra_rom_buf[1], extra_rom_len[1]))
|
||||
{
|
||||
SSNES_ERR("Cannot load Sufami Turbo rom.\n");
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (xml_buf)
|
||||
free(xml_buf);
|
||||
|
||||
end:
|
||||
if (g_extern.rom_file)
|
||||
fclose(g_extern.rom_file);
|
||||
for (unsigned i = 0; i < 2; i++)
|
||||
{
|
||||
if (extra_rom[i])
|
||||
fclose(extra_rom[i]);
|
||||
free(extra_rom_buf[i]);
|
||||
}
|
||||
free(rom_buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool load_normal_rom(void)
|
||||
{
|
||||
void *rom_buf = NULL;
|
||||
ssize_t rom_len = 0;
|
||||
|
||||
if (!g_extern.system.need_fullpath)
|
||||
{
|
||||
if ((rom_len = read_rom_file(g_extern.rom_file, &rom_buf)) == -1)
|
||||
if ((rom_len[0] = read_rom_file(g_extern.rom_file, &rom_buf[0])) == -1)
|
||||
{
|
||||
SSNES_ERR("Could not read ROM file.\n");
|
||||
return false;
|
||||
|
@ -731,7 +566,7 @@ static bool load_normal_rom(void)
|
|||
if (g_extern.rom_file)
|
||||
fclose(g_extern.rom_file);
|
||||
|
||||
SSNES_LOG("ROM size: %d bytes\n", (int)rom_len);
|
||||
SSNES_LOG("ROM size: %u bytes.\n", (unsigned)rom_len[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -744,20 +579,81 @@ static bool load_normal_rom(void)
|
|||
fclose(g_extern.rom_file);
|
||||
SSNES_LOG("ROM loading skipped. Implementation will load it on its own.\n");
|
||||
}
|
||||
|
||||
|
||||
char *xml_buf = load_xml_map(g_extern.xml_name);
|
||||
|
||||
if (!psnes_load_cartridge_normal(xml_buf, (const uint8_t*)rom_buf, rom_len))
|
||||
info[0].path = rom_paths[0];
|
||||
info[0].data = rom_buf[0];
|
||||
info[0].size = rom_len[0];
|
||||
info[0].meta = xml_buf;
|
||||
|
||||
for (size_t i = 1; i < roms; i++)
|
||||
{
|
||||
SSNES_ERR("ROM file is not valid.\n");
|
||||
free(rom_buf);
|
||||
free(xml_buf);
|
||||
return false;
|
||||
if (rom_paths[i] &&
|
||||
!g_extern.system.info.need_fullpath &&
|
||||
(rom_len[i] = read_file(rom_paths[i], &rom_buf[i])) == -1)
|
||||
{
|
||||
SSNES_ERR("Could not read ROM file: \"%s\".\n", rom_paths[i]);
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
info[i].path = rom_paths[i];
|
||||
info[i].data = rom_buf[i];
|
||||
info[i].size = rom_len[i];
|
||||
}
|
||||
|
||||
if (rom_type == 0)
|
||||
ret = retro_load_game(&info[0]);
|
||||
else
|
||||
ret = retro_load_game_special(rom_type, info, roms);
|
||||
|
||||
if (!ret)
|
||||
SSNES_ERR("Failed to load game.\n");
|
||||
|
||||
end:
|
||||
for (unsigned i = 0; i < MAX_ROMS; i++)
|
||||
free(rom_buf[i]);
|
||||
free(xml_buf);
|
||||
free(rom_buf);
|
||||
return true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool load_normal_rom(void)
|
||||
{
|
||||
const char *path = *g_extern.fullpath ? g_extern.fullpath : NULL;
|
||||
return load_roms(0, &path, 1);
|
||||
}
|
||||
|
||||
static bool load_sgb_rom(void)
|
||||
{
|
||||
const char *path[2] = {
|
||||
*g_extern.fullpath ? g_extern.fullpath : NULL,
|
||||
g_extern.gb_rom_path
|
||||
};
|
||||
|
||||
return load_roms(RETRO_GAME_TYPE_SUPER_GAME_BOY, path, 2);
|
||||
}
|
||||
|
||||
static bool load_bsx_rom(bool slotted)
|
||||
{
|
||||
const char *path[2] = {
|
||||
*g_extern.fullpath ? g_extern.fullpath : NULL,
|
||||
g_extern.bsx_rom_path
|
||||
};
|
||||
|
||||
return load_roms(slotted ? RETRO_GAME_TYPE_BSX_SLOTTED : RETRO_GAME_TYPE_BSX, path, 2);
|
||||
}
|
||||
|
||||
static bool load_sufami_rom(void)
|
||||
{
|
||||
const char *path[3] = {
|
||||
*g_extern.fullpath ? g_extern.fullpath : NULL,
|
||||
g_extern.sufami_rom_path[0] ? g_extern.sufami_rom_path[0] : NULL,
|
||||
g_extern.sufami_rom_path[1] ? g_extern.sufami_rom_path[1] : NULL,
|
||||
};
|
||||
|
||||
return load_roms(RETRO_GAME_TYPE_SUFAMI_TURBO, path, 3);
|
||||
}
|
||||
|
||||
bool init_rom_file(enum ssnes_game_type type)
|
||||
|
|
|
@ -278,6 +278,7 @@ struct global
|
|||
#endif
|
||||
|
||||
char basename[PATH_MAX];
|
||||
char fullpath[PATH_MAX];
|
||||
char savefile_name_srm[PATH_MAX];
|
||||
char savefile_name_rtc[PATH_MAX]; // Make sure that fill_pathname has space.
|
||||
char savefile_name_psrm[PATH_MAX];
|
||||
|
@ -298,11 +299,8 @@ struct global
|
|||
|
||||
struct
|
||||
{
|
||||
struct retro_game_geometry geom;
|
||||
struct retro_system_timing timing;
|
||||
struct retro_system_info info;
|
||||
|
||||
char fullpath[PATH_MAX];
|
||||
struct retro_system_av_info av_info;
|
||||
|
||||
char *environment;
|
||||
char *environment_split;
|
||||
|
|
2
gfx/gl.c
2
gfx/gl.c
|
@ -19,7 +19,7 @@
|
|||
#include "../driver.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include "../libsnes.hpp"
|
||||
#include "../libretro.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../general.h"
|
||||
|
|
|
@ -467,8 +467,9 @@ static void *xv_init(const video_info_t *video, const input_driver_t **input, vo
|
|||
attributes.border_pixel = 0;
|
||||
attributes.event_mask = StructureNotifyMask | DestroyNotify | ClientMessage;
|
||||
|
||||
width = video->fullscreen ? ((video->width == 0) ? g_extern.system.geom.base_width : video->width) : video->width;
|
||||
height = video->fullscreen ? ((video->height == 0) ? g_extern.system.geom.base_height : video->height) : video->height;
|
||||
const struct retro_game_geometry *geom = &g_extern.system.av_info.geometry;
|
||||
width = video->fullscreen ? ((video->width == 0) ? geom->base_width : video->width) : video->width;
|
||||
height = video->fullscreen ? ((video->height == 0) ? geom->base_height : video->height) : video->height;
|
||||
xv->window = XCreateWindow(xv->display, DefaultRootWindow(xv->display),
|
||||
0, 0, width, height,
|
||||
0, xv->depth, InputOutput, visualinfo->visual,
|
||||
|
@ -492,8 +493,8 @@ static void *xv_init(const video_info_t *video, const input_driver_t **input, vo
|
|||
atom = XInternAtom(xv->display, "XV_AUTOPAINT_COLORKEY", true);
|
||||
if (atom != None) XvSetPortAttribute(xv->display, xv->port, atom, 1);
|
||||
|
||||
xv->width = g_extern.system.geom.max_width;
|
||||
xv->height = g_extern.system.geom.max_height;
|
||||
xv->width = geom->max_width;
|
||||
xv->height = geom->max_height;
|
||||
|
||||
xv->image = XvShmCreateImage(xv->display, xv->port, xv->fourcc, NULL, xv->width, xv->height, &xv->shminfo);
|
||||
if (!xv->image)
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "../general.h"
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "../libsnes.hpp"
|
||||
#include "../libretro.h"
|
||||
#include "ssnes_sdl_input.h"
|
||||
#include "keysym.h"
|
||||
|
||||
|
@ -293,78 +293,51 @@ static int16_t sdl_mouse_device_state(sdl_input_t *sdl, unsigned id)
|
|||
{
|
||||
switch (id)
|
||||
{
|
||||
case SNES_DEVICE_ID_MOUSE_LEFT:
|
||||
case RETRO_DEVICE_ID_MOUSE_LEFT:
|
||||
return sdl->mouse_l;
|
||||
case SNES_DEVICE_ID_MOUSE_RIGHT:
|
||||
case RETRO_DEVICE_ID_MOUSE_RIGHT:
|
||||
return sdl->mouse_r;
|
||||
case SNES_DEVICE_ID_MOUSE_X:
|
||||
case RETRO_DEVICE_ID_MOUSE_X:
|
||||
return sdl->mouse_x;
|
||||
case SNES_DEVICE_ID_MOUSE_Y:
|
||||
case RETRO_DEVICE_ID_MOUSE_Y:
|
||||
return sdl->mouse_y;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Missing some controllers, but hey :)
|
||||
static int16_t sdl_scope_device_state(sdl_input_t *sdl, unsigned id)
|
||||
static int16_t sdl_lightgun_device_state(sdl_input_t *sdl, unsigned id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case SNES_DEVICE_ID_SUPER_SCOPE_X:
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_X:
|
||||
return sdl->mouse_x;
|
||||
case SNES_DEVICE_ID_SUPER_SCOPE_Y:
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_Y:
|
||||
return sdl->mouse_y;
|
||||
case SNES_DEVICE_ID_SUPER_SCOPE_TRIGGER:
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_TRIGGER:
|
||||
return sdl->mouse_l;
|
||||
case SNES_DEVICE_ID_SUPER_SCOPE_CURSOR:
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_CURSOR:
|
||||
return sdl->mouse_m;
|
||||
case SNES_DEVICE_ID_SUPER_SCOPE_TURBO:
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_TURBO:
|
||||
return sdl->mouse_r;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Support two players.
|
||||
static int16_t sdl_justifier_device_state(sdl_input_t *sdl, unsigned index, unsigned id)
|
||||
{
|
||||
if (index == 0)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case SNES_DEVICE_ID_JUSTIFIER_X:
|
||||
return sdl->mouse_x;
|
||||
case SNES_DEVICE_ID_JUSTIFIER_Y:
|
||||
return sdl->mouse_y;
|
||||
case SNES_DEVICE_ID_JUSTIFIER_TRIGGER:
|
||||
return sdl->mouse_l;
|
||||
case SNES_DEVICE_ID_JUSTIFIER_START:
|
||||
return sdl->mouse_r;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int16_t sdl_input_state(void *data_, const struct snes_keybind **binds, bool port, unsigned device, unsigned index, unsigned id)
|
||||
{
|
||||
sdl_input_t *data = (sdl_input_t*)data_;
|
||||
switch (device)
|
||||
{
|
||||
case SNES_DEVICE_JOYPAD:
|
||||
return sdl_joypad_device_state(data, binds, (port == SNES_PORT_1) ? 0 : 1, id);
|
||||
case SNES_DEVICE_MULTITAP:
|
||||
return sdl_joypad_device_state(data, binds, (port == SNES_PORT_2) ? 1 + index : 0, id);
|
||||
case SNES_DEVICE_MOUSE:
|
||||
case RETRO_DEVICE_JOYPAD:
|
||||
return sdl_joypad_device_state(data, binds, port, id);
|
||||
case RETRO_DEVICE_JOYPAD_MULTITAP:
|
||||
return sdl_joypad_device_state(data, binds, (port == 1) ? 1 + index : 0, id);
|
||||
case RETRO_DEVICE_MOUSE:
|
||||
return sdl_mouse_device_state(data, id);
|
||||
case SNES_DEVICE_SUPER_SCOPE:
|
||||
return sdl_scope_device_state(data, id);
|
||||
case SNES_DEVICE_JUSTIFIER:
|
||||
case SNES_DEVICE_JUSTIFIERS:
|
||||
return sdl_justifier_device_state(data, index, id);
|
||||
case RETRO_DEVICE_LIGHTGUN:
|
||||
return sdl_lightgun_device_state(data, id);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
|
|
|
@ -191,12 +191,12 @@ static int16_t x_input_state(void *data, const struct snes_keybind **binds, bool
|
|||
|
||||
switch (device)
|
||||
{
|
||||
case SNES_DEVICE_JOYPAD:
|
||||
return x_is_pressed(x11, binds[(port == SNES_PORT_1) ? 0 : 1], id) ||
|
||||
case RETRO_DEVICE_JOYPAD:
|
||||
return x_is_pressed(x11, binds[port], id) ||
|
||||
input_sdl.input_state(x11->sdl, binds, port, device, index, id);
|
||||
|
||||
case SNES_DEVICE_MULTITAP:
|
||||
return x_is_pressed(x11, binds[(port == SNES_PORT_2) ? 1 + index : 0], id) ||
|
||||
case RETRO_DEVICE_JOYPAD_MULTITAP:
|
||||
return x_is_pressed(x11, binds[(port == 1) ? 1 + index : 0], id) ||
|
||||
input_sdl.input_state(x11->sdl, binds, port, device, index, id);
|
||||
|
||||
default:
|
||||
|
|
11
libretro.h
11
libretro.h
|
@ -144,9 +144,14 @@ struct retro_variable
|
|||
|
||||
struct retro_game_info
|
||||
{
|
||||
const char *path; // Path to game. Usually used as a reference.
|
||||
const void *data; // Memory buffer of loaded game. If the game is too big to load in one go. SET_NEED_FULLPATH should be used.
|
||||
// In this case, data and size will be 0, and game can be loaded from path.
|
||||
const char *path; // Path to game, UTF-8 encoded. Usually used as a reference.
|
||||
// May be NULL if rom was loaded from stdin or similar.
|
||||
// SET_NEED_FULLPATH path guaranteed that this path is valid.
|
||||
const void *data; // Memory buffer of loaded game.
|
||||
// If the game is too big to load in one go.
|
||||
// SET_NEED_FULLPATH should be used.
|
||||
// In this case, data and size will be 0,
|
||||
// and game can be loaded from path.
|
||||
size_t size; // Size of memory buffer.
|
||||
const char *meta; // String of implementation specific meta-data.
|
||||
};
|
||||
|
|
10
movie.c
10
movie.c
|
@ -82,8 +82,8 @@ static bool init_playback(bsv_movie_t *handle, const char *path)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (psnes_serialize_size() == state_size)
|
||||
psnes_unserialize(handle->state, state_size);
|
||||
if (pretro_serialize_size() == state_size)
|
||||
pretro_unserialize(handle->state, state_size);
|
||||
else
|
||||
SSNES_WARN("Movie format seems to have a different serializer version. Will most likely fail.\n");
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ static bool init_record(bsv_movie_t *handle, const char *path)
|
|||
|
||||
header[CRC_INDEX] = swap_if_big32(g_extern.cart_crc);
|
||||
|
||||
uint32_t state_size = psnes_serialize_size();
|
||||
uint32_t state_size = pretro_serialize_size();
|
||||
|
||||
header[STATE_SIZE_INDEX] = swap_if_big32(state_size);
|
||||
fwrite(header, 4, sizeof(uint32_t), handle->file);
|
||||
|
@ -123,7 +123,7 @@ static bool init_record(bsv_movie_t *handle, const char *path)
|
|||
if (!handle->state)
|
||||
return false;
|
||||
|
||||
psnes_serialize(handle->state, state_size);
|
||||
pretro_serialize(handle->state, state_size);
|
||||
fwrite(handle->state, 1, state_size, handle->file);
|
||||
}
|
||||
|
||||
|
@ -224,7 +224,7 @@ void bsv_movie_frame_rewind(bsv_movie_t *handle)
|
|||
if (!handle->playback)
|
||||
{
|
||||
fseek(handle->file, 4 * sizeof(uint32_t), SEEK_SET);
|
||||
psnes_serialize(handle->state, handle->state_size);
|
||||
pretro_serialize(handle->state, handle->state_size);
|
||||
fwrite(handle->state, 1, handle->state_size, handle->file);
|
||||
}
|
||||
else
|
||||
|
|
107
netplay.c
107
netplay.c
|
@ -63,7 +63,6 @@ static int16_t netplay_input_state(netplay_t *handle, bool port, unsigned device
|
|||
// If we're fast-forward replaying to resync, check if we should actually show frame.
|
||||
static bool netplay_should_skip(netplay_t *handle);
|
||||
static bool netplay_can_poll(netplay_t *handle);
|
||||
static const struct snes_callbacks* netplay_callbacks(netplay_t *handle);
|
||||
static void netplay_set_spectate_input(netplay_t *handle, int16_t input);
|
||||
|
||||
static bool netplay_send_cmd(netplay_t *handle, uint32_t cmd, const void *data, size_t size);
|
||||
|
@ -74,7 +73,7 @@ static bool netplay_get_cmd(netplay_t *handle);
|
|||
|
||||
struct delta_frame
|
||||
{
|
||||
uint8_t *state;
|
||||
void *state;
|
||||
|
||||
uint16_t real_input_state;
|
||||
uint16_t simulated_input_state;
|
||||
|
@ -96,7 +95,7 @@ struct netplay
|
|||
char other_nick[32];
|
||||
struct sockaddr_storage other_addr;
|
||||
|
||||
struct snes_callbacks cbs;
|
||||
struct retro_callbacks cbs;
|
||||
int fd; // TCP connection for state sending, etc. Also used for commands.
|
||||
int udp_fd; // UDP connection for game state updates.
|
||||
unsigned port; // Which port is governed by netplay (other player)?
|
||||
|
@ -188,24 +187,32 @@ void input_poll_net(void)
|
|||
netplay_poll(g_extern.netplay);
|
||||
}
|
||||
|
||||
void video_frame_net(const uint16_t *data, unsigned width, unsigned height)
|
||||
void video_frame_net(const void *data, unsigned width, unsigned height, size_t pitch)
|
||||
{
|
||||
if (!netplay_should_skip(g_extern.netplay))
|
||||
netplay_callbacks(g_extern.netplay)->frame_cb(data, width, height);
|
||||
g_extern.netplay->cbs.frame_cb(data, width, height, pitch);
|
||||
}
|
||||
|
||||
void audio_sample_net(uint16_t left, uint16_t right)
|
||||
void audio_sample_net(int16_t left, int16_t right)
|
||||
{
|
||||
if (!netplay_should_skip(g_extern.netplay))
|
||||
netplay_callbacks(g_extern.netplay)->sample_cb(left, right);
|
||||
g_extern.netplay->cbs.sample_cb(left, right);
|
||||
}
|
||||
|
||||
int16_t input_state_net(bool port, unsigned device, unsigned index, unsigned id)
|
||||
size_t audio_sample_batch_net(const int16_t *data, size_t frames)
|
||||
{
|
||||
if (!netplay_should_skip(g_extern.netplay))
|
||||
return g_extern.netplay->cbs.sample_batch_cb(data, frames);
|
||||
else
|
||||
return frames;
|
||||
}
|
||||
|
||||
int16_t input_state_net(unsigned port, unsigned device, unsigned index, unsigned id)
|
||||
{
|
||||
if (netplay_is_alive(g_extern.netplay))
|
||||
return netplay_input_state(g_extern.netplay, port, device, index, id);
|
||||
else
|
||||
return netplay_callbacks(g_extern.netplay)->state_cb(port, device, index, id);
|
||||
return g_extern.netplay->cbs.state_cb(port, device, index, id);
|
||||
}
|
||||
|
||||
#ifndef HAVE_SOCKET_LEGACY
|
||||
|
@ -447,18 +454,20 @@ bool netplay_can_poll(netplay_t *handle)
|
|||
static uint32_t implementation_magic_value(void)
|
||||
{
|
||||
uint32_t res = 0;
|
||||
unsigned major = psnes_library_revision_major();
|
||||
unsigned minor = psnes_library_revision_minor();
|
||||
unsigned api = pretro_api_version();
|
||||
|
||||
res |= (major & 0xf) << 0;
|
||||
res |= (minor & 0xf) << 4;
|
||||
res |= api;
|
||||
|
||||
// Shouldn't really use this, but oh well :) It'll do the job.
|
||||
const char *lib = psnes_library_id();
|
||||
const char *lib = g_extern.system.info.library_name;
|
||||
size_t len = strlen(lib);
|
||||
for (size_t i = 0; i < len; i++)
|
||||
res ^= lib[i] << (i & 0xf);
|
||||
|
||||
lib = g_extern.system.info.library_version;
|
||||
len = strlen(lib);
|
||||
for (size_t i = 0; i < len; i++)
|
||||
res ^= lib[i] << (i & 0xf);
|
||||
|
||||
const char *ver = PACKAGE_VERSION;
|
||||
len = strlen(ver);
|
||||
for (size_t i = 0; i < len; i++)
|
||||
|
@ -516,7 +525,7 @@ static bool send_info(netplay_t *handle)
|
|||
uint32_t header[3] = {
|
||||
htonl(g_extern.cart_crc),
|
||||
htonl(implementation_magic_value()),
|
||||
htonl(psnes_get_memory_size(SNES_MEMORY_CARTRIDGE_RAM))
|
||||
htonl(pretro_get_memory_size(RETRO_MEMORY_SAVE_RAM))
|
||||
};
|
||||
|
||||
if (!send_all(handle->fd, header, sizeof(header)))
|
||||
|
@ -528,9 +537,9 @@ static bool send_info(netplay_t *handle)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Get SRAM data from Player 1 :)
|
||||
uint8_t *sram = psnes_get_memory_data(SNES_MEMORY_CARTRIDGE_RAM);
|
||||
unsigned sram_size = psnes_get_memory_size(SNES_MEMORY_CARTRIDGE_RAM);
|
||||
// Get SRAM data from Player 1.
|
||||
void *sram = pretro_get_memory_data(RETRO_MEMORY_SAVE_RAM);
|
||||
unsigned sram_size = pretro_get_memory_size(RETRO_MEMORY_SAVE_RAM);
|
||||
|
||||
if (!recv_all(handle->fd, sram, sram_size))
|
||||
{
|
||||
|
@ -574,7 +583,7 @@ static bool get_info(netplay_t *handle)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (psnes_get_memory_size(SNES_MEMORY_CARTRIDGE_RAM) != ntohl(header[2]))
|
||||
if (pretro_get_memory_size(RETRO_MEMORY_SAVE_RAM) != ntohl(header[2]))
|
||||
{
|
||||
SSNES_ERR("Cartridge SRAM sizes do not correspond.\n");
|
||||
return false;
|
||||
|
@ -586,9 +595,9 @@ static bool get_info(netplay_t *handle)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Send SRAM data to our Player 2 :)
|
||||
const uint8_t *sram = psnes_get_memory_data(SNES_MEMORY_CARTRIDGE_RAM);
|
||||
unsigned sram_size = psnes_get_memory_size(SNES_MEMORY_CARTRIDGE_RAM);
|
||||
// Send SRAM data to our Player 2.
|
||||
const void *sram = pretro_get_memory_data(RETRO_MEMORY_SAVE_RAM);
|
||||
unsigned sram_size = pretro_get_memory_size(RETRO_MEMORY_SAVE_RAM);
|
||||
if (!send_all(handle->fd, sram, sram_size))
|
||||
{
|
||||
SSNES_ERR("Failed to send SRAM data to client.\n");
|
||||
|
@ -611,7 +620,7 @@ static bool get_info(netplay_t *handle)
|
|||
static uint32_t *bsv_header_generate(size_t *size, uint32_t magic)
|
||||
{
|
||||
uint32_t bsv_header[4] = {0};
|
||||
unsigned serialize_size = psnes_serialize_size();
|
||||
size_t serialize_size = pretro_serialize_size();
|
||||
size_t header_size = sizeof(bsv_header) + serialize_size;
|
||||
*size = header_size;
|
||||
|
||||
|
@ -624,7 +633,7 @@ static uint32_t *bsv_header_generate(size_t *size, uint32_t magic)
|
|||
bsv_header[CRC_INDEX] = swap_if_big32(g_extern.cart_crc);
|
||||
bsv_header[STATE_SIZE_INDEX] = swap_if_big32(serialize_size);
|
||||
|
||||
if (serialize_size && !psnes_serialize((uint8_t*)header + sizeof(bsv_header), serialize_size))
|
||||
if (serialize_size && !pretro_serialize(header + sizeof(bsv_header), serialize_size))
|
||||
{
|
||||
free(header);
|
||||
return NULL;
|
||||
|
@ -659,10 +668,10 @@ static bool bsv_parse_header(const uint32_t *header, uint32_t magic)
|
|||
}
|
||||
|
||||
uint32_t in_state_size = swap_if_big32(header[STATE_SIZE_INDEX]);
|
||||
if (in_state_size != psnes_serialize_size())
|
||||
if (in_state_size != pretro_serialize_size())
|
||||
{
|
||||
SSNES_ERR("Serialization size mismatch, got 0x%x, expected 0x%x.\n",
|
||||
in_state_size, psnes_serialize_size());
|
||||
(unsigned)in_state_size, (unsigned)pretro_serialize_size());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -696,30 +705,29 @@ static bool get_info_spectate(netplay_t *handle)
|
|||
return false;
|
||||
}
|
||||
|
||||
unsigned save_state_size = psnes_serialize_size();
|
||||
size_t save_state_size = pretro_serialize_size();
|
||||
if (!bsv_parse_header(header, implementation_magic_value()))
|
||||
{
|
||||
SSNES_ERR("Received invalid BSV header from host.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t *buf = (uint8_t*)malloc(save_state_size);
|
||||
void *buf = malloc(save_state_size);
|
||||
if (!buf)
|
||||
return false;
|
||||
|
||||
size_t size = save_state_size;
|
||||
uint8_t *tmp_buf = buf;
|
||||
|
||||
if (!recv_all(handle->fd, tmp_buf, size))
|
||||
if (!recv_all(handle->fd, buf, size))
|
||||
{
|
||||
SSNES_ERR("Failed to receive save state from host.\n");
|
||||
free(tmp_buf);
|
||||
free(buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = true;
|
||||
if (save_state_size)
|
||||
ret = psnes_unserialize(buf, save_state_size);
|
||||
ret = pretro_unserialize(buf, save_state_size);
|
||||
|
||||
free(buf);
|
||||
return ret;
|
||||
|
@ -728,16 +736,16 @@ static bool get_info_spectate(netplay_t *handle)
|
|||
static void init_buffers(netplay_t *handle)
|
||||
{
|
||||
handle->buffer = (struct delta_frame*)calloc(handle->buffer_size, sizeof(*handle->buffer));
|
||||
handle->state_size = psnes_serialize_size();
|
||||
handle->state_size = pretro_serialize_size();
|
||||
for (unsigned i = 0; i < handle->buffer_size; i++)
|
||||
{
|
||||
handle->buffer[i].state = (uint8_t*)malloc(handle->state_size);
|
||||
handle->buffer[i].state = malloc(handle->state_size);
|
||||
handle->buffer[i].is_simulated = true;
|
||||
}
|
||||
}
|
||||
|
||||
netplay_t *netplay_new(const char *server, uint16_t port,
|
||||
unsigned frames, const struct snes_callbacks *cb,
|
||||
unsigned frames, const struct retro_callbacks *cb,
|
||||
bool spectate,
|
||||
const char *nick)
|
||||
{
|
||||
|
@ -896,11 +904,11 @@ static bool get_self_input_state(netplay_t *handle)
|
|||
uint32_t state = 0;
|
||||
if (handle->frame_count > 0) // First frame we always give zero input since relying on input from first frame screws up when we use -F 0.
|
||||
{
|
||||
snes_input_state_t cb = handle->cbs.state_cb;
|
||||
retro_input_state_t cb = handle->cbs.state_cb;
|
||||
for (unsigned i = 0; i < SSNES_FIRST_META_KEY; i++)
|
||||
{
|
||||
int16_t tmp = cb(g_settings.input.netplay_client_swap_input ? 0 : !handle->port,
|
||||
SNES_DEVICE_JOYPAD, 0, i);
|
||||
RETRO_DEVICE_JOYPAD, 0, i);
|
||||
state |= tmp ? 1 << i : 0;
|
||||
}
|
||||
}
|
||||
|
@ -1221,11 +1229,6 @@ void netplay_free(netplay_t *handle)
|
|||
free(handle);
|
||||
}
|
||||
|
||||
static const struct snes_callbacks* netplay_callbacks(netplay_t *handle)
|
||||
{
|
||||
return &handle->cbs;
|
||||
}
|
||||
|
||||
static bool netplay_should_skip(netplay_t *handle)
|
||||
{
|
||||
return handle->is_replay && handle->has_connection;
|
||||
|
@ -1233,7 +1236,7 @@ static bool netplay_should_skip(netplay_t *handle)
|
|||
|
||||
static void netplay_pre_frame_net(netplay_t *handle)
|
||||
{
|
||||
psnes_serialize(handle->buffer[handle->self_ptr].state, handle->state_size);
|
||||
pretro_serialize(handle->buffer[handle->self_ptr].state, handle->state_size);
|
||||
handle->can_poll = true;
|
||||
|
||||
input_poll_net();
|
||||
|
@ -1252,9 +1255,9 @@ static void netplay_set_spectate_input(netplay_t *handle, int16_t input)
|
|||
handle->spectate_input[handle->spectate_input_ptr++] = swap_if_big16(input);
|
||||
}
|
||||
|
||||
int16_t input_state_spectate(bool port, unsigned device, unsigned index, unsigned id)
|
||||
int16_t input_state_spectate(unsigned port, unsigned device, unsigned index, unsigned id)
|
||||
{
|
||||
int16_t res = netplay_callbacks(g_extern.netplay)->state_cb(port, device, index, id);
|
||||
int16_t res = g_extern.netplay->cbs.state_cb(port, device, index, id);
|
||||
netplay_set_spectate_input(g_extern.netplay, res);
|
||||
return res;
|
||||
}
|
||||
|
@ -1270,12 +1273,12 @@ static int16_t netplay_get_spectate_input(netplay_t *handle, bool port, unsigned
|
|||
msg_queue_clear(g_extern.msg_queue);
|
||||
msg_queue_push(g_extern.msg_queue, "Connection with host was cut.", 1, 180);
|
||||
|
||||
psnes_set_input_state(netplay_callbacks(g_extern.netplay)->state_cb);
|
||||
return netplay_callbacks(g_extern.netplay)->state_cb(port, device, index, id);
|
||||
pretro_set_input_state(g_extern.netplay->cbs.state_cb);
|
||||
return g_extern.netplay->cbs.state_cb(port, device, index, id);
|
||||
}
|
||||
}
|
||||
|
||||
int16_t input_state_spectate_client(bool port, unsigned device, unsigned index, unsigned id)
|
||||
int16_t input_state_spectate_client(unsigned port, unsigned device, unsigned index, unsigned id)
|
||||
{
|
||||
return netplay_get_spectate_input(g_extern.netplay, port, device, index, id);
|
||||
}
|
||||
|
@ -1397,15 +1400,15 @@ static void netplay_post_frame_net(netplay_t *handle)
|
|||
handle->tmp_ptr = handle->other_ptr;
|
||||
handle->tmp_frame_count = handle->other_frame_count;
|
||||
|
||||
psnes_unserialize(handle->buffer[handle->other_ptr].state, handle->state_size);
|
||||
pretro_unserialize(handle->buffer[handle->other_ptr].state, handle->state_size);
|
||||
bool first = true;
|
||||
while (first || (handle->tmp_ptr != handle->self_ptr))
|
||||
{
|
||||
psnes_serialize(handle->buffer[handle->tmp_ptr].state, handle->state_size);
|
||||
pretro_serialize(handle->buffer[handle->tmp_ptr].state, handle->state_size);
|
||||
#ifdef HAVE_THREADS
|
||||
lock_autosave();
|
||||
#endif
|
||||
psnes_run();
|
||||
pretro_run();
|
||||
#ifdef HAVE_THREADS
|
||||
unlock_autosave();
|
||||
#endif
|
||||
|
|
|
@ -26,9 +26,9 @@
|
|||
|
||||
void input_poll_net(void);
|
||||
int16_t input_state_net(unsigned port, unsigned device, unsigned index, unsigned id);
|
||||
void video_frame_net(const uint16_t *data, unsigned width, unsigned height, size_t pitch);
|
||||
void video_frame_net(const void *data, unsigned width, unsigned height, size_t pitch);
|
||||
void audio_sample_net(int16_t left, int16_t right);
|
||||
void audio_sample_batch_net(const int16_t *data, size_t frames);
|
||||
size_t audio_sample_batch_net(const int16_t *data, size_t frames);
|
||||
|
||||
int16_t input_state_spectate(unsigned port, unsigned device, unsigned index, unsigned id);
|
||||
int16_t input_state_spectate_client(unsigned port, unsigned device, unsigned index, unsigned id);
|
||||
|
|
48
settings.c
48
settings.c
|
@ -525,35 +525,35 @@ struct bind_map
|
|||
#define DECLARE_BIND(x, bind) { true, "input_" #x, "input_" #x "_btn", "input_" #x "_axis", bind }
|
||||
#define DECL_PLAYER(P) \
|
||||
{ \
|
||||
DECLARE_BIND(player##P##_b, SNES_DEVICE_ID_JOYPAD_B), \
|
||||
DECLARE_BIND(player##P##_y, SNES_DEVICE_ID_JOYPAD_Y), \
|
||||
DECLARE_BIND(player##P##_select, SNES_DEVICE_ID_JOYPAD_SELECT), \
|
||||
DECLARE_BIND(player##P##_start, SNES_DEVICE_ID_JOYPAD_START), \
|
||||
DECLARE_BIND(player##P##_up, SNES_DEVICE_ID_JOYPAD_UP), \
|
||||
DECLARE_BIND(player##P##_down, SNES_DEVICE_ID_JOYPAD_DOWN), \
|
||||
DECLARE_BIND(player##P##_left, SNES_DEVICE_ID_JOYPAD_LEFT), \
|
||||
DECLARE_BIND(player##P##_right, SNES_DEVICE_ID_JOYPAD_RIGHT), \
|
||||
DECLARE_BIND(player##P##_a, SNES_DEVICE_ID_JOYPAD_A), \
|
||||
DECLARE_BIND(player##P##_x, SNES_DEVICE_ID_JOYPAD_X), \
|
||||
DECLARE_BIND(player##P##_l, SNES_DEVICE_ID_JOYPAD_L), \
|
||||
DECLARE_BIND(player##P##_r, SNES_DEVICE_ID_JOYPAD_R), \
|
||||
DECLARE_BIND(player##P##_b, RETRO_DEVICE_ID_JOYPAD_B), \
|
||||
DECLARE_BIND(player##P##_y, RETRO_DEVICE_ID_JOYPAD_Y), \
|
||||
DECLARE_BIND(player##P##_select, RETRO_DEVICE_ID_JOYPAD_SELECT), \
|
||||
DECLARE_BIND(player##P##_start, RETRO_DEVICE_ID_JOYPAD_START), \
|
||||
DECLARE_BIND(player##P##_up, RETRO_DEVICE_ID_JOYPAD_UP), \
|
||||
DECLARE_BIND(player##P##_down, RETRO_DEVICE_ID_JOYPAD_DOWN), \
|
||||
DECLARE_BIND(player##P##_left, RETRO_DEVICE_ID_JOYPAD_LEFT), \
|
||||
DECLARE_BIND(player##P##_right, RETRO_DEVICE_ID_JOYPAD_RIGHT), \
|
||||
DECLARE_BIND(player##P##_a, RETRO_DEVICE_ID_JOYPAD_A), \
|
||||
DECLARE_BIND(player##P##_x, RETRO_DEVICE_ID_JOYPAD_X), \
|
||||
DECLARE_BIND(player##P##_l, RETRO_DEVICE_ID_JOYPAD_L), \
|
||||
DECLARE_BIND(player##P##_r, RETRO_DEVICE_ID_JOYPAD_R), \
|
||||
}
|
||||
|
||||
// Big and nasty bind map... :)
|
||||
static const struct bind_map bind_maps[MAX_PLAYERS][SSNES_BIND_LIST_END] = {
|
||||
{
|
||||
DECLARE_BIND(player1_b, SNES_DEVICE_ID_JOYPAD_B),
|
||||
DECLARE_BIND(player1_y, SNES_DEVICE_ID_JOYPAD_Y),
|
||||
DECLARE_BIND(player1_select, SNES_DEVICE_ID_JOYPAD_SELECT),
|
||||
DECLARE_BIND(player1_start, SNES_DEVICE_ID_JOYPAD_START),
|
||||
DECLARE_BIND(player1_up, SNES_DEVICE_ID_JOYPAD_UP),
|
||||
DECLARE_BIND(player1_down, SNES_DEVICE_ID_JOYPAD_DOWN),
|
||||
DECLARE_BIND(player1_left, SNES_DEVICE_ID_JOYPAD_LEFT),
|
||||
DECLARE_BIND(player1_right, SNES_DEVICE_ID_JOYPAD_RIGHT),
|
||||
DECLARE_BIND(player1_a, SNES_DEVICE_ID_JOYPAD_A),
|
||||
DECLARE_BIND(player1_x, SNES_DEVICE_ID_JOYPAD_X),
|
||||
DECLARE_BIND(player1_l, SNES_DEVICE_ID_JOYPAD_L),
|
||||
DECLARE_BIND(player1_r, SNES_DEVICE_ID_JOYPAD_R),
|
||||
DECLARE_BIND(player1_b, RETRO_DEVICE_ID_JOYPAD_B),
|
||||
DECLARE_BIND(player1_y, RETRO_DEVICE_ID_JOYPAD_Y),
|
||||
DECLARE_BIND(player1_select, RETRO_DEVICE_ID_JOYPAD_SELECT),
|
||||
DECLARE_BIND(player1_start, RETRO_DEVICE_ID_JOYPAD_START),
|
||||
DECLARE_BIND(player1_up, RETRO_DEVICE_ID_JOYPAD_UP),
|
||||
DECLARE_BIND(player1_down, RETRO_DEVICE_ID_JOYPAD_DOWN),
|
||||
DECLARE_BIND(player1_left, RETRO_DEVICE_ID_JOYPAD_LEFT),
|
||||
DECLARE_BIND(player1_right, RETRO_DEVICE_ID_JOYPAD_RIGHT),
|
||||
DECLARE_BIND(player1_a, RETRO_DEVICE_ID_JOYPAD_A),
|
||||
DECLARE_BIND(player1_x, RETRO_DEVICE_ID_JOYPAD_X),
|
||||
DECLARE_BIND(player1_l, RETRO_DEVICE_ID_JOYPAD_L),
|
||||
DECLARE_BIND(player1_r, RETRO_DEVICE_ID_JOYPAD_R),
|
||||
|
||||
DECLARE_BIND(toggle_fast_forward, SSNES_FAST_FORWARD_KEY),
|
||||
DECLARE_BIND(hold_fast_forward, SSNES_FAST_FORWARD_HOLD_KEY),
|
||||
|
|
220
ssnes.c
220
ssnes.c
|
@ -341,13 +341,22 @@ static bool audio_flush(const int16_t *data, size_t samples)
|
|||
}
|
||||
#endif
|
||||
|
||||
static void audio_sample_rewind(uint16_t left, uint16_t right)
|
||||
static void audio_sample_rewind(int16_t left, int16_t right)
|
||||
{
|
||||
g_extern.audio_data.rewind_buf[--g_extern.audio_data.rewind_ptr] = right;
|
||||
g_extern.audio_data.rewind_buf[--g_extern.audio_data.rewind_ptr] = left;
|
||||
}
|
||||
|
||||
static void audio_sample(uint16_t left, uint16_t right)
|
||||
size_t audio_sample_batch_rewind(const int16_t *data, size_t frames)
|
||||
{
|
||||
size_t samples = frames << 1;
|
||||
for (size_t i = 0; i < samples; i++)
|
||||
g_extern.audio_data.rewind_buf[--g_extern.audio_data.rewind_ptr] = data[i];
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
static void audio_sample(int16_t left, int16_t right)
|
||||
{
|
||||
g_extern.audio_data.conv_outsamples[g_extern.audio_data.data_ptr++] = left;
|
||||
g_extern.audio_data.conv_outsamples[g_extern.audio_data.data_ptr++] = right;
|
||||
|
@ -361,9 +370,7 @@ static void audio_sample(uint16_t left, uint16_t right)
|
|||
g_extern.audio_data.data_ptr = 0;
|
||||
}
|
||||
|
||||
// Non-standard, alternative callback better suited for systems that process audio in batch.
|
||||
// Avoids tons of calls to audio_sample() ...
|
||||
unsigned audio_sample_batch(const int16_t *data, unsigned frames)
|
||||
size_t audio_sample_batch(const int16_t *data, size_t frames)
|
||||
{
|
||||
if (frames > (AUDIO_CHUNK_SIZE_NONBLOCKING >> 1))
|
||||
frames = AUDIO_CHUNK_SIZE_NONBLOCKING >> 1;
|
||||
|
@ -377,8 +384,10 @@ static void input_poll(void)
|
|||
input_poll_func();
|
||||
}
|
||||
|
||||
static int16_t input_state(bool port, unsigned device, unsigned index, unsigned id)
|
||||
static int16_t input_state(unsigned port, unsigned device, unsigned index, unsigned id)
|
||||
{
|
||||
device &= RETRO_DEVICE_MASK;
|
||||
|
||||
#ifdef HAVE_BSV_MOVIE
|
||||
if (g_extern.bsv.movie && g_extern.bsv.movie_playback)
|
||||
{
|
||||
|
@ -544,7 +553,7 @@ static void print_help(void)
|
|||
|
||||
static void set_basename(const char *path)
|
||||
{
|
||||
strlcpy(g_extern.system.fullpath, path, sizeof(g_extern.system.fullpath));
|
||||
strlcpy(g_extern.fullpath, path, sizeof(g_extern.fullpath));
|
||||
|
||||
strlcpy(g_extern.basename, path, sizeof(g_extern.basename));
|
||||
char *dst = strrchr(g_extern.basename, '.');
|
||||
|
@ -1027,24 +1036,24 @@ static inline void load_save_files(void)
|
|||
switch (g_extern.game_type)
|
||||
{
|
||||
case SSNES_CART_NORMAL:
|
||||
load_ram_file(g_extern.savefile_name_srm, SNES_MEMORY_CARTRIDGE_RAM);
|
||||
load_ram_file(g_extern.savefile_name_rtc, SNES_MEMORY_CARTRIDGE_RTC);
|
||||
load_ram_file(g_extern.savefile_name_srm, RETRO_MEMORY_SAVE_RAM);
|
||||
load_ram_file(g_extern.savefile_name_rtc, RETRO_MEMORY_RTC);
|
||||
break;
|
||||
|
||||
case SSNES_CART_SGB:
|
||||
save_ram_file(g_extern.savefile_name_srm, SNES_MEMORY_GAME_BOY_RAM);
|
||||
save_ram_file(g_extern.savefile_name_rtc, SNES_MEMORY_GAME_BOY_RTC);
|
||||
save_ram_file(g_extern.savefile_name_srm, RETRO_MEMORY_SNES_GAME_BOY_RAM);
|
||||
save_ram_file(g_extern.savefile_name_rtc, RETRO_MEMORY_SNES_GAME_BOY_RTC);
|
||||
break;
|
||||
|
||||
case SSNES_CART_BSX:
|
||||
case SSNES_CART_BSX_SLOTTED:
|
||||
load_ram_file(g_extern.savefile_name_srm, SNES_MEMORY_BSX_RAM);
|
||||
load_ram_file(g_extern.savefile_name_psrm, SNES_MEMORY_BSX_PRAM);
|
||||
load_ram_file(g_extern.savefile_name_srm, RETRO_MEMORY_SNES_BSX_RAM);
|
||||
load_ram_file(g_extern.savefile_name_psrm, RETRO_MEMORY_SNES_BSX_PRAM);
|
||||
break;
|
||||
|
||||
case SSNES_CART_SUFAMI:
|
||||
load_ram_file(g_extern.savefile_name_asrm, SNES_MEMORY_SUFAMI_TURBO_A_RAM);
|
||||
load_ram_file(g_extern.savefile_name_bsrm, SNES_MEMORY_SUFAMI_TURBO_B_RAM);
|
||||
load_ram_file(g_extern.savefile_name_asrm, RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM);
|
||||
load_ram_file(g_extern.savefile_name_bsrm, RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1058,27 +1067,27 @@ static inline void save_files(void)
|
|||
{
|
||||
case SSNES_CART_NORMAL:
|
||||
SSNES_LOG("Saving regular SRAM.\n");
|
||||
save_ram_file(g_extern.savefile_name_srm, SNES_MEMORY_CARTRIDGE_RAM);
|
||||
save_ram_file(g_extern.savefile_name_rtc, SNES_MEMORY_CARTRIDGE_RTC);
|
||||
save_ram_file(g_extern.savefile_name_srm, RETRO_MEMORY_SAVE_RAM);
|
||||
save_ram_file(g_extern.savefile_name_rtc, RETRO_MEMORY_RTC);
|
||||
break;
|
||||
|
||||
case SSNES_CART_SGB:
|
||||
SSNES_LOG("Saving Gameboy SRAM.\n");
|
||||
save_ram_file(g_extern.savefile_name_srm, SNES_MEMORY_GAME_BOY_RAM);
|
||||
save_ram_file(g_extern.savefile_name_rtc, SNES_MEMORY_GAME_BOY_RTC);
|
||||
save_ram_file(g_extern.savefile_name_srm, RETRO_MEMORY_SNES_GAME_BOY_RAM);
|
||||
save_ram_file(g_extern.savefile_name_rtc, RETRO_MEMORY_SNES_GAME_BOY_RTC);
|
||||
break;
|
||||
|
||||
case SSNES_CART_BSX:
|
||||
case SSNES_CART_BSX_SLOTTED:
|
||||
SSNES_LOG("Saving BSX (P)RAM.\n");
|
||||
save_ram_file(g_extern.savefile_name_srm, SNES_MEMORY_BSX_RAM);
|
||||
save_ram_file(g_extern.savefile_name_psrm, SNES_MEMORY_BSX_PRAM);
|
||||
save_ram_file(g_extern.savefile_name_srm, RETRO_MEMORY_SNES_BSX_RAM);
|
||||
save_ram_file(g_extern.savefile_name_psrm, RETRO_MEMORY_SNES_BSX_PRAM);
|
||||
break;
|
||||
|
||||
case SSNES_CART_SUFAMI:
|
||||
SSNES_LOG("Saving Sufami turbo A/B RAM.\n");
|
||||
save_ram_file(g_extern.savefile_name_asrm, SNES_MEMORY_SUFAMI_TURBO_A_RAM);
|
||||
save_ram_file(g_extern.savefile_name_bsrm, SNES_MEMORY_SUFAMI_TURBO_B_RAM);
|
||||
save_ram_file(g_extern.savefile_name_asrm, RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM);
|
||||
save_ram_file(g_extern.savefile_name_bsrm, RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1093,26 +1102,21 @@ static void init_recording(void)
|
|||
if (!g_extern.recording)
|
||||
return;
|
||||
|
||||
// Canonical values.
|
||||
double fps = psnes_get_region() == SNES_REGION_NTSC ? 60.00 : 50.00;
|
||||
double samplerate = 32000.0;
|
||||
if (g_extern.system.timing_set)
|
||||
{
|
||||
fps = g_extern.system.timing.fps;
|
||||
samplerate = g_extern.system.timing.sample_rate;
|
||||
SSNES_LOG("Custom timing given: FPS: %.4f, Sample rate: %.4f\n", (float)fps, (float)samplerate);
|
||||
}
|
||||
double fps = g_extern.system.av_info.timing.fps;
|
||||
double samplerate = g_extern.system.av_info.timing.sample_rate;
|
||||
SSNES_LOG("Custom timing given: FPS: %.4f, Sample rate: %.4f\n", (float)fps, (float)samplerate);
|
||||
|
||||
struct ffemu_params params = {0};
|
||||
params.out_width = g_extern.system.geom.base_width;
|
||||
params.out_height = g_extern.system.geom.base_height;
|
||||
params.fb_width = g_extern.system.geom.max_width;
|
||||
params.fb_height = g_extern.system.geom.max_height;
|
||||
params.channels = 2;
|
||||
params.filename = g_extern.record_path;
|
||||
params.fps = fps;
|
||||
const struct retro_system_av_info *info = &g_extern.system.av_info;
|
||||
params.out_width = info->geometry.base_width;
|
||||
params.out_height = info->geometry.base_height;
|
||||
params.fb_width = info->geometry.max_width;
|
||||
params.fb_height = info->geometry.max_height;
|
||||
params.channels = 2;
|
||||
params.filename = g_extern.record_path;
|
||||
params.fps = fps;
|
||||
params.samplerate = samplerate;
|
||||
params.rgb32 = false;
|
||||
params.rgb32 = false;
|
||||
|
||||
if (g_extern.record_width || g_extern.record_height)
|
||||
{
|
||||
|
@ -1191,7 +1195,7 @@ static void init_rewind(void)
|
|||
if (!g_settings.rewind_enable)
|
||||
return;
|
||||
|
||||
g_extern.state_size = psnes_serialize_size();
|
||||
g_extern.state_size = pretro_serialize_size();
|
||||
|
||||
// Make sure we allocate at least 4-byte multiple.
|
||||
size_t aligned_state_size = (g_extern.state_size + 3) & ~3;
|
||||
|
@ -1203,7 +1207,7 @@ static void init_rewind(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!psnes_serialize((uint8_t*)g_extern.state_buf, g_extern.state_size))
|
||||
if (!pretro_serialize(g_extern.state_buf, g_extern.state_size))
|
||||
{
|
||||
SSNES_ERR("Failed to perform initial serialization for rewind.\n");
|
||||
free(g_extern.state_buf);
|
||||
|
@ -1279,9 +1283,10 @@ static void init_netplay(void)
|
|||
if (!g_extern.netplay_enable)
|
||||
return;
|
||||
|
||||
struct snes_callbacks cbs = {0};
|
||||
struct retro_callbacks cbs = {0};
|
||||
cbs.frame_cb = video_frame;
|
||||
cbs.sample_cb = audio_sample;
|
||||
cbs.sample_batch_cb = audio_sample_batch;
|
||||
cbs.state_cb = input_state;
|
||||
|
||||
if (*g_extern.netplay_server)
|
||||
|
@ -1318,32 +1323,37 @@ static void deinit_netplay(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
static void init_libsnes_cbs_plain(void)
|
||||
{
|
||||
pretro_set_video_refresh(video_frame);
|
||||
pretro_set_audio_sample(audio_sample);
|
||||
pretro_set_audio_sample_batch(audio_sample_batch);
|
||||
pretro_set_input_state(input_state);
|
||||
pretro_set_input_poll(input_poll);
|
||||
}
|
||||
|
||||
static void init_libsnes_cbs(void)
|
||||
{
|
||||
#ifdef HAVE_NETPLAY
|
||||
if (g_extern.netplay)
|
||||
{
|
||||
psnes_set_video_refresh(g_extern.netplay_is_spectate ?
|
||||
pretro_set_video_refresh(g_extern.netplay_is_spectate ?
|
||||
video_frame : video_frame_net);
|
||||
psnes_set_audio_sample(g_extern.netplay_is_spectate ?
|
||||
audio_sample : audio_sample_net);
|
||||
|
||||
psnes_set_input_state(g_extern.netplay_is_spectate ?
|
||||
pretro_set_audio_sample(g_extern.netplay_is_spectate ?
|
||||
audio_sample : audio_sample_net);
|
||||
pretro_set_audio_sample_batch(g_extern.netplay_is_spectate ?
|
||||
audio_sample_batch : audio_sample_batch_net);
|
||||
|
||||
pretro_set_input_state(g_extern.netplay_is_spectate ?
|
||||
(g_extern.netplay_is_client ? input_state_spectate_client : input_state_spectate)
|
||||
: input_state_net);
|
||||
}
|
||||
else
|
||||
{
|
||||
psnes_set_video_refresh(video_frame);
|
||||
psnes_set_audio_sample(audio_sample);
|
||||
psnes_set_input_state(input_state);
|
||||
}
|
||||
init_libsnes_cbs_plain();
|
||||
#else
|
||||
psnes_set_video_refresh(video_frame);
|
||||
psnes_set_audio_sample(audio_sample);
|
||||
psnes_set_input_state(input_state);
|
||||
init_libsnes_cbs_plain();
|
||||
#endif
|
||||
psnes_set_input_poll(input_poll);
|
||||
}
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
|
@ -1356,42 +1366,42 @@ static void init_autosave(void)
|
|||
{
|
||||
case SSNES_CART_BSX:
|
||||
case SSNES_CART_BSX_SLOTTED:
|
||||
ram_types[0] = SNES_MEMORY_BSX_RAM;
|
||||
ram_types[1] = SNES_MEMORY_BSX_PRAM;
|
||||
ram_types[0] = RETRO_MEMORY_SNES_BSX_RAM;
|
||||
ram_types[1] = RETRO_MEMORY_SNES_BSX_PRAM;
|
||||
ram_paths[0] = g_extern.savefile_name_srm;
|
||||
ram_paths[1] = g_extern.savefile_name_psrm;
|
||||
break;
|
||||
|
||||
case SSNES_CART_SUFAMI:
|
||||
ram_types[0] = SNES_MEMORY_SUFAMI_TURBO_A_RAM;
|
||||
ram_types[1] = SNES_MEMORY_SUFAMI_TURBO_B_RAM;
|
||||
ram_types[0] = RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM;
|
||||
ram_types[1] = RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM;
|
||||
ram_paths[0] = g_extern.savefile_name_asrm;
|
||||
ram_paths[1] = g_extern.savefile_name_bsrm;
|
||||
break;
|
||||
|
||||
case SSNES_CART_SGB:
|
||||
ram_types[0] = SNES_MEMORY_GAME_BOY_RAM;
|
||||
ram_types[1] = SNES_MEMORY_GAME_BOY_RTC;
|
||||
ram_types[0] = RETRO_MEMORY_SNES_GAME_BOY_RAM;
|
||||
ram_types[1] = RETRO_MEMORY_SNES_GAME_BOY_RTC;
|
||||
ram_paths[0] = g_extern.savefile_name_srm;
|
||||
ram_paths[1] = g_extern.savefile_name_rtc;
|
||||
break;
|
||||
|
||||
default:
|
||||
ram_types[0] = SNES_MEMORY_CARTRIDGE_RAM;
|
||||
ram_types[1] = SNES_MEMORY_CARTRIDGE_RTC;
|
||||
ram_types[0] = RETRO_MEMORY_SAVE_RAM;
|
||||
ram_types[1] = RETRO_MEMORY_RTC;
|
||||
ram_paths[0] = g_extern.savefile_name_srm;
|
||||
ram_paths[1] = g_extern.savefile_name_rtc;
|
||||
}
|
||||
|
||||
if (g_settings.autosave_interval > 0)
|
||||
{
|
||||
for (unsigned i = 0; i < sizeof(g_extern.autosave)/sizeof(g_extern.autosave[0]); i++)
|
||||
for (unsigned i = 0; i < sizeof(g_extern.autosave) / sizeof(g_extern.autosave[0]); i++)
|
||||
{
|
||||
if (ram_paths[i] && strlen(ram_paths[i]) > 0 && psnes_get_memory_size(ram_types[i]) > 0)
|
||||
if (ram_paths[i] && *ram_paths[i] && pretro_get_memory_size(ram_types[i]) > 0)
|
||||
{
|
||||
g_extern.autosave[i] = autosave_new(ram_paths[i],
|
||||
psnes_get_memory_data(ram_types[i]),
|
||||
psnes_get_memory_size(ram_types[i]),
|
||||
pretro_get_memory_data(ram_types[i]),
|
||||
pretro_get_memory_size(ram_types[i]),
|
||||
g_settings.autosave_interval);
|
||||
if (!g_extern.autosave[i])
|
||||
SSNES_WARN("Could not initialize autosave.\n");
|
||||
|
@ -1402,7 +1412,7 @@ static void init_autosave(void)
|
|||
|
||||
static void deinit_autosave(void)
|
||||
{
|
||||
for (unsigned i = 0; i < sizeof(g_extern.autosave)/sizeof(g_extern.autosave[0]); i++)
|
||||
for (unsigned i = 0; i < sizeof(g_extern.autosave) / sizeof(g_extern.autosave[0]); i++)
|
||||
{
|
||||
if (g_extern.autosave[i])
|
||||
autosave_free(g_extern.autosave[i]);
|
||||
|
@ -1786,7 +1796,7 @@ static void check_rewind(void)
|
|||
setup_rewind_audio();
|
||||
|
||||
msg_queue_push(g_extern.msg_queue, "Rewinding.", 0, g_extern.is_paused ? 1 : 30);
|
||||
psnes_unserialize((uint8_t*)buf, g_extern.state_size);
|
||||
pretro_unserialize(buf, g_extern.state_size);
|
||||
|
||||
#ifdef HAVE_BSV_MOVIE
|
||||
if (g_extern.bsv.movie)
|
||||
|
@ -1806,12 +1816,15 @@ static void check_rewind(void)
|
|||
if (cnt == 0)
|
||||
#endif
|
||||
{
|
||||
psnes_serialize((uint8_t*)g_extern.state_buf, g_extern.state_size);
|
||||
pretro_serialize(g_extern.state_buf, g_extern.state_size);
|
||||
state_manager_push(g_extern.state_manager, g_extern.state_buf);
|
||||
}
|
||||
}
|
||||
|
||||
psnes_set_audio_sample(g_extern.frame_is_reverse ? audio_sample_rewind : audio_sample);
|
||||
pretro_set_audio_sample(g_extern.frame_is_reverse ?
|
||||
audio_sample_rewind : audio_sample);
|
||||
pretro_set_audio_sample_batch(g_extern.frame_is_reverse ?
|
||||
audio_sample_batch_rewind : audio_sample_batch);
|
||||
}
|
||||
|
||||
static void check_slowmotion(void)
|
||||
|
@ -1980,7 +1993,7 @@ void ssnes_game_reset(void)
|
|||
SSNES_LOG("Resetting game.\n");
|
||||
msg_queue_clear(g_extern.msg_queue);
|
||||
msg_queue_push(g_extern.msg_queue, "Reset.", 1, 120);
|
||||
psnes_reset();
|
||||
pretro_reset();
|
||||
init_controllers(); // bSNES since v073r01 resets controllers to JOYPAD after a reset, so just enforce it here.
|
||||
}
|
||||
|
||||
|
@ -2206,11 +2219,6 @@ static void do_state_checks(void)
|
|||
check_input_rate();
|
||||
}
|
||||
|
||||
static void fill_title_buf(void)
|
||||
{
|
||||
snprintf(g_extern.title_buf, sizeof(g_extern.title_buf), "SSNES : %s", psnes_library_id());
|
||||
}
|
||||
|
||||
static void init_state(void)
|
||||
{
|
||||
g_extern.video_active = true;
|
||||
|
@ -2233,6 +2241,33 @@ void ssnes_main_clear_state(void)
|
|||
init_state();
|
||||
}
|
||||
|
||||
static void init_system_info(void)
|
||||
{
|
||||
struct retro_system_info *info = &g_extern.system.info;
|
||||
retro_get_system_info(info);
|
||||
|
||||
if (!info->library_name)
|
||||
info->library_name = "Unknown";
|
||||
if (!info->library_version)
|
||||
info->library_version = "v0";
|
||||
|
||||
snprintf(g_extern.title_buf, sizeof(g_extern.title_buf), "SSNES : %s %s",
|
||||
info->library_name, info->library_version);
|
||||
}
|
||||
|
||||
static void init_system_av_info(void)
|
||||
{
|
||||
retro_get_system_av_info(&g_extern.system.av_info);
|
||||
}
|
||||
|
||||
static void verify_api_version(void)
|
||||
{
|
||||
SSNES_LOG("Version of libretro API: %u\n", pretro_api_version());
|
||||
SSNES_LOG("Compiled against API: %u\n", RETRO_API_VERSION);
|
||||
if (pretro_api_version() != RETRO_API_VERSION)
|
||||
SSNES_WARN("SSNES is compiled against a different version of libretro than this libretro implementation.\n");
|
||||
}
|
||||
|
||||
int ssnes_main_init(int argc, char *argv[])
|
||||
{
|
||||
init_state();
|
||||
|
@ -2254,16 +2289,14 @@ int ssnes_main_init(int argc, char *argv[])
|
|||
}
|
||||
|
||||
config_load();
|
||||
init_libsnes_sym();
|
||||
fill_title_buf();
|
||||
|
||||
init_libretro_sym();
|
||||
init_system_info();
|
||||
|
||||
init_drivers_pre();
|
||||
|
||||
psnes_init();
|
||||
if (*g_extern.basename)
|
||||
psnes_set_cartridge_basename(g_extern.basename);
|
||||
|
||||
SSNES_LOG("Version of libretro API: %u.%u\n",
|
||||
psnes_library_revision_major(), psnes_library_revision_minor());
|
||||
verify_api_version();
|
||||
pretro_init();
|
||||
|
||||
g_extern.use_sram = true;
|
||||
#ifdef HAVE_XML
|
||||
|
@ -2276,6 +2309,7 @@ int ssnes_main_init(int argc, char *argv[])
|
|||
if (!init_rom_file(g_extern.game_type))
|
||||
goto error;
|
||||
|
||||
init_system_av_info();
|
||||
init_msg_queue();
|
||||
|
||||
if (!g_extern.sram_load_disable)
|
||||
|
@ -2335,10 +2369,10 @@ int ssnes_main_init(int argc, char *argv[])
|
|||
return 0;
|
||||
|
||||
error:
|
||||
psnes_unload_cartridge();
|
||||
psnes_term();
|
||||
pretro_unload_game();
|
||||
pretro_deinit();
|
||||
uninit_drivers();
|
||||
uninit_libsnes_sym();
|
||||
uninit_libretro_sym();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -2378,7 +2412,7 @@ bool ssnes_main_iterate(void)
|
|||
bsv_movie_set_frame_start(g_extern.bsv.movie);
|
||||
#endif
|
||||
|
||||
psnes_run();
|
||||
pretro_run();
|
||||
|
||||
#ifdef HAVE_BSV_MOVIE
|
||||
if (g_extern.bsv.movie)
|
||||
|
@ -2437,10 +2471,10 @@ void ssnes_main_deinit(void)
|
|||
#endif
|
||||
deinit_msg_queue();
|
||||
|
||||
psnes_unload_cartridge();
|
||||
psnes_term();
|
||||
pretro_unload_game();
|
||||
pretro_deinit();
|
||||
uninit_drivers();
|
||||
uninit_libsnes_sym();
|
||||
uninit_libretro_sym();
|
||||
}
|
||||
|
||||
#ifndef SSNES_CONSOLE
|
||||
|
|
Loading…
Add table
Reference in a new issue