1 #ifndef LIBRETRO_CORE_OPTIONS_H__
2 #define LIBRETRO_CORE_OPTIONS_H__
8 #include <retro_inline.h>
10 #ifndef HAVE_NO_LANGEXTRA
11 #include "libretro_core_options_intl.h"
15 ********************************
17 ********************************
19 * - 2.0: Add support for core options v2 interface
20 * - 1.3: Move translations to libretro_core_options_intl.h
21 * - libretro_core_options_intl.h includes BOM and utf-8
22 * fix for MSVC 2010-2013
23 * - Added HAVE_NO_LANGEXTRA flag to disable translations
24 * on platforms/compilers without BOM support
25 * - 1.2: Use core options v1 interface when
26 * RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1
27 * (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
28 * - 1.1: Support generation of core options v0 retro_core_option_value
29 * arrays containing options with a single value
38 ********************************
39 * Core Option Definitions
40 ********************************
43 /* RETRO_LANGUAGE_ENGLISH */
46 * - All other languages must include the same keys and values
47 * - Will be used as a fallback in the event that frontend language
49 * - Will be used as a fallback for any missing entries in
50 * frontend language definition */
52 struct retro_core_option_v2_category option_cats_us[] = {
54 "video", /* key (category name) */
55 "Video", /* category description (label) */
56 "Configure display options." /* category sublabel */
61 "Options affecting low-level emulation performance and accuracy."
66 struct retro_core_option_v2_definition option_defs_us[] = {
68 "mycore_region", /* key (option name) */
69 "Console Region", /* description (label) */
70 NULL, /* 'categorised' description (used instead of
71 * 'description' if frontend has category
72 * support; if NULL or empty, regular
73 * description is always used */
74 "Specify which region the system is from.", /* sublabel */
75 NULL, /* 'categorised' sublabel (used instead of
76 * 'sublabel' if frontend has category
77 * support; if NULL or empty, regular
78 * sublabel is always used */
79 NULL, /* category key (must match an entry in
80 * option_cats_us; if NULL or empty,
81 * option is uncategorised */
83 { "auto", "Auto" }, /* value_1, value_1_label */
84 { "ntsc-j", "Japan" }, /* value_2, value_2_label */
85 { "ntsc-u", "America" }, /* value_3, value_3_label */
86 { "pal", "Europe" }, /* value_4, value_4_label */
89 "auto" /* default_value */
93 "Video > Scale", /* description: here a 'Video >' prefix is used to
94 * signify a category on frontends without explicit
96 "Scale", /* 'categorised' description: will be displayed inside
97 * the 'Video' submenu */
98 "Set internal video scale factor.",
100 "video", /* category key */
102 { "1x", NULL }, /* If value itself is human-readable (e.g. a number) */
103 { "2x", NULL }, /* and can displayed directly, the value_label should */
104 { "3x", NULL }, /* be set to NULL */
112 "Advanced > Reduce Slowdown",
114 "Enabling 'Advanced > Reduce Slowdown' will reduce accuracy.", /* sublabel */
115 "Enabling 'Reduce Slowdown' will reduce accuracy.", /* 'categorised' sublabel:
116 * will be displayed inside the 'Advanced' submenu; note that
117 * 'Advanced > Reduce Slowdown' is replaced with 'Reduce Slowdown' */
120 { "enabled", NULL }, /* If value is equal to 'enabled' or 'disabled', */
121 { "disabled", NULL }, /* value_label should be set to NULL */
126 { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },
129 struct retro_core_options_v2 options_us = {
135 ********************************
137 ********************************
140 #ifndef HAVE_NO_LANGEXTRA
141 struct retro_core_options_v2 *options_intl[RETRO_LANGUAGE_LAST] = {
142 &options_us, /* RETRO_LANGUAGE_ENGLISH */
143 NULL, /* RETRO_LANGUAGE_JAPANESE */
144 &options_fr, /* RETRO_LANGUAGE_FRENCH */
145 NULL, /* RETRO_LANGUAGE_SPANISH */
146 NULL, /* RETRO_LANGUAGE_GERMAN */
147 NULL, /* RETRO_LANGUAGE_ITALIAN */
148 NULL, /* RETRO_LANGUAGE_DUTCH */
149 NULL, /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
150 NULL, /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
151 NULL, /* RETRO_LANGUAGE_RUSSIAN */
152 NULL, /* RETRO_LANGUAGE_KOREAN */
153 NULL, /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
154 NULL, /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
155 NULL, /* RETRO_LANGUAGE_ESPERANTO */
156 NULL, /* RETRO_LANGUAGE_POLISH */
157 NULL, /* RETRO_LANGUAGE_VIETNAMESE */
158 NULL, /* RETRO_LANGUAGE_ARABIC */
159 NULL, /* RETRO_LANGUAGE_GREEK */
160 NULL, /* RETRO_LANGUAGE_TURKISH */
161 NULL, /* RETRO_LANGUAGE_SLOVAK */
162 NULL, /* RETRO_LANGUAGE_PERSIAN */
163 NULL, /* RETRO_LANGUAGE_HEBREW */
164 NULL, /* RETRO_LANGUAGE_ASTURIAN */
165 NULL, /* RETRO_LANGUAGE_FINNISH */
166 NULL, /* RETRO_LANGUAGE_INDONESIAN */
167 NULL, /* RETRO_LANGUAGE_SWEDISH */
168 NULL, /* RETRO_LANGUAGE_UKRAINIAN */
169 NULL, /* RETRO_LANGUAGE_CZECH */
174 ********************************
176 ********************************
179 /* Handles configuration/setting of core options.
180 * Should be called as early as possible - ideally inside
181 * retro_set_environment(), and no later than retro_load_game()
182 * > We place the function body in the header to avoid the
183 * necessity of adding more .c files (i.e. want this to
184 * be as painless as possible for core devs)
187 static INLINE void libretro_set_core_options(retro_environment_t environ_cb,
188 bool *categories_supported)
190 unsigned version = 0;
191 #ifndef HAVE_NO_LANGEXTRA
192 unsigned language = 0;
195 if (!environ_cb || !categories_supported)
198 *categories_supported = false;
200 if (!environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version))
205 #ifndef HAVE_NO_LANGEXTRA
206 struct retro_core_options_v2_intl core_options_intl;
208 core_options_intl.us = &options_us;
209 core_options_intl.local = NULL;
211 if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&
212 (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH))
213 core_options_intl.local = options_intl[language];
215 *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,
218 *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,
225 size_t option_index = 0;
226 size_t num_options = 0;
227 struct retro_core_option_definition
228 *option_v1_defs_us = NULL;
229 #ifndef HAVE_NO_LANGEXTRA
230 size_t num_options_intl = 0;
231 struct retro_core_option_v2_definition
232 *option_defs_intl = NULL;
233 struct retro_core_option_definition
234 *option_v1_defs_intl = NULL;
235 struct retro_core_options_intl
236 core_options_v1_intl;
238 struct retro_variable *variables = NULL;
239 char **values_buf = NULL;
241 /* Determine total number of options */
244 if (option_defs_us[num_options].key)
252 /* Allocate US array */
253 option_v1_defs_us = (struct retro_core_option_definition *)
254 calloc(num_options + 1, sizeof(struct retro_core_option_definition));
256 /* Copy parameters from option_defs_us array */
257 for (i = 0; i < num_options; i++)
259 struct retro_core_option_v2_definition *option_def_us = &option_defs_us[i];
260 struct retro_core_option_value *option_values = option_def_us->values;
261 struct retro_core_option_definition *option_v1_def_us = &option_v1_defs_us[i];
262 struct retro_core_option_value *option_v1_values = option_v1_def_us->values;
264 option_v1_def_us->key = option_def_us->key;
265 option_v1_def_us->desc = option_def_us->desc;
266 option_v1_def_us->info = option_def_us->info;
267 option_v1_def_us->default_value = option_def_us->default_value;
269 /* Values must be copied individually... */
270 while (option_values->value)
272 option_v1_values->value = option_values->value;
273 option_v1_values->label = option_values->label;
280 #ifndef HAVE_NO_LANGEXTRA
281 if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&
282 (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH) &&
283 options_intl[language])
284 option_defs_intl = options_intl[language]->definitions;
286 if (option_defs_intl)
288 /* Determine number of intl options */
291 if (option_defs_intl[num_options_intl].key)
297 /* Allocate intl array */
298 option_v1_defs_intl = (struct retro_core_option_definition *)
299 calloc(num_options_intl + 1, sizeof(struct retro_core_option_definition));
301 /* Copy parameters from option_defs_intl array */
302 for (i = 0; i < num_options_intl; i++)
304 struct retro_core_option_v2_definition *option_def_intl = &option_defs_intl[i];
305 struct retro_core_option_value *option_values = option_def_intl->values;
306 struct retro_core_option_definition *option_v1_def_intl = &option_v1_defs_intl[i];
307 struct retro_core_option_value *option_v1_values = option_v1_def_intl->values;
309 option_v1_def_intl->key = option_def_intl->key;
310 option_v1_def_intl->desc = option_def_intl->desc;
311 option_v1_def_intl->info = option_def_intl->info;
312 option_v1_def_intl->default_value = option_def_intl->default_value;
314 /* Values must be copied individually... */
315 while (option_values->value)
317 option_v1_values->value = option_values->value;
318 option_v1_values->label = option_values->label;
326 core_options_v1_intl.us = option_v1_defs_us;
327 core_options_v1_intl.local = option_v1_defs_intl;
329 environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_v1_intl);
331 environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, option_v1_defs_us);
336 /* Allocate arrays */
337 variables = (struct retro_variable *)calloc(num_options + 1,
338 sizeof(struct retro_variable));
339 values_buf = (char **)calloc(num_options, sizeof(char *));
341 if (!variables || !values_buf)
344 /* Copy parameters from option_defs_us array */
345 for (i = 0; i < num_options; i++)
347 const char *key = option_defs_us[i].key;
348 const char *desc = option_defs_us[i].desc;
349 const char *default_value = option_defs_us[i].default_value;
350 struct retro_core_option_value *values = option_defs_us[i].values;
352 size_t default_index = 0;
354 values_buf[i] = NULL;
358 size_t num_values = 0;
360 /* Determine number of values */
363 if (values[num_values].value)
365 /* Check if this is the default value */
367 if (strcmp(values[num_values].value, default_value) == 0)
368 default_index = num_values;
370 buf_len += strlen(values[num_values].value);
377 /* Build values string */
380 buf_len += num_values - 1;
381 buf_len += strlen(desc);
383 values_buf[i] = (char *)calloc(buf_len, sizeof(char));
387 strcpy(values_buf[i], desc);
388 strcat(values_buf[i], "; ");
390 /* Default value goes first */
391 strcat(values_buf[i], values[default_index].value);
393 /* Add remaining values */
394 for (j = 0; j < num_values; j++)
396 if (j != default_index)
398 strcat(values_buf[i], "|");
399 strcat(values_buf[i], values[j].value);
405 variables[option_index].key = key;
406 variables[option_index].value = values_buf[i];
411 environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);
417 if (option_v1_defs_us)
419 free(option_v1_defs_us);
420 option_v1_defs_us = NULL;
423 #ifndef HAVE_NO_LANGEXTRA
424 if (option_v1_defs_intl)
426 free(option_v1_defs_intl);
427 option_v1_defs_intl = NULL;
433 for (i = 0; i < num_options; i++)
438 values_buf[i] = NULL;