From e13ffc7507e9544cb4b27a3f54b75176bc08526d Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 30 Jan 2020 17:13:44 +0100 Subject: [PATCH] Add missing samples --- .../samples/core_options/README.md | 53 +++ .../example_default/libretro_core_options.h | 284 ++++++++++++++++ .../libretro_core_options_intl.h | 80 +++++ .../libretro_core_options.h | 311 ++++++++++++++++++ .../libretro_core_options_intl.h | 80 +++++ .../libretro_core_options.h | 284 ++++++++++++++++ .../libretro_core_options_intl.h | 115 +++++++ 7 files changed, 1207 insertions(+) create mode 100644 libretro-common/samples/core_options/README.md create mode 100644 libretro-common/samples/core_options/example_default/libretro_core_options.h create mode 100644 libretro-common/samples/core_options/example_default/libretro_core_options_intl.h create mode 100644 libretro-common/samples/core_options/example_hide_option/libretro_core_options.h create mode 100644 libretro-common/samples/core_options/example_hide_option/libretro_core_options_intl.h create mode 100644 libretro-common/samples/core_options/example_translation/libretro_core_options.h create mode 100644 libretro-common/samples/core_options/example_translation/libretro_core_options_intl.h diff --git a/libretro-common/samples/core_options/README.md b/libretro-common/samples/core_options/README.md new file mode 100644 index 0000000000..ea7868b0d9 --- /dev/null +++ b/libretro-common/samples/core_options/README.md @@ -0,0 +1,53 @@ +## Adding 'enhanced' core options to a core + +The basic steps for updating a core to support core options v1 are as follows: + +- Copy `example_default/libretro_core_options.h` to the same directory as `libretro.c/.cpp` + +- Copy `example_default/libretro_core_options_intl.h` to the same directory as `libretro.c/.cpp` + +- Add `#include "libretro_core_options.h"` to `libretro.c/.cpp` + +- Replace any existing calls of `RETRO_ENVIRONMENT_SET_VARIABLES` with `libretro_set_core_options(retro_environment_t environ_cb)` + (Note: `libretro_set_core_options()` should be called as early as possible - preferably in `retro_set_environment()` + and no later than `retro_load_game()`) + +- Open `libretro_core_options.h` and replace the contents of the existing `option_defs_us` struct array with all required core option parameters. + +## Adding core option translations + +To add a translation, simply: + +- Copy the contents of `option_defs_us` *from* `libretro_core_options.h` *to* `libretro_core_options_intl.h` into a new struct array with the appropriate language suffix + +- Translate all human-readable strings + +- Add the new struct array to the appropriate location in the `option_defs_intl` array inside `libretro_core_options.h` + +This is most easily understood by considering the example in `example_translation/`. Here a French translation has been added (`option_defs_fr`), with comments explaining the appropriate formatting requirements. + +NOTE: Since translations involve the use of UTF-8 characters, `libretro_core_options_intl.h` must include a BOM marker. *This renders translations incompatible with c89 builds*. When performing a c89 build, the flag `HAVE_NO_LANGEXTRA` *must* be defined (e.g. `-DHAVE_NO_LANGEXTRA`). This will disable all translations. + +## Disabling core options on unsupported frontends + +Sometimes it is desirable to only show a particular core option if the frontend supports the new core options v1 API. For example: + +- The API v1 allows cores to hide options dynamically + +- We can therefore create a specific 'toggle display' option to hide or show a number of other options (e.g. advanced settings) + +- On frontends that do not support API v1, this 'toggle display' option will have no function - it should therefore be omitted + +This can be handled easily by editing the `libretro_set_core_options()` function to ignore certain core name (key) values when generating option variable arrays for old-style frontends. Again, this is most easily understood by considering the example in `example_hide_option/libretro_core_options.h`: + +- Here, a `mycore_show_speedhacks` option is added to `option_defs_us` + +- On line 227, the following comparison allows the option to be skipped: + (Note that another `strcmp()` may be added for each option to be omitted) + +```c +if (strcmp(key, "mycore_show_speedhacks") == 0) + continue; +``` + +For any cores that require this functionality, `example_hide_option/libretro_core_options.h` should be used as a template in place of `example_default/libretro_core_options.h` diff --git a/libretro-common/samples/core_options/example_default/libretro_core_options.h b/libretro-common/samples/core_options/example_default/libretro_core_options.h new file mode 100644 index 0000000000..04f9cb9aba --- /dev/null +++ b/libretro-common/samples/core_options/example_default/libretro_core_options.h @@ -0,0 +1,284 @@ +#ifndef LIBRETRO_CORE_OPTIONS_H__ +#define LIBRETRO_CORE_OPTIONS_H__ + +#include +#include + +#include +#include + +#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[] = { + { + "mycore_region", /* key (option name) */ + "Console Region", /* description (label) */ + "Specify which region the system is from.", /* sublabel */ + { + { "auto", "Auto" }, /* value_1, value_1_label */ + { "ntsc-j", "Japan" }, /* value_2, value_2_label */ + { "ntsc-u", "America" }, /* value_3, value_3_label */ + { "pal", "Europe" }, /* value_4, value_4_label */ + { NULL, NULL }, + }, + "auto" /* default_value */ + }, + { + "mycore_video_scale", + "Video Scale", + "Set internal video scale factor.", + { + { "1x", NULL }, /* If value itself is human-readable (e.g. a number) */ + { "2x", NULL }, /* and can displayed directly, the value_label should */ + { "3x", NULL }, /* be set to NULL */ + { "4x", NULL }, + { NULL, NULL }, + }, + "3x" + }, + { + "mycore_overclock", + "Reduce Slowdown", + "Enable CPU overclock (unsafe).", + { + { "enabled", NULL }, /* If value is equal to 'enabled' or 'disabled', */ + { "disabled", NULL }, /* value_label should be set to NULL */ + { NULL, NULL }, + }, + "disabled" + }, + { 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 */ +}; +#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 */ + while (true) + { + if (option_defs_us[num_options].key) + num_options++; + else + break; + } + + /* 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 */ + while (true) + { + if (values[num_values].value) + { + /* 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++; + } + else + break; + } + + /* 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 diff --git a/libretro-common/samples/core_options/example_default/libretro_core_options_intl.h b/libretro-common/samples/core_options/example_default/libretro_core_options_intl.h new file mode 100644 index 0000000000..16cbf7751d --- /dev/null +++ b/libretro-common/samples/core_options/example_default/libretro_core_options_intl.h @@ -0,0 +1,80 @@ +#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 + +/* + ******************************** + * 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 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libretro-common/samples/core_options/example_hide_option/libretro_core_options.h b/libretro-common/samples/core_options/example_hide_option/libretro_core_options.h new file mode 100644 index 0000000000..f75a7ec12b --- /dev/null +++ b/libretro-common/samples/core_options/example_hide_option/libretro_core_options.h @@ -0,0 +1,311 @@ +#ifndef LIBRETRO_CORE_OPTIONS_H__ +#define LIBRETRO_CORE_OPTIONS_H__ + +#include +#include + +#include +#include + +#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[] = { + { + "mycore_region", /* key (option name) */ + "Console Region", /* description (label) */ + "Specify which region the system is from.", /* sublabel */ + { + { "auto", "Auto" }, /* value_1, value_1_label */ + { "ntsc-j", "Japan" }, /* value_2, value_2_label */ + { "ntsc-u", "America" }, /* value_3, value_3_label */ + { "pal", "Europe" }, /* value_4, value_4_label */ + { NULL, NULL }, + }, + "auto" /* default_value */ + }, + { + "mycore_video_scale", + "Video Scale", + "Set internal video scale factor.", + { + { "1x", NULL }, /* If value itself is human-readable (e.g. a number) */ + { "2x", NULL }, /* and can displayed directly, the value_label should */ + { "3x", NULL }, /* be set to NULL */ + { "4x", NULL }, + { NULL, NULL }, + }, + "3x" + }, + /* This 'mycore_show_speedhacks' option will only be shown + * if the frontend supports core options API v1. + * It will be hidden on older frontends. + * See line 227 */ + { + "mycore_show_speedhacks", + "Show Unsafe Settings", + "Enable configuration of emulation speed hacks.", + { + { "enabled", NULL }, + { "disabled", NULL }, + { NULL, NULL}, + }, + "disabled" + }, + { + "mycore_overclock", + "Reduce Slowdown", + "Enable CPU overclock (unsafe).", + { + { "enabled", NULL }, /* If value is equal to 'enabled' or 'disabled', */ + { "disabled", NULL }, /* value_label should be set to NULL */ + { NULL, NULL }, + }, + "disabled" + }, + { 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 */ +}; +#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 option_index = 0; + size_t num_options = 0; + struct retro_variable *variables = NULL; + char **values_buf = NULL; + + /* Determine number of options + * > Note: We are going to skip a number of irrelevant + * core options when building the retro_variable array, + * but we'll allocate space for all of them. The difference + * in resource usage is negligible, and this allows us to + * keep the code 'cleaner' */ + while (true) + { + if (option_defs_us[num_options].key) + num_options++; + else + break; + } + + /* 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; + + /* Skip options that are irrelevant when using the + * old style core options interface */ + if (strcmp(key, "mycore_show_speedhacks") == 0) + continue; + + if (desc) + { + size_t num_values = 0; + + /* Determine number of values */ + while (true) + { + if (values[num_values].value) + { + /* 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++; + } + else + break; + } + + /* 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[option_index].key = key; + variables[option_index].value = values_buf[i]; + option_index++; + } + + /* 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 diff --git a/libretro-common/samples/core_options/example_hide_option/libretro_core_options_intl.h b/libretro-common/samples/core_options/example_hide_option/libretro_core_options_intl.h new file mode 100644 index 0000000000..16cbf7751d --- /dev/null +++ b/libretro-common/samples/core_options/example_hide_option/libretro_core_options_intl.h @@ -0,0 +1,80 @@ +#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 + +/* + ******************************** + * 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 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libretro-common/samples/core_options/example_translation/libretro_core_options.h b/libretro-common/samples/core_options/example_translation/libretro_core_options.h new file mode 100644 index 0000000000..d5cd4aa614 --- /dev/null +++ b/libretro-common/samples/core_options/example_translation/libretro_core_options.h @@ -0,0 +1,284 @@ +#ifndef LIBRETRO_CORE_OPTIONS_H__ +#define LIBRETRO_CORE_OPTIONS_H__ + +#include +#include + +#include +#include + +#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[] = { + { + "mycore_region", /* key (option name) */ + "Console Region", /* description (label) */ + "Specify which region the system is from.", /* sublabel */ + { + { "auto", "Auto" }, /* value_1, value_1_label */ + { "ntsc-j", "Japan" }, /* value_2, value_2_label */ + { "ntsc-u", "America" }, /* value_3, value_3_label */ + { "pal", "Europe" }, /* value_4, value_4_label */ + { NULL, NULL }, + }, + "auto" /* default_value */ + }, + { + "mycore_video_scale", + "Video Scale", + "Set internal video scale factor.", + { + { "1x", NULL }, /* If value itself is human-readable (e.g. a number) */ + { "2x", NULL }, /* and can displayed directly, the value_label should */ + { "3x", NULL }, /* be set to NULL */ + { "4x", NULL }, + { NULL, NULL }, + }, + "3x" + }, + { + "mycore_overclock", + "Reduce Slowdown", + "Enable CPU overclock (unsafe).", + { + { "enabled", NULL }, /* If value is equal to 'enabled' or 'disabled', */ + { "disabled", NULL }, /* value_label should be set to NULL */ + { NULL, NULL }, + }, + "disabled" + }, + { 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 */ + option_defs_fr, /* 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 */ +}; +#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 */ + while (true) + { + if (option_defs_us[num_options].key) + num_options++; + else + break; + } + + /* 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 */ + while (true) + { + if (values[num_values].value) + { + /* 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++; + } + else + break; + } + + /* 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 diff --git a/libretro-common/samples/core_options/example_translation/libretro_core_options_intl.h b/libretro-common/samples/core_options/example_translation/libretro_core_options_intl.h new file mode 100644 index 0000000000..cd5cbb969d --- /dev/null +++ b/libretro-common/samples/core_options/example_translation/libretro_core_options_intl.h @@ -0,0 +1,115 @@ +#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 + +/* + ******************************** + * 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 */ + +struct retro_core_option_definition option_defs_fr[] = { + { + "mycore_region", /* key must match option_defs_us entry */ + "Région de la console", /* translated description */ + "Spécifiez la région d'origine du système.", /* translated sublabel */ + { + { "auto", "Auto" }, /* value must match option_defs_us entry */ + { "ntsc-j", "Japon" }, /* > only value_label should be translated */ + { "ntsc-u", "Amérique" }, + { "pal", "L'Europe" }, + { NULL, NULL }, + }, + NULL /* default_value is taken from option_defs_us -> can set to NULL here */ + }, + { + "mycore_video_scale", + "Échelle vidéo", + "Définir le facteur d'échelle vidéo interne.", + { + { NULL, NULL }, /* If value_labels do not require translation (e.g. numbers), values may be omitted */ + }, + NULL + }, + { + "mycore_overclock", + "Réduire le ralentissement", + "Activer l'overclocking du processeur (non sécurisé).", + { + { NULL, NULL }, /* 'enabled' and 'disabled' values should not be translated */ + }, + NULL + }, + { NULL, NULL, NULL, {{0}}, NULL }, +}; + +/* 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 */ + +#ifdef __cplusplus +} +#endif + +#endif