Refactor and upgrade Core Options

This commit is contained in:
Ryunam 2021-05-22 21:00:49 +02:00
parent 10f7e32b79
commit 266417f6b6
5 changed files with 1495 additions and 242 deletions

View File

@ -0,0 +1,39 @@
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_inline.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __LIBRETRO_SDK_INLINE_H
#define __LIBRETRO_SDK_INLINE_H
#ifndef INLINE
#if defined(_WIN32) || defined(__INTEL_COMPILER)
#define INLINE __inline
#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
#define INLINE inline
#elif defined(__GNUC__)
#define INLINE __inline__
#else
#define INLINE
#endif
#endif
#endif

View File

@ -1,5 +1,6 @@
#include <cassert>
#include "libretro.h"
#include "libretro_core_options.h"
static retro_environment_t environ_cb;
static retro_video_refresh_t video_cb;
@ -71,265 +72,312 @@ static double get_aspect_ratio()
return ratio;
}
static void flush_variables()
static void update_variables(void)
{
retro_variable variable = { "bsnes_aspect_ratio", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
char key[256];
struct retro_variable var;
var.key = "bsnes_aspect_ratio";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(variable.value, "8:7") == 0)
if (strcmp(var.value, "8:7") == 0)
aspect_ratio_mode = 1;
else if (strcmp(variable.value, "4:3") == 0)
else if (strcmp(var.value, "4:3") == 0)
aspect_ratio_mode = 2;
else if (strcmp(variable.value, "NTSC") == 0)
else if (strcmp(var.value, "NTSC") == 0)
aspect_ratio_mode = 3;
else if (strcmp(variable.value, "PAL") == 0)
else if (strcmp(var.value, "PAL") == 0)
aspect_ratio_mode = 4;
else
aspect_ratio_mode = 0;
}
variable = { "bsnes_blur_emulation", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
{
if (strcmp(variable.value, "ON") == 0)
emulator->configure("Video/BlurEmulation", true);
else if (strcmp(variable.value, "OFF") == 0)
emulator->configure("Video/BlurEmulation", false);
}
var.key = "bsnes_ppu_show_overscan";
var.value = NULL;
variable = { "bsnes_hotfixes", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(variable.value, "ON") == 0)
emulator->configure("Hacks/Hotfixes", true);
else if (strcmp(variable.value, "OFF") == 0)
emulator->configure("Hacks/Hotfixes", false);
}
variable = { "bsnes_entropy", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
{
if (strcmp(variable.value, "None") == 0)
emulator->configure("Hacks/Entropy", "None");
else if (strcmp(variable.value, "Low") == 0)
emulator->configure("Hacks/Entropy", "Low");
else if (strcmp(variable.value, "High") == 0)
emulator->configure("Hacks/Entropy", "High");
}
variable = { "bsnes_cpu_overclock", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
{
int val = atoi(variable.value);
emulator->configure("Hacks/CPU/Overclock", val);
}
variable = { "bsnes_cpu_fastmath", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
{
if (strcmp(variable.value, "ON") == 0)
emulator->configure("Hacks/CPU/FastMath", true);
else if (strcmp(variable.value, "OFF") == 0)
emulator->configure("Hacks/CPU/FastMath", false);
}
variable = { "bsnes_cpu_sa1_overclock", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
{
int val = atoi(variable.value);
emulator->configure("Hacks/SA1/Overclock", val);
}
variable = { "bsnes_cpu_sfx_overclock", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
{
int val = atoi(variable.value);
emulator->configure("Hacks/SuperFX/Overclock", val);
}
variable = { "bsnes_ppu_fast", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
{
if (strcmp(variable.value, "ON") == 0)
emulator->configure("Hacks/PPU/Fast", true);
else if (strcmp(variable.value, "OFF") == 0)
emulator->configure("Hacks/PPU/Fast", false);
}
variable = { "bsnes_ppu_deinterlace", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
{
if (strcmp(variable.value, "ON") == 0)
emulator->configure("Hacks/PPU/Deinterlace", true);
else if (strcmp(variable.value, "OFF") == 0)
emulator->configure("Hacks/PPU/Deinterlace", false);
}
variable = { "bsnes_ppu_no_sprite_limit", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
{
if (strcmp(variable.value, "ON") == 0)
emulator->configure("Hacks/PPU/NoSpriteLimit", true);
else if (strcmp(variable.value, "OFF") == 0)
emulator->configure("Hacks/PPU/NoSpriteLimit", false);
}
variable = { "bsnes_ppu_no_vram_blocking", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
{
if (strcmp(variable.value, "ON") == 0)
emulator->configure("Hacks/PPU/NoVRAMBlocking", true);
else if (strcmp(variable.value, "OFF") == 0)
emulator->configure("Hacks/PPU/NoVRAMBlocking", false);
}
variable = { "bsnes_ppu_show_overscan", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
{
if (strcmp(variable.value, "ON") == 0)
if (strcmp(var.value, "ON") == 0)
program->overscan = true;
else if (strcmp(variable.value, "OFF") == 0)
else if (strcmp(var.value, "OFF") == 0)
program->overscan = false;
}
variable = { "bsnes_mode7_scale", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
var.key = "bsnes_blur_emulation";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
int val = variable.value[0] - '0';
if (strcmp(var.value, "ON") == 0)
emulator->configure("Video/BlurEmulation", true);
else if (strcmp(var.value, "OFF") == 0)
emulator->configure("Video/BlurEmulation", false);
}
var.key = "bsnes_hotfixes";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(var.value, "ON") == 0)
emulator->configure("Hacks/Hotfixes", true);
else if (strcmp(var.value, "OFF") == 0)
emulator->configure("Hacks/Hotfixes", false);
}
var.key = "bsnes_entropy";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(var.value, "None") == 0)
emulator->configure("Hacks/Entropy", "None");
else if (strcmp(var.value, "Low") == 0)
emulator->configure("Hacks/Entropy", "Low");
else if (strcmp(var.value, "High") == 0)
emulator->configure("Hacks/Entropy", "High");
}
var.key = "bsnes_cpu_overclock";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
int val = atoi(var.value);
emulator->configure("Hacks/CPU/Overclock", val);
}
var.key = "bsnes_cpu_fastmath";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(var.value, "ON") == 0)
emulator->configure("Hacks/CPU/FastMath", true);
else if (strcmp(var.value, "OFF") == 0)
emulator->configure("Hacks/CPU/FastMath", false);
}
var.key = "bsnes_cpu_sa1_overclock";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
int val = atoi(var.value);
emulator->configure("Hacks/SA1/Overclock", val);
}
var.key = "bsnes_cpu_sfx_overclock";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
int val = atoi(var.value);
emulator->configure("Hacks/SuperFX/Overclock", val);
}
var.key = "bsnes_ppu_fast";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(var.value, "ON") == 0)
emulator->configure("Hacks/PPU/Fast", true);
else if (strcmp(var.value, "OFF") == 0)
emulator->configure("Hacks/PPU/Fast", false);
}
var.key = "bsnes_ppu_deinterlace";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(var.value, "ON") == 0)
emulator->configure("Hacks/PPU/Deinterlace", true);
else if (strcmp(var.value, "OFF") == 0)
emulator->configure("Hacks/PPU/Deinterlace", false);
}
var.key = "bsnes_ppu_no_sprite_limit";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(var.value, "ON") == 0)
emulator->configure("Hacks/PPU/NoSpriteLimit", true);
else if (strcmp(var.value, "OFF") == 0)
emulator->configure("Hacks/PPU/NoSpriteLimit", false);
}
var.key = "bsnes_ppu_no_vram_blocking";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(var.value, "ON") == 0)
emulator->configure("Hacks/PPU/NoVRAMBlocking", true);
else if (strcmp(var.value, "OFF") == 0)
emulator->configure("Hacks/PPU/NoVRAMBlocking", false);
}
var.key = "bsnes_mode7_scale";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
int val = var.value[0] - '0';
if (val >= 1 && val <= 8)
emulator->configure("Hacks/PPU/Mode7/Scale", val);
}
variable = { "bsnes_mode7_perspective", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
var.key = "bsnes_mode7_perspective";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(variable.value, "ON") == 0)
if (strcmp(var.value, "ON") == 0)
emulator->configure("Hacks/PPU/Mode7/Perspective", true);
else if (strcmp(variable.value, "OFF") == 0)
else if (strcmp(var.value, "OFF") == 0)
emulator->configure("Hacks/PPU/Mode7/Perspective", false);
}
variable = { "bsnes_mode7_supersample", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
var.key = "bsnes_mode7_supersample";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(variable.value, "ON") == 0)
if (strcmp(var.value, "ON") == 0)
emulator->configure("Hacks/PPU/Mode7/Supersample", true);
else if (strcmp(variable.value, "OFF") == 0)
else if (strcmp(var.value, "OFF") == 0)
emulator->configure("Hacks/PPU/Mode7/Supersample", false);
}
variable = { "bsnes_mode7_mosaic", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
var.key = "bsnes_mode7_mosaic";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(variable.value, "ON") == 0)
if (strcmp(var.value, "ON") == 0)
emulator->configure("Hacks/PPU/Mode7/Mosaic", true);
else if (strcmp(variable.value, "OFF") == 0)
else if (strcmp(var.value, "OFF") == 0)
emulator->configure("Hacks/PPU/Mode7/Mosaic", false);
}
variable = { "bsnes_dsp_fast", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
var.key = "bsnes_dsp_fast";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(variable.value, "ON") == 0)
if (strcmp(var.value, "ON") == 0)
emulator->configure("Hacks/DSP/Fast", true);
else if (strcmp(variable.value, "OFF") == 0)
else if (strcmp(var.value, "OFF") == 0)
emulator->configure("Hacks/DSP/Fast", false);
}
variable = { "bsnes_dsp_cubic", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
var.key = "bsnes_dsp_cubic";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(variable.value, "ON") == 0)
if (strcmp(var.value, "ON") == 0)
emulator->configure("Hacks/DSP/Cubic", true);
else if (strcmp(variable.value, "OFF") == 0)
else if (strcmp(var.value, "OFF") == 0)
emulator->configure("Hacks/DSP/Cubic", false);
}
variable = { "bsnes_dsp_echo_shadow", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
var.key = "bsnes_dsp_echo_shadow";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(variable.value, "ON") == 0)
if (strcmp(var.value, "ON") == 0)
emulator->configure("Hacks/DSP/EchoShadow", true);
else if (strcmp(variable.value, "OFF") == 0)
else if (strcmp(var.value, "OFF") == 0)
emulator->configure("Hacks/DSP/EchoShadow", false);
}
variable = { "bsnes_coprocessor_delayed_sync", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
var.key = "bsnes_coprocessor_delayed_sync";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(variable.value, "ON") == 0)
if (strcmp(var.value, "ON") == 0)
emulator->configure("Hacks/Coprocessor/DelayedSync", true);
else if (strcmp(variable.value, "OFF") == 0)
else if (strcmp(var.value, "OFF") == 0)
emulator->configure("Hacks/Coprocessor/DelayedSync", false);
}
variable = { "bsnes_coprocessor_prefer_hle", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
var.key = "bsnes_coprocessor_prefer_hle";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(variable.value, "ON") == 0)
if (strcmp(var.value, "ON") == 0)
emulator->configure("Hacks/Coprocessor/PreferHLE", true);
else if (strcmp(variable.value, "OFF") == 0)
else if (strcmp(var.value, "OFF") == 0)
emulator->configure("Hacks/Coprocessor/PreferHLE", false);
}
variable = { "bsnes_sgb_bios", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
var.key = "bsnes_sgb_bios";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
sgb_bios = variable.value;
sgb_bios = var.value;
}
variable = { "bsnes_run_ahead_frames", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
var.key = "bsnes_run_ahead_frames";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(variable.value, "OFF") == 0)
if (strcmp(var.value, "OFF") == 0)
run_ahead_frames = 0;
else
run_ahead_frames = atoi(variable.value);
run_ahead_frames = atoi(var.value);
}
variable = { "bsnes_touchscreen_lightgun", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
var.key = "bsnes_touchscreen_lightgun";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(variable.value, "ON") == 0)
if (strcmp(var.value, "ON") == 0)
{
emulator->configure("Input/Pointer/Relative", false);
retro_pointer_enabled = true;
}
else
else if (strcmp(var.value, "OFF") == 0)
{
emulator->configure("Input/Pointer/Relative", true);
retro_pointer_enabled = false;
}
}
variable = { "bsnes_touchscreen_lightgun_superscope_reverse", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
var.key = "bsnes_touchscreen_lightgun_superscope_reverse";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(variable.value, "ON") == 0)
{
if (strcmp(var.value, "ON") == 0)
retro_pointer_superscope_reverse_buttons = true;
}
else
{
else if (strcmp(var.value, "OFF") == 0)
retro_pointer_superscope_reverse_buttons = false;
}
}
// Refresh Geometry
}
void update_geometry(void)
{
struct retro_system_av_info avinfo;
retro_get_system_av_info(&avinfo);
avinfo.geometry.aspect_ratio = get_aspect_ratio();
environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, &avinfo);
}
static void check_variables()
{
bool updated = false;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
flush_variables();
}
static uint retro_device_to_snes(unsigned device)
{
switch (device)
@ -486,42 +534,14 @@ static void set_environment_info(retro_environment_t cb)
cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, const_cast<retro_input_descriptor *>(desc));
static const retro_variable vars[] = {
{ "bsnes_aspect_ratio", "Aspect Ratio; Auto|8:7|4:3|NTSC|PAL" },
{ "bsnes_blur_emulation", "Blur emulation; OFF|ON" },
{ "bsnes_entropy", "Entropy (randomization); Low|High|None" },
{ "bsnes_hotfixes", "Hotfixes; OFF|ON" },
{ "bsnes_cpu_overclock", "CPU Overclocking; 100|110|120|130|140|150|160|170|180|190|200|210|220|230|240|250|260|270|280|290|300|310|320|330|340|350|360|370|380|390|400|10|20|30|40|50|60|70|80|90" },
{ "bsnes_cpu_fastmath", "CPU Fast Math; OFF|ON" },
{ "bsnes_sa1_overclock", "SA1 Coprocessor Overclocking; 100|110|120|130|140|150|160|170|180|190|200|210|220|230|240|250|260|270|280|290|300|310|320|330|340|350|360|370|380|390|400|10|20|30|40|50|60|70|80|90" },
{ "bsnes_sfx_overclock", "SuperFX Coprocessor Overclocking; 100|110|120|130|140|150|160|170|180|190|200|210|220|230|240|250|260|270|280|290|300|310|320|330|340|350|360|370|380|390|400|410|420|430|440|450|460|470|480|490|500|510|520|530|540|550|560|570|580|590|600|610|620|630|640|650|660|670|680|690|700|710|720|730|740|750|760|770|780|790|800|10|20|30|40|50|60|70|80|90" },
{ "bsnes_ppu_fast", "PPU Fast mode; ON|OFF" },
{ "bsnes_ppu_deinterlace", "PPU Deinterlace; ON|OFF" },
{ "bsnes_ppu_no_sprite_limit", "PPU No sprite limit; OFF|ON" },
{ "bsnes_ppu_no_vram_blocking", "PPU No VRAM blocking; OFF|ON" },
{ "bsnes_ppu_show_overscan", "Show Overscan; OFF|ON" },
{ "bsnes_mode7_scale", "HD Mode 7 Scale; 1x|2x|3x|4x|5x|6x|7x|8x" },
{ "bsnes_mode7_perspective", "HD Mode 7 Perspective correction; ON|OFF" },
{ "bsnes_mode7_supersample", "HD Mode 7 Supersampling; OFF|ON" },
{ "bsnes_mode7_mosaic", "HD Mode 7 HD->SD Mosaic; ON|OFF" },
{ "bsnes_dsp_fast", "DSP Fast mode; ON|OFF" },
{ "bsnes_dsp_cubic", "DSP Cubic interpolation; OFF|ON" },
{ "bsnes_dsp_echo_shadow", "DSP Echo shadow RAM; OFF|ON" },
{ "bsnes_coprocessor_delayed_sync", "Coprocessor Delayed Sync; ON|OFF" },
{ "bsnes_coprocessor_prefer_hle", "Coprocessor Prefer HLE; ON|OFF" },
{ "bsnes_sgb_bios", "Preferred Super GameBoy BIOS (restart); SGB1.sfc|SGB2.sfc" },
{ "bsnes_run_ahead_frames", "Amount of frames for run-ahead; OFF|1|2|3|4" },
{ "bsnes_touchscreen_lightgun", "Enable Touchscreen Lightgun; ON|OFF" },
{ "bsnes_touchscreen_lightgun_superscope_reverse", "Super Scope Reverse Trigger Buttons; OFF|ON" },
{ nullptr },
};
cb(RETRO_ENVIRONMENT_SET_VARIABLES, const_cast<retro_variable *>(vars));
}
RETRO_API void retro_set_environment(retro_environment_t cb)
void retro_set_environment(retro_environment_t cb)
{
environ_cb = cb;
libretro_set_core_options(environ_cb);
retro_log_callback log = {};
if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log) && log.log)
libretro_print = log.log;
@ -529,48 +549,48 @@ RETRO_API void retro_set_environment(retro_environment_t cb)
set_environment_info(cb);
}
RETRO_API void retro_set_video_refresh(retro_video_refresh_t cb)
void retro_set_video_refresh(retro_video_refresh_t cb)
{
video_cb = cb;
}
RETRO_API void retro_set_audio_sample(retro_audio_sample_t cb)
void retro_set_audio_sample(retro_audio_sample_t cb)
{
audio_cb = cb;
}
RETRO_API void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb)
void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb)
{
audio_batch_cb = cb;
}
RETRO_API void retro_set_input_poll(retro_input_poll_t cb)
void retro_set_input_poll(retro_input_poll_t cb)
{
input_poll = cb;
}
RETRO_API void retro_set_input_state(retro_input_state_t cb)
void retro_set_input_state(retro_input_state_t cb)
{
input_state = cb;
}
RETRO_API void retro_init()
void retro_init()
{
emulator = new SuperFamicom::Interface;
program = new Program;
}
RETRO_API void retro_deinit()
void retro_deinit()
{
delete program;
}
RETRO_API unsigned retro_api_version()
unsigned retro_api_version()
{
return RETRO_API_VERSION;
}
RETRO_API void retro_get_system_info(retro_system_info *info)
void retro_get_system_info(retro_system_info *info)
{
info->library_name = "bsnes";
info->library_version = Emulator::Version;
@ -579,7 +599,7 @@ RETRO_API void retro_get_system_info(retro_system_info *info)
info->block_extract = false;
}
RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info)
void retro_get_system_av_info(struct retro_system_av_info *info)
{
info->geometry.base_width = 512; // accurate ppu
info->geometry.base_height = program->overscan ? 480 : 448; // accurate ppu
@ -587,7 +607,7 @@ RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info)
info->geometry.max_height = 1920; // 8x 240
info->geometry.aspect_ratio = get_aspect_ratio();
info->timing.sample_rate = SAMPLERATE;
if (retro_get_region() == RETRO_REGION_NTSC) {
info->timing.fps = 21477272.0 / 357366.0;
audio_buffer_max = (SAMPLERATE/60) * 2;
@ -598,12 +618,12 @@ RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info)
}
}
RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device)
void retro_set_controller_port_device(unsigned port, unsigned device)
{
set_controller_ports(port, device);
}
RETRO_API void retro_reset()
void retro_reset()
{
emulator->reset();
}
@ -624,10 +644,14 @@ static void run_with_runahead(const int frames)
emulator->unserialize(state);
}
RETRO_API void retro_run()
void retro_run()
{
check_variables();
bool updated = false;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
update_variables();
input_poll();
update_geometry();
bool is_fast_forwarding = false;
environ_cb(RETRO_ENVIRONMENT_GET_FASTFORWARDING, &is_fast_forwarding);
@ -637,30 +661,30 @@ RETRO_API void retro_run()
run_with_runahead(run_ahead_frames);
}
RETRO_API size_t retro_serialize_size()
size_t retro_serialize_size()
{
return emulator->serialize().size();
}
RETRO_API bool retro_serialize(void *data, size_t size)
bool retro_serialize(void *data, size_t size)
{
memcpy(data, emulator->serialize().data(), size);
return true;
}
RETRO_API bool retro_unserialize(const void *data, size_t size)
bool retro_unserialize(const void *data, size_t size)
{
serializer s(static_cast<const uint8_t *>(data), size);
return emulator->unserialize(s);
}
RETRO_API void retro_cheat_reset()
void retro_cheat_reset()
{
cheatList.reset();
emulator->cheats(cheatList);
}
RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code)
void retro_cheat_set(unsigned index, bool enabled, const char *code)
{
string cheat = string(code);
bool decoded = false;
@ -681,7 +705,7 @@ RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code)
}
}
RETRO_API bool retro_load_game(const retro_game_info *game)
bool retro_load_game(const retro_game_info *game)
{
// bsnes uses 0RGB1555 internally but it is deprecated
// let software conversion happen in frontend
@ -691,7 +715,7 @@ RETRO_API bool retro_load_game(const retro_game_info *game)
emulator->configure("Audio/Frequency", SAMPLERATE);
flush_variables();
update_variables();
if (string(game->path).endsWith(".gb") || string(game->path).endsWith(".gbc"))
{
@ -736,12 +760,12 @@ RETRO_API bool retro_load_game(const retro_game_info *game)
return true;
}
RETRO_API bool retro_load_game_special(unsigned game_type,
bool retro_load_game_special(unsigned game_type,
const struct retro_game_info *info, size_t num_info)
{
emulator->configure("Audio/Frequency", SAMPLERATE);
flush_variables();
update_variables();
switch(game_type)
{
@ -772,25 +796,25 @@ RETRO_API bool retro_load_game_special(unsigned game_type,
return true;
}
RETRO_API void retro_unload_game()
void retro_unload_game()
{
program->save();
emulator->unload();
}
RETRO_API unsigned retro_get_region()
unsigned retro_get_region()
{
return program->superFamicom.region == "NTSC" ? RETRO_REGION_NTSC : RETRO_REGION_PAL;
}
// Currently, there is no safe/sensible way to use the memory interface without severe hackery.
// Rely on higan to load and save SRAM until there is really compelling reason not to.
RETRO_API void *retro_get_memory_data(unsigned id)
void *retro_get_memory_data(unsigned id)
{
return nullptr;
}
RETRO_API size_t retro_get_memory_size(unsigned id)
size_t retro_get_memory_size(unsigned id)
{
return 0;
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this libretro API header (libretro.h).
@ -69,7 +69,7 @@ extern "C" {
# endif
# endif
# else
# if defined(__GNUC__) && __GNUC__ >= 4 && !defined(__CELLOS_LV2__)
# if defined(__GNUC__) && __GNUC__ >= 4
# define RETRO_API RETRO_CALLCONV __attribute__((__visibility__("default")))
# else
# define RETRO_API RETRO_CALLCONV
@ -278,6 +278,11 @@ enum retro_language
RETRO_LANGUAGE_ARABIC = 16,
RETRO_LANGUAGE_GREEK = 17,
RETRO_LANGUAGE_TURKISH = 18,
RETRO_LANGUAGE_SLOVAK = 19,
RETRO_LANGUAGE_PERSIAN = 20,
RETRO_LANGUAGE_HEBREW = 21,
RETRO_LANGUAGE_ASTURIAN = 22,
RETRO_LANGUAGE_FINNISH = 23,
RETRO_LANGUAGE_LAST,
/* Ensure sizeof(enum) == sizeof(int) */
@ -708,6 +713,9 @@ enum retro_mod
* state of rumble motors in controllers.
* A strong and weak motor is supported, and they can be
* controlled indepedently.
* Should be called from either retro_init() or retro_load_game().
* Should not be called from retro_set_environment().
* Returns false if rumble functionality is unavailable.
*/
#define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24
/* uint64_t * --
@ -1087,10 +1095,10 @@ enum retro_mod
#define RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE (50 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* float * --
* Float value that lets us know what target refresh rate
* Float value that lets us know what target refresh rate
* is curently in use by the frontend.
*
* The core can use the returned value to set an ideal
* The core can use the returned value to set an ideal
* refresh rate/framerate.
*/
@ -1098,7 +1106,7 @@ enum retro_mod
/* bool * --
* Boolean value that indicates whether or not the frontend supports
* input bitmasks being returned by retro_input_state_t. The advantage
* of this is that retro_input_state_t has to be only called once to
* of this is that retro_input_state_t has to be only called once to
* grab all button states instead of multiple times.
*
* If it returns true, you can pass RETRO_DEVICE_ID_JOYPAD_MASK as 'id'
@ -1117,7 +1125,7 @@ enum retro_mod
* This may be still be done regardless of the core options
* interface version.
*
* If version is 1 however, core options may instead be set by
* If version is >= 1 however, core options may instead be set by
* passing an array of retro_core_option_definition structs to
* RETRO_ENVIRONMENT_SET_CORE_OPTIONS, or a 2D array of
* retro_core_option_definition structs to RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL.
@ -1132,8 +1140,8 @@ enum retro_mod
* GET_VARIABLE.
* This allows the frontend to present these variables to
* a user dynamically.
* This should only be called if RETRO_ENVIRONMENT_GET_ENHANCED_CORE_OPTIONS
* returns an API version of 1.
* This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
* returns an API version of >= 1.
* This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES.
* This should be called the first time as early as
* possible (ideally in retro_set_environment).
@ -1194,8 +1202,8 @@ enum retro_mod
* GET_VARIABLE.
* This allows the frontend to present these variables to
* a user dynamically.
* This should only be called if RETRO_ENVIRONMENT_GET_ENHANCED_CORE_OPTIONS
* returns an API version of 1.
* This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
* returns an API version of >= 1.
* This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES.
* This should be called the first time as early as
* possible (ideally in retro_set_environment).
@ -1246,6 +1254,140 @@ enum retro_mod
* default when calling SET_VARIABLES/SET_CORE_OPTIONS.
*/
#define RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER 56
/* unsigned * --
*
* Allows an implementation to ask frontend preferred hardware
* context to use. Core should use this information to deal
* with what specific context to request with SET_HW_RENDER.
*
* 'data' points to an unsigned variable
*/
#define RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION 57
/* unsigned * --
* Unsigned value is the API version number of the disk control
* interface supported by the frontend. If callback return false,
* API version is assumed to be 0.
*
* In legacy code, the disk control interface is defined by passing
* a struct of type retro_disk_control_callback to
* RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE.
* This may be still be done regardless of the disk control
* interface version.
*
* If version is >= 1 however, the disk control interface may
* instead be defined by passing a struct of type
* retro_disk_control_ext_callback to
* RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE.
* This allows the core to provide additional information about
* disk images to the frontend and/or enables extra
* disk control functionality by the frontend.
*/
#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE 58
/* const struct retro_disk_control_ext_callback * --
* Sets an interface which frontend can use to eject and insert
* disk images, and also obtain information about individual
* disk image files registered by the core.
* This is used for games which consist of multiple images and
* must be manually swapped out by the user (e.g. PSX, floppy disk
* based systems).
*/
#define RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION 59
/* unsigned * --
* Unsigned value is the API version number of the message
* interface supported by the frontend. If callback returns
* false, API version is assumed to be 0.
*
* In legacy code, messages may be displayed in an
* implementation-specific manner by passing a struct
* of type retro_message to RETRO_ENVIRONMENT_SET_MESSAGE.
* This may be still be done regardless of the message
* interface version.
*
* If version is >= 1 however, messages may instead be
* displayed by passing a struct of type retro_message_ext
* to RETRO_ENVIRONMENT_SET_MESSAGE_EXT. This allows the
* core to specify message logging level, priority and
* destination (OSD, logging interface or both).
*/
#define RETRO_ENVIRONMENT_SET_MESSAGE_EXT 60
/* const struct retro_message_ext * --
* Sets a message to be displayed in an implementation-specific
* manner for a certain amount of 'frames'. Additionally allows
* the core to specify message logging level, priority and
* destination (OSD, logging interface or both).
* Should not be used for trivial messages, which should simply be
* logged via RETRO_ENVIRONMENT_GET_LOG_INTERFACE (or as a
* fallback, stderr).
*/
#define RETRO_ENVIRONMENT_GET_INPUT_MAX_USERS 61
/* unsigned * --
* Unsigned value is the number of active input devices
* provided by the frontend. This may change between
* frames, but will remain constant for the duration
* of each frame.
* If callback returns true, a core need not poll any
* input device with an index greater than or equal to
* the number of active devices.
* If callback returns false, the number of active input
* devices is unknown. In this case, all input devices
* should be considered active.
*/
#define RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK 62
/* const struct retro_audio_buffer_status_callback * --
* Lets the core know the occupancy level of the frontend
* audio buffer. Can be used by a core to attempt frame
* skipping in order to avoid buffer under-runs.
* A core may pass NULL to disable buffer status reporting
* in the frontend.
*/
#define RETRO_ENVIRONMENT_SET_MINIMUM_AUDIO_LATENCY 63
/* const unsigned * --
* Sets minimum frontend audio latency in milliseconds.
* Resultant audio latency may be larger than set value,
* or smaller if a hardware limit is encountered. A frontend
* is expected to honour requests up to 512 ms.
*
* - If value is less than current frontend
* audio latency, callback has no effect
* - If value is zero, default frontend audio
* latency is set
*
* May be used by a core to increase audio latency and
* therefore decrease the probability of buffer under-runs
* (crackling) when performing 'intensive' operations.
* A core utilising RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK
* to implement audio-buffer-based frame skipping may achieve
* optimal results by setting the audio latency to a 'high'
* (typically 6x or 8x) integer multiple of the expected
* frame time.
*
* WARNING: This can only be called from within retro_run().
* Calling this can require a full reinitialization of audio
* drivers in the frontend, so it is important to call it very
* sparingly, and usually only with the users explicit consent.
* An eventual driver reinitialize will happen so that audio
* callbacks happening after this call within the same retro_run()
* call will target the newly initialized driver.
*/
#define RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE 64
/* const struct retro_fastforwarding_override * --
* Used by a libretro core to override the current
* fastforwarding mode of the frontend.
* If NULL is passed to this function, the frontend
* will return true if fastforwarding override
* functionality is supported (no change in
* fastforwarding state will occur in this case).
*/
/* VFS functionality */
/* File paths:
@ -1922,6 +2064,10 @@ enum retro_sensor_action
{
RETRO_SENSOR_ACCELEROMETER_ENABLE = 0,
RETRO_SENSOR_ACCELEROMETER_DISABLE,
RETRO_SENSOR_GYROSCOPE_ENABLE,
RETRO_SENSOR_GYROSCOPE_DISABLE,
RETRO_SENSOR_ILLUMINANCE_ENABLE,
RETRO_SENSOR_ILLUMINANCE_DISABLE,
RETRO_SENSOR_DUMMY = INT_MAX
};
@ -1930,6 +2076,10 @@ enum retro_sensor_action
#define RETRO_SENSOR_ACCELEROMETER_X 0
#define RETRO_SENSOR_ACCELEROMETER_Y 1
#define RETRO_SENSOR_ACCELEROMETER_Z 2
#define RETRO_SENSOR_GYROSCOPE_X 3
#define RETRO_SENSOR_GYROSCOPE_Y 4
#define RETRO_SENSOR_GYROSCOPE_Z 5
#define RETRO_SENSOR_ILLUMINANCE 6
typedef bool (RETRO_CALLCONV *retro_set_sensor_state_t)(unsigned port,
enum retro_sensor_action action, unsigned rate);
@ -2127,6 +2277,30 @@ struct retro_frame_time_callback
retro_usec_t reference;
};
/* Notifies a libretro core of the current occupancy
* level of the frontend audio buffer.
*
* - active: 'true' if audio buffer is currently
* in use. Will be 'false' if audio is
* disabled in the frontend
*
* - occupancy: Given as a value in the range [0,100],
* corresponding to the occupancy percentage
* of the audio buffer
*
* - underrun_likely: 'true' if the frontend expects an
* audio buffer underrun during the
* next frame (indicates that a core
* should attempt frame skipping)
*
* It will be called right before retro_run() every frame. */
typedef void (RETRO_CALLCONV *retro_audio_buffer_status_callback_t)(
bool active, unsigned occupancy, bool underrun_likely);
struct retro_audio_buffer_status_callback
{
retro_audio_buffer_status_callback_t callback;
};
/* Pass this to retro_video_refresh_t if rendering to hardware.
* Passing NULL to retro_video_refresh_t is still a frame dupe as normal.
* */
@ -2287,7 +2461,8 @@ struct retro_keyboard_callback
retro_keyboard_event_t callback;
};
/* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE.
/* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE &
* RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE.
* Should be set for implementations which can swap out multiple disk
* images in runtime.
*
@ -2345,6 +2520,53 @@ typedef bool (RETRO_CALLCONV *retro_replace_image_index_t)(unsigned index,
* with replace_image_index. */
typedef bool (RETRO_CALLCONV *retro_add_image_index_t)(void);
/* Sets initial image to insert in drive when calling
* core_load_game().
* Since we cannot pass the initial index when loading
* content (this would require a major API change), this
* is set by the frontend *before* calling the core's
* retro_load_game()/retro_load_game_special() implementation.
* A core should therefore cache the index/path values and handle
* them inside retro_load_game()/retro_load_game_special().
* - If 'index' is invalid (index >= get_num_images()), the
* core should ignore the set value and instead use 0
* - 'path' is used purely for error checking - i.e. when
* content is loaded, the core should verify that the
* disk specified by 'index' has the specified file path.
* This is to guard against auto selecting the wrong image
* if (for example) the user should modify an existing M3U
* playlist. We have to let the core handle this because
* set_initial_image() must be called before loading content,
* i.e. the frontend cannot access image paths in advance
* and thus cannot perform the error check itself.
* If set path and content path do not match, the core should
* ignore the set 'index' value and instead use 0
* Returns 'false' if index or 'path' are invalid, or core
* does not support this functionality
*/
typedef bool (RETRO_CALLCONV *retro_set_initial_image_t)(unsigned index, const char *path);
/* Fetches the path of the specified disk image file.
* Returns 'false' if index is invalid (index >= get_num_images())
* or path is otherwise unavailable.
*/
typedef bool (RETRO_CALLCONV *retro_get_image_path_t)(unsigned index, char *path, size_t len);
/* Fetches a core-provided 'label' for the specified disk
* image file. In the simplest case this may be a file name
* (without extension), but for cores with more complex
* content requirements information may be provided to
* facilitate user disk swapping - for example, a core
* running floppy-disk-based content may uniquely label
* save disks, data disks, level disks, etc. with names
* corresponding to in-game disk change prompts (so the
* frontend can provide better user guidance than a 'dumb'
* disk index value).
* Returns 'false' if index is invalid (index >= get_num_images())
* or label is otherwise unavailable.
*/
typedef bool (RETRO_CALLCONV *retro_get_image_label_t)(unsigned index, char *label, size_t len);
struct retro_disk_control_callback
{
retro_set_eject_state_t set_eject_state;
@ -2358,6 +2580,27 @@ struct retro_disk_control_callback
retro_add_image_index_t add_image_index;
};
struct retro_disk_control_ext_callback
{
retro_set_eject_state_t set_eject_state;
retro_get_eject_state_t get_eject_state;
retro_get_image_index_t get_image_index;
retro_set_image_index_t set_image_index;
retro_get_num_images_t get_num_images;
retro_replace_image_index_t replace_image_index;
retro_add_image_index_t add_image_index;
/* NOTE: Frontend will only attempt to record/restore
* last used disk index if both set_initial_image()
* and get_image_path() are implemented */
retro_set_initial_image_t set_initial_image; /* Optional - may be NULL */
retro_get_image_path_t get_image_path; /* Optional - may be NULL */
retro_get_image_label_t get_image_label; /* Optional - may be NULL */
};
enum retro_pixel_format
{
/* 0RGB1555, native endian.
@ -2388,6 +2631,104 @@ struct retro_message
unsigned frames; /* Duration in frames of message. */
};
enum retro_message_target
{
RETRO_MESSAGE_TARGET_ALL = 0,
RETRO_MESSAGE_TARGET_OSD,
RETRO_MESSAGE_TARGET_LOG
};
enum retro_message_type
{
RETRO_MESSAGE_TYPE_NOTIFICATION = 0,
RETRO_MESSAGE_TYPE_NOTIFICATION_ALT,
RETRO_MESSAGE_TYPE_STATUS,
RETRO_MESSAGE_TYPE_PROGRESS
};
struct retro_message_ext
{
/* Message string to be displayed/logged */
const char *msg;
/* Duration (in ms) of message when targeting the OSD */
unsigned duration;
/* Message priority when targeting the OSD
* > When multiple concurrent messages are sent to
* the frontend and the frontend does not have the
* capacity to display them all, messages with the
* *highest* priority value should be shown
* > There is no upper limit to a message priority
* value (within the bounds of the unsigned data type)
* > In the reference frontend (RetroArch), the same
* priority values are used for frontend-generated
* notifications, which are typically assigned values
* between 0 and 3 depending upon importance */
unsigned priority;
/* Message logging level (info, warn, error, etc.) */
enum retro_log_level level;
/* Message destination: OSD, logging interface or both */
enum retro_message_target target;
/* Message 'type' when targeting the OSD
* > RETRO_MESSAGE_TYPE_NOTIFICATION: Specifies that a
* message should be handled in identical fashion to
* a standard frontend-generated notification
* > RETRO_MESSAGE_TYPE_NOTIFICATION_ALT: Specifies that
* message is a notification that requires user attention
* or action, but that it should be displayed in a manner
* that differs from standard frontend-generated notifications.
* This would typically correspond to messages that should be
* displayed immediately (independently from any internal
* frontend message queue), and/or which should be visually
* distinguishable from frontend-generated notifications.
* For example, a core may wish to inform the user of
* information related to a disk-change event. It is
* expected that the frontend itself may provide a
* notification in this case; if the core sends a
* message of type RETRO_MESSAGE_TYPE_NOTIFICATION, an
* uncomfortable 'double-notification' may occur. A message
* of RETRO_MESSAGE_TYPE_NOTIFICATION_ALT should therefore
* be presented such that visual conflict with regular
* notifications does not occur
* > RETRO_MESSAGE_TYPE_STATUS: Indicates that message
* is not a standard notification. This typically
* corresponds to 'status' indicators, such as a core's
* internal FPS, which are intended to be displayed
* either permanently while a core is running, or in
* a manner that does not suggest user attention or action
* is required. 'Status' type messages should therefore be
* displayed in a different on-screen location and in a manner
* easily distinguishable from both standard frontend-generated
* notifications and messages of type RETRO_MESSAGE_TYPE_NOTIFICATION_ALT
* > RETRO_MESSAGE_TYPE_PROGRESS: Indicates that message reports
* the progress of an internal core task. For example, in cases
* where a core itself handles the loading of content from a file,
* this may correspond to the percentage of the file that has been
* read. Alternatively, an audio/video playback core may use a
* message of type RETRO_MESSAGE_TYPE_PROGRESS to display the current
* playback position as a percentage of the runtime. 'Progress' type
* messages should therefore be displayed as a literal progress bar,
* where:
* - 'retro_message_ext.msg' is the progress bar title/label
* - 'retro_message_ext.progress' determines the length of
* the progress bar
* NOTE: Message type is a *hint*, and may be ignored
* by the frontend. If a frontend lacks support for
* displaying messages via alternate means than standard
* frontend-generated notifications, it will treat *all*
* messages as having the type RETRO_MESSAGE_TYPE_NOTIFICATION */
enum retro_message_type type;
/* Task progress when targeting the OSD and message is
* of type RETRO_MESSAGE_TYPE_PROGRESS
* > -1: Unmetered/indeterminate
* > 0-100: Current progress percentage
* NOTE: Since message type is a hint, a frontend may ignore
* progress values. Where relevant, a core should therefore
* include progress percentage within the message string,
* such that the message intent remains clear when displayed
* as a standard frontend-generated notification */
int8_t progress;
};
/* Describes how the libretro implementation maps a libretro input bind
* to its internal input system through a human readable string.
* This string can be used to better let a user configure input. */
@ -2408,7 +2749,7 @@ struct retro_input_descriptor
struct retro_system_info
{
/* All pointers are owned by libretro implementation, and pointers must
* remain valid until retro_deinit() is called. */
* remain valid until it is unloaded. */
const char *library_name; /* Descriptive name of library. Should not
* contain any version numbers, etc. */
@ -2501,7 +2842,21 @@ struct retro_core_option_display
bool visible;
};
/* Maximum number of values permitted for a core option */
/* Maximum number of values permitted for a core option
* > Note: We have to set a maximum value due the limitations
* of the C language - i.e. it is not possible to create an
* array of structs each containing a variable sized array,
* so the retro_core_option_definition values array must
* have a fixed size. The size limit of 128 is a balancing
* act - it needs to be large enough to support all 'sane'
* core options, but setting it too large may impact low memory
* platforms. In practise, if a core option has more than
* 128 values then the implementation is likely flawed.
* To quote the above API reference:
* "The number of possible options should be very limited
* i.e. it should be feasible to cycle through options
* without a keyboard."
*/
#define RETRO_NUM_CORE_OPTION_VALUES_MAX 128
struct retro_core_option_value
@ -2593,6 +2948,47 @@ struct retro_framebuffer
Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */
};
/* Used by a libretro core to override the current
* fastforwarding mode of the frontend */
struct retro_fastforwarding_override
{
/* Specifies the runtime speed multiplier that
* will be applied when 'fastforward' is true.
* For example, a value of 5.0 when running 60 FPS
* content will cap the fast-forward rate at 300 FPS.
* Note that the target multiplier may not be achieved
* if the host hardware has insufficient processing
* power.
* Setting a value of 0.0 (or greater than 0.0 but
* less than 1.0) will result in an uncapped
* fast-forward rate (limited only by hardware
* capacity).
* If the value is negative, it will be ignored
* (i.e. the frontend will use a runtime speed
* multiplier of its own choosing) */
float ratio;
/* If true, fastforwarding mode will be enabled.
* If false, fastforwarding mode will be disabled. */
bool fastforward;
/* If true, and if supported by the frontend, an
* on-screen notification will be displayed while
* 'fastforward' is true.
* If false, and if supported by the frontend, any
* on-screen fast-forward notifications will be
* suppressed */
bool notification;
/* If true, the core will have sole control over
* when fastforwarding mode is enabled/disabled;
* the frontend will not be able to change the
* state set by 'fastforward' until either
* 'inhibit_toggle' is set to false, or the core
* is unloaded */
bool inhibit_toggle;
};
/* Callbacks */
/* Environment callback. Gives implementations a way of performing

View File

@ -0,0 +1,704 @@
#ifndef LIBRETRO_CORE_OPTIONS_H__
#define LIBRETRO_CORE_OPTIONS_H__
#include <stdlib.h>
#include <string.h>
#include "libretro.h"
#include "libretro-common/include/retro_inline.h"
#ifndef HAVE_NO_LANGEXTRA
#include "libretro_core_options_intl.h"
#endif
/*
********************************
* VERSION: 1.3
********************************
*
* - 1.3: Move translations to libretro_core_options_intl.h
* - libretro_core_options_intl.h includes BOM and utf-8
* fix for MSVC 2010-2013
* - Added HAVE_NO_LANGEXTRA flag to disable translations
* on platforms/compilers without BOM support
* - 1.2: Use core options v1 interface when
* RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1
* (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
* - 1.1: Support generation of core options v0 retro_core_option_value
* arrays containing options with a single value
* - 1.0: First commit
*/
#ifdef __cplusplus
extern "C" {
#endif
/*
********************************
* Core Option Definitions
********************************
*/
/* RETRO_LANGUAGE_ENGLISH */
/* Default language:
* - All other languages must include the same keys and values
* - Will be used as a fallback in the event that frontend language
* is not available
* - Will be used as a fallback for any missing entries in
* frontend language definition */
struct retro_core_option_definition option_defs_us[] = {
{
"bsnes_aspect_ratio",
"Preferred Aspect Ratio",
"Choose the preferred content aspect ratio. This will only apply when RetroArch's aspect ratio is set to 'Core provided' in the Video settings.",
{
{ "Auto", NULL },
{ "8:7", NULL },
{ "4:3", NULL },
{ "NTSC", NULL },
{ "PAL", NULL },
{ NULL, NULL },
},
"Auto"
},
{
"bsnes_ppu_show_overscan",
"Crop Overscan",
"Remove the borders at the top and bottom of the screen, typically unused by games and hidden by the bezel of a standard-definition television.",
{
{ "OFF", "8 Pixels" },
{ "ON", "disabled" },
{ NULL, NULL },
},
"OFF"
},
{
"bsnes_blur_emulation",
"Blur Emulation",
"Simulates the limited horizontal resolution of SDTVs by blurring together horizontally-adjacent pixels. Some games depend on this to emulate a transparency effect.",
{
{ "ON", "enabled" },
{ "OFF", "disabled" },
{ NULL, NULL },
},
"OFF"
},
{
"bsnes_hotfixes",
"Hotfixes",
"Even commercially licensed and officially released software sometimes shipped with bugs. This option will correct certain issues that occurred even on real hardware.",
{
{ "ON", "enabled" },
{ "OFF", "disabled" },
{ NULL, NULL },
},
"OFF"
},
{
"bsnes_entropy",
"Entropy (randomization)",
"Determines the level of randomization of the memory and registers. If set to None, all memory and registers are initialized to constant values at startup. Low randomization provides the most accurate representation of a real system. High randomizes as much as possible.",
{
{ "Low", NULL },
{ "High", NULL },
{ "None", NULL },
{ NULL, NULL },
},
"Low"
},
{
"bsnes_cpu_overclock",
"Overclocking - CPU",
"Overclocks or downclocks the CPU. Setting this value above 100% may help reduce loading times and remove slowdown. Use with caution as it may also cause certain games to crash or exhibit issues.",
{
{ "10", "10%" },
{ "20", "20%" },
{ "30", "30%" },
{ "40", "40%" },
{ "50", "50%" },
{ "60", "60%" },
{ "70", "70%" },
{ "80", "80%" },
{ "90", "90%" },
{ "100", "100%" },
{ "110", "110%" },
{ "120", "120%" },
{ "130", "130%" },
{ "140", "140%" },
{ "150", "150%" },
{ "160", "160%" },
{ "170", "170%" },
{ "180", "180%" },
{ "190", "190%" },
{ "200", "200%" },
{ "210", "210%" },
{ "220", "220%" },
{ "230", "230%" },
{ "240", "240%" },
{ "250", "250%" },
{ "260", "260%" },
{ "270", "270%" },
{ "280", "280%" },
{ "290", "290%" },
{ "300", "300%" },
{ "310", "310%" },
{ "320", "320%" },
{ "330", "330%" },
{ "340", "340%" },
{ "350", "350%" },
{ "360", "360%" },
{ "370", "370%" },
{ "380", "380%" },
{ "390", "390%" },
{ "400", "400%" },
{ NULL, NULL },
},
"100"
},
{
"bsnes_cpu_fastmath",
"CPU Fast Math",
"CPU multiplication and division take time to complete on a real SNES. Older emulators did not simulate these delays and provided results immediately. Some older ROM hacks do not wait for math operations to complete and need this hack.",
{
{ "ON", "enabled" },
{ "OFF", "disabled" },
{ NULL, NULL },
},
"OFF"
},
{
"bsnes_cpu_sa1_overclock",
"Overclocking - SA-1 Coprocessor",
"Overclocks or downclocks the Super Accelerator 1 (SA-1) chip. Setting this value above 100% may help obtain higher performance in games that support the SA-1 chip. Use with caution as it may also cause certain games to crash or exhibit issues.",
{
{ "10", "10%" },
{ "20", "20%" },
{ "30", "30%" },
{ "40", "40%" },
{ "50", "50%" },
{ "60", "60%" },
{ "70", "70%" },
{ "80", "80%" },
{ "90", "90%" },
{ "100", "100%" },
{ "110", "110%" },
{ "120", "120%" },
{ "130", "130%" },
{ "140", "140%" },
{ "150", "150%" },
{ "160", "160%" },
{ "170", "170%" },
{ "180", "180%" },
{ "190", "190%" },
{ "200", "200%" },
{ "210", "210%" },
{ "220", "220%" },
{ "230", "230%" },
{ "240", "240%" },
{ "250", "250%" },
{ "260", "260%" },
{ "270", "270%" },
{ "280", "280%" },
{ "290", "290%" },
{ "300", "300%" },
{ "310", "310%" },
{ "320", "320%" },
{ "330", "330%" },
{ "340", "340%" },
{ "350", "350%" },
{ "360", "360%" },
{ "370", "370%" },
{ "380", "380%" },
{ "390", "390%" },
{ "400", "400%" },
{ NULL, NULL },
},
"100"
},
{
"bsnes_cpu_sfx_overclock",
"Overclocking - SuperFX Coprocessor",
"Overclocks or downclocks the SuperFX coprocessor. Setting this value above 100% may help obtain higher performance in games that support the SuperFX. Use with caution as it may also cause certain games to crash or exhibit issues.",
{
{ "10", "10%" },
{ "20", "20%" },
{ "30", "30%" },
{ "40", "40%" },
{ "50", "50%" },
{ "60", "60%" },
{ "70", "70%" },
{ "80", "80%" },
{ "90", "90%" },
{ "100", "100%" },
{ "110", "110%" },
{ "120", "120%" },
{ "130", "130%" },
{ "140", "140%" },
{ "150", "150%" },
{ "160", "160%" },
{ "170", "170%" },
{ "180", "180%" },
{ "190", "190%" },
{ "200", "200%" },
{ "210", "210%" },
{ "220", "220%" },
{ "230", "230%" },
{ "240", "240%" },
{ "250", "250%" },
{ "260", "260%" },
{ "270", "270%" },
{ "280", "280%" },
{ "290", "290%" },
{ "300", "300%" },
{ "310", "310%" },
{ "320", "320%" },
{ "330", "330%" },
{ "340", "340%" },
{ "350", "350%" },
{ "360", "360%" },
{ "370", "370%" },
{ "380", "380%" },
{ "390", "390%" },
{ "400", "400%" },
{ "410", "410%" },
{ "420", "420%" },
{ "430", "430%" },
{ "440", "440%" },
{ "450", "450%" },
{ "460", "460%" },
{ "470", "470%" },
{ "480", "480%" },
{ "490", "490%" },
{ "500", "500%" },
{ "510", "510%" },
{ "520", "520%" },
{ "530", "530%" },
{ "540", "540%" },
{ "550", "550%" },
{ "560", "560%" },
{ "570", "570%" },
{ "580", "580%" },
{ "590", "590%" },
{ "600", "600%" },
{ "610", "610%" },
{ "620", "620%" },
{ "630", "630%" },
{ "640", "640%" },
{ "650", "650%" },
{ "660", "660%" },
{ "670", "670%" },
{ "680", "680%" },
{ "690", "690%" },
{ "700", "700%" },
{ "710", "710%" },
{ "720", "720%" },
{ "730", "730%" },
{ "740", "740%" },
{ "750", "750%" },
{ "760", "760%" },
{ "770", "770%" },
{ "780", "780%" },
{ "790", "790%" },
{ "800", "800%" },
{ NULL, NULL },
},
"100"
},
{
"bsnes_ppu_fast",
"PPU (Video) - Fast Mode",
"Enables faster emulation of the PPU at the cost of a minor reduction of accuracy. It is recommended to leave this active.",
{
{ "ON", "enabled" },
{ "OFF", "disabled" },
{ NULL, NULL },
},
"ON"
},
{
"bsnes_ppu_deinterlace",
"PPU (Video) - Deinterlace",
"Deinterlaces all games by rendering internally at 480p. Performance penalty is almost non-existent, so it is recommended to leave this active.",
{
{ "ON", "enabled" },
{ "OFF", "disabled" },
{ NULL, NULL },
},
"ON"
},
{
"bsnes_ppu_no_sprite_limit",
"PPU (Video) - No Sprite Limit",
"Removes any limit to the number of sprites that can be drawn simultaneously on screen. May cause issues with certain games.",
{
{ "ON", "enabled" },
{ "OFF", "disabled" },
{ NULL, NULL },
},
"OFF"
},
{
"bsnes_ppu_no_vram_blocking",
"PPU (Video) - No VRAM Blocking",
"Emulates a bug in older releases of ZSNES and Snes9x, where VRAM blocking was not emulated. A few older ROM hacks relied on this behavior and will render graphics incorrectly if not enabled. This option is extremely inaccurate and hurts PPU speed, so it is recommended to leave it disabled unless you need to play a game that is otherwise incompatible with this core.",
{
{ "ON", "enabled" },
{ "OFF", "disabled" },
{ NULL, NULL },
},
"OFF"
},
{
"bsnes_mode7_scale",
"HD Mode 7 - Scale",
"Allows to increase the horizontal and vertical resolution of the Mode 7 graphics used in certain games.",
{
{ "1x", "240p (1x)" },
{ "2x", "480p (2x)" },
{ "3x", "720p (3x)" },
{ "4x", "960p (4x)" },
{ "5x", "1200p (5x)" },
{ "6x", "1440p (6x)" },
{ "7x", "1680p (7x)" },
{ "8x", "1920p (8x)" },
{ NULL, NULL },
},
"1x"
},
{
"bsnes_mode7_perspective",
"HD Mode 7 - Perspective Correction",
"Corrects the perspective of the Mode 7 graphics used in certain games by working around some limitations of the integer math used by the SNES.",
{
{ "ON", "enabled" },
{ "OFF", "disabled" },
{ NULL, NULL },
},
"ON"
},
{
"bsnes_mode7_supersample",
"HD Mode 7 - Supersampling",
"Allows to supersample the Mode 7 graphics used in certain games. Combined with higher Mode 7 scale factors, it produces an effect similar to anti-aliasing.",
{
{ "ON", "enabled" },
{ "OFF", "disabled" },
{ NULL, NULL },
},
"OFF"
},
{
"bsnes_mode7_mosaic",
"HD Mode 7 - HD->SD Mosaic",
"Determines whether the mosaic effect should be shown when upscaling the Mode 7 graphics used in certain games.",
{
{ "ON", "enabled" },
{ "OFF", "disabled" },
{ NULL, NULL },
},
"ON"
},
{
"bsnes_dsp_fast",
"DSP (Audio) - Fast Mode",
"Enables faster emulation of the DSP at the cost of a minor reduction of accuracy. It is recommended to leave this active.",
{
{ "ON", "enabled" },
{ "OFF", "disabled" },
{ NULL, NULL },
},
"ON"
},
{
"bsnes_dsp_cubic",
"DSP (Audio) - Cubic Interpolation",
"Applies cubic interpolation to the sound, preserving more of the high range.",
{
{ "ON", "enabled" },
{ "OFF", "disabled" },
{ NULL, NULL },
},
"OFF"
},
{
"bsnes_dsp_echo_shadow",
"DSP (Audio) - Echo Shadow RAM",
"Emulates a bug in ZSNES where echo RAM was treated as separate from APU RAM. Many older ROM hacks for Super Mario World relied on this behavior and will crash without enabling this. This option is extremely inaccurate and should not be enabled unless required.",
{
{ "ON", "enabled" },
{ "OFF", "disabled" },
{ NULL, NULL },
},
"OFF"
},
{
"bsnes_coprocessor_delayed_sync",
"Coprocessors - Fast Mode",
"Enables faster emulation of the coprocessors at the cost of a minor reduction of accuracy. It is recommended to leave this active.",
{
{ "ON", "enabled" },
{ "OFF", "disabled" },
{ NULL, NULL },
},
"ON"
},
{
"bsnes_coprocessor_prefer_hle",
"Coprocessors - Prefer HLE",
"When this option is enabled, less accurate HLE emulation will always be used when available. If disabled, HLE will only be used when LLE firmware is missing.",
{
{ "ON", "enabled" },
{ "OFF", "disabled" },
{ NULL, NULL },
},
"ON"
},
{
"bsnes_sgb_bios",
"Preferred Super Game Boy BIOS (Requires Restart)",
"Allows to choose the preferred Super Game Boy BIOS to be used with compatible titles. Requires a restart to take effect.",
{
{ "SGB1.sfc", "Super Game Boy (SGB1.sfc)" },
{ "SGB2.sfc", "Super Game Boy 2 (SGB2.sfc)" },
{ NULL, NULL },
},
"SGB1.sfc"
},
{
"bsnes_run_ahead_frames",
"Internal Run-Ahead",
"Simulates the system ahead of time and rolls back to reduce input latency. Has very high system requirements.",
{
{ "OFF", "disabled" },
{ "1", "1 frame" },
{ "2", "2 frames" },
{ "3", "3 frames" },
{ "4", "4 frames" },
{ NULL, NULL },
},
"OFF"
},
{
"bsnes_touchscreen_lightgun",
"Touchscreen Lightgun",
"Enables Super Scope input for touchscreen devices.",
{
{ "ON", "enabled" },
{ "OFF", "disabled" },
{ NULL, NULL },
},
"ON"
},
{
"bsnes_touchscreen_lightgun_superscope_reverse",
"Super Scope Reverse Trigger Buttons",
"Allows to reverse the Super Scope trigger and cursor buttons with the touchscreen lightgun.",
{
{ "ON", "enabled" },
{ "OFF", "disabled" },
{ NULL, NULL },
},
"OFF"
},
{ NULL, NULL, NULL, {{0}}, NULL },
};
/*
********************************
* Language Mapping
********************************
*/
#ifndef HAVE_NO_LANGEXTRA
struct retro_core_option_definition *option_defs_intl[RETRO_LANGUAGE_LAST] = {
option_defs_us, /* RETRO_LANGUAGE_ENGLISH */
NULL, /* RETRO_LANGUAGE_JAPANESE */
NULL, /* RETRO_LANGUAGE_FRENCH */
NULL, /* RETRO_LANGUAGE_SPANISH */
NULL, /* RETRO_LANGUAGE_GERMAN */
NULL, /* RETRO_LANGUAGE_ITALIAN */
NULL, /* RETRO_LANGUAGE_DUTCH */
NULL, /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
NULL, /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
NULL, /* RETRO_LANGUAGE_RUSSIAN */
NULL, /* RETRO_LANGUAGE_KOREAN */
NULL, /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
NULL, /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
NULL, /* RETRO_LANGUAGE_ESPERANTO */
NULL, /* RETRO_LANGUAGE_POLISH */
NULL, /* RETRO_LANGUAGE_VIETNAMESE */
NULL, /* RETRO_LANGUAGE_ARABIC */
NULL, /* RETRO_LANGUAGE_GREEK */
NULL, /* RETRO_LANGUAGE_TURKISH */
NULL, /* RETRO_LANGUAGE_SLOVAK */
NULL, /* RETRO_LANGUAGE_PERSIAN */
NULL, /* RETRO_LANGUAGE_HEBREW */
NULL, /* RETRO_LANGUAGE_ASTURIAN */
NULL, /* RETRO_LANGUAGE_FINNISH */
};
#endif
/*
********************************
* Functions
********************************
*/
/* Handles configuration/setting of core options.
* Should be called as early as possible - ideally inside
* retro_set_environment(), and no later than retro_load_game()
* > We place the function body in the header to avoid the
* necessity of adding more .c files (i.e. want this to
* be as painless as possible for core devs)
*/
static INLINE void libretro_set_core_options(retro_environment_t environ_cb)
{
unsigned version = 0;
if (!environ_cb)
return;
if (environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version) && (version >= 1))
{
#ifndef HAVE_NO_LANGEXTRA
struct retro_core_options_intl core_options_intl;
unsigned language = 0;
core_options_intl.us = option_defs_us;
core_options_intl.local = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&
(language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH))
core_options_intl.local = option_defs_intl[language];
environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_intl);
#else
environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, &option_defs_us);
#endif
}
else
{
size_t i;
size_t num_options = 0;
struct retro_variable *variables = NULL;
char **values_buf = NULL;
/* Determine number of options */
for (;;)
{
if (!option_defs_us[num_options].key)
break;
num_options++;
}
/* Allocate arrays */
variables = (struct retro_variable *)calloc(num_options + 1, sizeof(struct retro_variable));
values_buf = (char **)calloc(num_options, sizeof(char *));
if (!variables || !values_buf)
goto error;
/* Copy parameters from option_defs_us array */
for (i = 0; i < num_options; i++)
{
const char *key = option_defs_us[i].key;
const char *desc = option_defs_us[i].desc;
const char *default_value = option_defs_us[i].default_value;
struct retro_core_option_value *values = option_defs_us[i].values;
size_t buf_len = 3;
size_t default_index = 0;
values_buf[i] = NULL;
if (desc)
{
size_t num_values = 0;
/* Determine number of values */
for (;;)
{
if (!values[num_values].value)
break;
/* Check if this is the default value */
if (default_value)
if (strcmp(values[num_values].value, default_value) == 0)
default_index = num_values;
buf_len += strlen(values[num_values].value);
num_values++;
}
/* Build values string */
if (num_values > 0)
{
size_t j;
buf_len += num_values - 1;
buf_len += strlen(desc);
values_buf[i] = (char *)calloc(buf_len, sizeof(char));
if (!values_buf[i])
goto error;
strcpy(values_buf[i], desc);
strcat(values_buf[i], "; ");
/* Default value goes first */
strcat(values_buf[i], values[default_index].value);
/* Add remaining values */
for (j = 0; j < num_values; j++)
{
if (j != default_index)
{
strcat(values_buf[i], "|");
strcat(values_buf[i], values[j].value);
}
}
}
}
variables[i].key = key;
variables[i].value = values_buf[i];
}
/* Set variables */
environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);
error:
/* Clean up */
if (values_buf)
{
for (i = 0; i < num_options; i++)
{
if (values_buf[i])
{
free(values_buf[i]);
values_buf[i] = NULL;
}
}
free(values_buf);
values_buf = NULL;
}
if (variables)
{
free(variables);
variables = NULL;
}
}
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,90 @@
#ifndef LIBRETRO_CORE_OPTIONS_INTL_H__
#define LIBRETRO_CORE_OPTIONS_INTL_H__
#if defined(_MSC_VER) && (_MSC_VER >= 1500 && _MSC_VER < 1900)
/* https://support.microsoft.com/en-us/kb/980263 */
#pragma execution_character_set("utf-8")
#pragma warning(disable:4566)
#endif
#include "libretro.h"
/*
********************************
* VERSION: 1.3
********************************
*
* - 1.3: Move translations to libretro_core_options_intl.h
* - libretro_core_options_intl.h includes BOM and utf-8
* fix for MSVC 2010-2013
* - Added HAVE_NO_LANGEXTRA flag to disable translations
* on platforms/compilers without BOM support
* - 1.2: Use core options v1 interface when
* RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1
* (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
* - 1.1: Support generation of core options v0 retro_core_option_value
* arrays containing options with a single value
* - 1.0: First commit
*/
#ifdef __cplusplus
extern "C" {
#endif
/*
********************************
* Core Option Definitions
********************************
*/
/* RETRO_LANGUAGE_JAPANESE */
/* RETRO_LANGUAGE_FRENCH */
/* RETRO_LANGUAGE_SPANISH */
/* RETRO_LANGUAGE_GERMAN */
/* RETRO_LANGUAGE_ITALIAN */
/* RETRO_LANGUAGE_DUTCH */
/* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
/* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
/* RETRO_LANGUAGE_RUSSIAN */
/* RETRO_LANGUAGE_KOREAN */
/* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
/* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
/* RETRO_LANGUAGE_ESPERANTO */
/* RETRO_LANGUAGE_POLISH */
/* RETRO_LANGUAGE_VIETNAMESE */
/* RETRO_LANGUAGE_ARABIC */
/* RETRO_LANGUAGE_GREEK */
/* RETRO_LANGUAGE_TURKISH */
/* RETRO_LANGUAGE_SLOVAK */
/* RETRO_LANGUAGE_PERSIAN */
/* RETRO_LANGUAGE_HEBREW */
/* RETRO_LANGUAGE_ASTURIAN */
/* RETRO_LANGUAGE_FINNISH */
#ifdef __cplusplus
}
#endif
#endif