db: Override cycle multiplier for Colin McRae PAL
[pcsx_rearmed.git] / deps / libretro-common / samples / core_options / example_categories / libretro_core_options.h
CommitLineData
3719602c
PC
1#ifndef LIBRETRO_CORE_OPTIONS_H__
2#define LIBRETRO_CORE_OPTIONS_H__
3
4#include <stdlib.h>
5#include <string.h>
6
7#include <libretro.h>
8#include <retro_inline.h>
9
10#ifndef HAVE_NO_LANGEXTRA
11#include "libretro_core_options_intl.h"
12#endif
13
14/*
15 ********************************
16 * VERSION: 2.0
17 ********************************
18 *
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
30 * - 1.0: First commit
31*/
32
33#ifdef __cplusplus
34extern "C" {
35#endif
36
37/*
38 ********************************
39 * Core Option Definitions
40 ********************************
41*/
42
43/* RETRO_LANGUAGE_ENGLISH */
44
45/* Default language:
46 * - All other languages must include the same keys and values
47 * - Will be used as a fallback in the event that frontend language
48 * is not available
49 * - Will be used as a fallback for any missing entries in
50 * frontend language definition */
51
52struct retro_core_option_v2_category option_cats_us[] = {
53 {
54 "video", /* key (category name) */
55 "Video", /* category description (label) */
56 "Configure display options." /* category sublabel */
57 },
58 {
59 "hacks",
60 "Advanced",
61 "Options affecting low-level emulation performance and accuracy."
62 },
63 { NULL, NULL, NULL },
64};
65
66struct retro_core_option_v2_definition option_defs_us[] = {
67 {
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 */
82 {
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 */
87 { NULL, NULL },
88 },
89 "auto" /* default_value */
90 },
91 {
92 "mycore_video_scale",
93 "Video > Scale", /* description: here a 'Video >' prefix is used to
94 * signify a category on frontends without explicit
95 * category support */
96 "Scale", /* 'categorised' description: will be displayed inside
97 * the 'Video' submenu */
98 "Set internal video scale factor.",
99 NULL,
100 "video", /* category key */
101 {
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 */
105 { "4x", NULL },
106 { NULL, NULL },
107 },
108 "3x"
109 },
110 {
111 "mycore_overclock",
112 "Advanced > Reduce Slowdown",
113 "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' */
118 "hacks",
119 {
120 { "enabled", NULL }, /* If value is equal to 'enabled' or 'disabled', */
121 { "disabled", NULL }, /* value_label should be set to NULL */
122 { NULL, NULL },
123 },
124 "disabled"
125 },
126 { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },
127};
128
129struct retro_core_options_v2 options_us = {
130 option_cats_us,
131 option_defs_us
132};
133
134/*
135 ********************************
136 * Language Mapping
137 ********************************
138*/
139
140#ifndef HAVE_NO_LANGEXTRA
141struct 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 */
170};
171#endif
172
173/*
174 ********************************
175 * Functions
176 ********************************
177*/
178
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)
185 */
186
187static INLINE void libretro_set_core_options(retro_environment_t environ_cb,
188 bool *categories_supported)
189{
190 unsigned version = 0;
191#ifndef HAVE_NO_LANGEXTRA
192 unsigned language = 0;
193#endif
194
195 if (!environ_cb || !categories_supported)
196 return;
197
198 *categories_supported = false;
199
200 if (!environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version))
201 version = 0;
202
203 if (version >= 2)
204 {
205#ifndef HAVE_NO_LANGEXTRA
206 struct retro_core_options_v2_intl core_options_intl;
207
208 core_options_intl.us = &options_us;
209 core_options_intl.local = NULL;
210
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];
214
215 *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,
216 &core_options_intl);
217#else
218 *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,
219 &options_us);
220#endif
221 }
222 else
223 {
224 size_t i, j;
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;
237#endif
238 struct retro_variable *variables = NULL;
239 char **values_buf = NULL;
240
241 /* Determine total number of options */
242 while (true)
243 {
244 if (option_defs_us[num_options].key)
245 num_options++;
246 else
247 break;
248 }
249
250 if (version >= 1)
251 {
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));
255
256 /* Copy parameters from option_defs_us array */
257 for (i = 0; i < num_options; i++)
258 {
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;
263
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;
268
269 /* Values must be copied individually... */
270 while (option_values->value)
271 {
272 option_v1_values->value = option_values->value;
273 option_v1_values->label = option_values->label;
274
275 option_values++;
276 option_v1_values++;
277 }
278 }
279
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;
285
286 if (option_defs_intl)
287 {
288 /* Determine number of intl options */
289 while (true)
290 {
291 if (option_defs_intl[num_options_intl].key)
292 num_options_intl++;
293 else
294 break;
295 }
296
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));
300
301 /* Copy parameters from option_defs_intl array */
302 for (i = 0; i < num_options_intl; i++)
303 {
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;
308
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;
313
314 /* Values must be copied individually... */
315 while (option_values->value)
316 {
317 option_v1_values->value = option_values->value;
318 option_v1_values->label = option_values->label;
319
320 option_values++;
321 option_v1_values++;
322 }
323 }
324 }
325
326 core_options_v1_intl.us = option_v1_defs_us;
327 core_options_v1_intl.local = option_v1_defs_intl;
328
329 environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_v1_intl);
330#else
331 environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, option_v1_defs_us);
332#endif
333 }
334 else
335 {
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 *));
340
341 if (!variables || !values_buf)
342 goto error;
343
344 /* Copy parameters from option_defs_us array */
345 for (i = 0; i < num_options; i++)
346 {
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;
351 size_t buf_len = 3;
352 size_t default_index = 0;
353
354 values_buf[i] = NULL;
355
356 if (desc)
357 {
358 size_t num_values = 0;
359
360 /* Determine number of values */
361 while (true)
362 {
363 if (values[num_values].value)
364 {
365 /* Check if this is the default value */
366 if (default_value)
367 if (strcmp(values[num_values].value, default_value) == 0)
368 default_index = num_values;
369
370 buf_len += strlen(values[num_values].value);
371 num_values++;
372 }
373 else
374 break;
375 }
376
377 /* Build values string */
378 if (num_values > 0)
379 {
380 buf_len += num_values - 1;
381 buf_len += strlen(desc);
382
383 values_buf[i] = (char *)calloc(buf_len, sizeof(char));
384 if (!values_buf[i])
385 goto error;
386
387 strcpy(values_buf[i], desc);
388 strcat(values_buf[i], "; ");
389
390 /* Default value goes first */
391 strcat(values_buf[i], values[default_index].value);
392
393 /* Add remaining values */
394 for (j = 0; j < num_values; j++)
395 {
396 if (j != default_index)
397 {
398 strcat(values_buf[i], "|");
399 strcat(values_buf[i], values[j].value);
400 }
401 }
402 }
403 }
404
405 variables[option_index].key = key;
406 variables[option_index].value = values_buf[i];
407 option_index++;
408 }
409
410 /* Set variables */
411 environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);
412 }
413
414error:
415 /* Clean up */
416
417 if (option_v1_defs_us)
418 {
419 free(option_v1_defs_us);
420 option_v1_defs_us = NULL;
421 }
422
423#ifndef HAVE_NO_LANGEXTRA
424 if (option_v1_defs_intl)
425 {
426 free(option_v1_defs_intl);
427 option_v1_defs_intl = NULL;
428 }
429#endif
430
431 if (values_buf)
432 {
433 for (i = 0; i < num_options; i++)
434 {
435 if (values_buf[i])
436 {
437 free(values_buf[i]);
438 values_buf[i] = NULL;
439 }
440 }
441
442 free(values_buf);
443 values_buf = NULL;
444 }
445
446 if (variables)
447 {
448 free(variables);
449 variables = NULL;
450 }
451 }
452}
453
454#ifdef __cplusplus
455}
456#endif
457
458#endif