From 0c82e4c73e0771433f25648edb82608919c5a903 Mon Sep 17 00:00:00 2001 From: jdgleaver Date: Tue, 19 Oct 2021 17:33:56 +0100 Subject: [PATCH] Update core options to v2 format (add category support) --- .../libretro-common/include/libretro.h | 799 ++++++++++++++++- src/drivers/libretro/libretro.c | 229 +++-- src/drivers/libretro/libretro_core_options.h | 806 +++++++++++------- .../libretro/libretro_core_options_intl.h | 91 ++ src/drivers/libretro/libretro_dipswitch.c | 44 +- src/drivers/libretro/libretro_dipswitch.h | 2 +- src/ntsc/nes_ntsc_config.h | 2 +- 7 files changed, 1570 insertions(+), 403 deletions(-) create mode 100644 src/drivers/libretro/libretro_core_options_intl.h diff --git a/src/drivers/libretro/libretro-common/include/libretro.h b/src/drivers/libretro/libretro-common/include/libretro.h index 8a5da86..2f17483 100644 --- a/src/drivers/libretro/libretro-common/include/libretro.h +++ b/src/drivers/libretro/libretro-common/include/libretro.h @@ -1131,6 +1131,13 @@ enum retro_mod * retro_core_option_definition structs to RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL. * This allows the core to additionally set option sublabel information * and/or provide localisation support. + * + * If version is >= 2, core options may instead be set by passing + * a retro_core_options_v2 struct to RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2, + * or an array of retro_core_options_v2 structs to + * RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL. This allows the core + * to additionally set optional core option category information + * for frontends with core option category support. */ #define RETRO_ENVIRONMENT_SET_CORE_OPTIONS 53 @@ -1172,7 +1179,7 @@ enum retro_mod * default value is NULL, the first entry in the * retro_core_option_definition::values array is treated as the default. * - * The number of possible options should be very limited, + * The number of possible option values should be very limited, * and must be less than RETRO_NUM_CORE_OPTION_VALUES_MAX. * i.e. it should be feasible to cycle through options * without a keyboard. @@ -1205,6 +1212,7 @@ enum retro_mod * 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 instead of RETRO_ENVIRONMENT_SET_CORE_OPTIONS. * This should be called the first time as early as * possible (ideally in retro_set_environment). * Afterwards it may be called again for the core to communicate @@ -1378,6 +1386,373 @@ enum retro_mod * 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). + */ + +#define RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE 65 + /* const struct retro_system_content_info_override * -- + * Allows an implementation to override 'global' content + * info parameters reported by retro_get_system_info(). + * Overrides also affect subsystem content info parameters + * set via RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO. + * This function must be called inside retro_set_environment(). + * If callback returns false, content info overrides + * are unsupported by the frontend, and will be ignored. + * If callback returns true, extended game info may be + * retrieved by calling RETRO_ENVIRONMENT_GET_GAME_INFO_EXT + * in retro_load_game() or retro_load_game_special(). + * + * 'data' points to an array of retro_system_content_info_override + * structs terminated by a { NULL, false, false } element. + * If 'data' is NULL, no changes will be made to the frontend; + * a core may therefore pass NULL in order to test whether + * the RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE and + * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT callbacks are supported + * by the frontend. + * + * For struct member descriptions, see the definition of + * struct retro_system_content_info_override. + * + * Example: + * + * - struct retro_system_info: + * { + * "My Core", // library_name + * "v1.0", // library_version + * "m3u|md|cue|iso|chd|sms|gg|sg", // valid_extensions + * true, // need_fullpath + * false // block_extract + * } + * + * - Array of struct retro_system_content_info_override: + * { + * { + * "md|sms|gg", // extensions + * false, // need_fullpath + * true // persistent_data + * }, + * { + * "sg", // extensions + * false, // need_fullpath + * false // persistent_data + * }, + * { NULL, false, false } + * } + * + * Result: + * - Files of type m3u, cue, iso, chd will not be + * loaded by the frontend. Frontend will pass a + * valid path to the core, and core will handle + * loading internally + * - Files of type md, sms, gg will be loaded by + * the frontend. A valid memory buffer will be + * passed to the core. This memory buffer will + * remain valid until retro_deinit() returns + * - Files of type sg will be loaded by the frontend. + * A valid memory buffer will be passed to the core. + * This memory buffer will remain valid until + * retro_load_game() (or retro_load_game_special()) + * returns + * + * NOTE: If an extension is listed multiple times in + * an array of retro_system_content_info_override + * structs, only the first instance will be registered + */ + +#define RETRO_ENVIRONMENT_GET_GAME_INFO_EXT 66 + /* const struct retro_game_info_ext ** -- + * Allows an implementation to fetch extended game + * information, providing additional content path + * and memory buffer status details. + * This function may only be called inside + * retro_load_game() or retro_load_game_special(). + * If callback returns false, extended game information + * is unsupported by the frontend. In this case, only + * regular retro_game_info will be available. + * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT is guaranteed + * to return true if RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE + * returns true. + * + * 'data' points to an array of retro_game_info_ext structs. + * + * For struct member descriptions, see the definition of + * struct retro_game_info_ext. + * + * - If function is called inside retro_load_game(), + * the retro_game_info_ext array is guaranteed to + * have a size of 1 - i.e. the returned pointer may + * be used to access directly the members of the + * first retro_game_info_ext struct, for example: + * + * struct retro_game_info_ext *game_info_ext; + * if (environ_cb(RETRO_ENVIRONMENT_GET_GAME_INFO_EXT, &game_info_ext)) + * printf("Content Directory: %s\n", game_info_ext->dir); + * + * - If the function is called inside retro_load_game_special(), + * the retro_game_info_ext array is guaranteed to have a + * size equal to the num_info argument passed to + * retro_load_game_special() + */ + +#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 67 + /* const struct retro_core_options_v2 * -- + * Allows an implementation to signal the environment + * which variables it might want to check for later using + * GET_VARIABLE. + * This allows the frontend to present these variables to + * a user dynamically. + * This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION + * returns an API version of >= 2. + * This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES. + * This should be called instead of RETRO_ENVIRONMENT_SET_CORE_OPTIONS. + * This should be called the first time as early as + * possible (ideally in retro_set_environment). + * Afterwards it may be called again for the core to communicate + * updated options to the frontend, but the number of core + * options must not change from the number in the initial call. + * If RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION returns an API + * version of >= 2, this callback is guaranteed to succeed + * (i.e. callback return value does not indicate success) + * If callback returns true, frontend has core option category + * support. + * If callback returns false, frontend does not have core option + * category support. + * + * 'data' points to a retro_core_options_v2 struct, containing + * of two pointers: + * - retro_core_options_v2::categories is an array of + * retro_core_option_v2_category structs terminated by a + * { NULL, NULL, NULL } element. If retro_core_options_v2::categories + * is NULL, all core options will have no category and will be shown + * at the top level of the frontend core option interface. If frontend + * does not have core option category support, categories array will + * be ignored. + * - retro_core_options_v2::definitions is an array of + * retro_core_option_v2_definition structs terminated by a + * { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL } + * element. + * + * >> retro_core_option_v2_category notes: + * + * - retro_core_option_v2_category::key should contain string + * that uniquely identifies the core option category. Valid + * key characters are [a-z, A-Z, 0-9, _, -] + * Namespace collisions with other implementations' category + * keys are permitted. + * - retro_core_option_v2_category::desc should contain a human + * readable description of the category key. + * - retro_core_option_v2_category::info should contain any + * additional human readable information text that a typical + * user may need to understand the nature of the core option + * category. + * + * Example entry: + * { + * "advanced_settings", + * "Advanced", + * "Options affecting low-level emulation performance and accuracy." + * } + * + * >> retro_core_option_v2_definition notes: + * + * - retro_core_option_v2_definition::key should be namespaced to not + * collide with other implementations' keys. e.g. A core called + * 'foo' should use keys named as 'foo_option'. Valid key characters + * are [a-z, A-Z, 0-9, _, -]. + * - retro_core_option_v2_definition::desc should contain a human readable + * description of the key. Will be used when the frontend does not + * have core option category support. Examples: "Aspect Ratio" or + * "Video > Aspect Ratio". + * - retro_core_option_v2_definition::desc_categorized should contain a + * human readable description of the key, which will be used when + * frontend has core option category support. Example: "Aspect Ratio", + * where associated retro_core_option_v2_category::desc is "Video". + * If empty or NULL, the string specified by + * retro_core_option_v2_definition::desc will be used instead. + * retro_core_option_v2_definition::desc_categorized will be ignored + * if retro_core_option_v2_definition::category_key is empty or NULL. + * - retro_core_option_v2_definition::info should contain any additional + * human readable information text that a typical user may need to + * understand the functionality of the option. + * - retro_core_option_v2_definition::info_categorized should contain + * any additional human readable information text that a typical user + * may need to understand the functionality of the option, and will be + * used when frontend has core option category support. This is provided + * to accommodate the case where info text references an option by + * name/desc, and the desc/desc_categorized text for that option differ. + * If empty or NULL, the string specified by + * retro_core_option_v2_definition::info will be used instead. + * retro_core_option_v2_definition::info_categorized will be ignored + * if retro_core_option_v2_definition::category_key is empty or NULL. + * - retro_core_option_v2_definition::category_key should contain a + * category identifier (e.g. "video" or "audio") that will be + * assigned to the core option if frontend has core option category + * support. A categorized option will be shown in a subsection/ + * submenu of the frontend core option interface. If key is empty + * or NULL, or if key does not match one of the + * retro_core_option_v2_category::key values in the associated + * retro_core_option_v2_category array, option will have no category + * and will be shown at the top level of the frontend core option + * interface. + * - retro_core_option_v2_definition::values is an array of + * retro_core_option_value structs terminated by a { NULL, NULL } + * element. + * --> retro_core_option_v2_definition::values[index].value is an + * expected option value. + * --> retro_core_option_v2_definition::values[index].label is a + * human readable label used when displaying the value on screen. + * If NULL, the value itself is used. + * - retro_core_option_v2_definition::default_value is the default + * core option setting. It must match one of the expected option + * values in the retro_core_option_v2_definition::values array. If + * it does not, or the default value is NULL, the first entry in the + * retro_core_option_v2_definition::values array is treated as the + * default. + * + * The number of possible option values should be very limited, + * and must be less than RETRO_NUM_CORE_OPTION_VALUES_MAX. + * i.e. it should be feasible to cycle through options + * without a keyboard. + * + * Example entries: + * + * - Uncategorized: + * + * { + * "foo_option", + * "Speed hack coprocessor X", + * NULL, + * "Provides increased performance at the expense of reduced accuracy.", + * NULL, + * NULL, + * { + * { "false", NULL }, + * { "true", NULL }, + * { "unstable", "Turbo (Unstable)" }, + * { NULL, NULL }, + * }, + * "false" + * } + * + * - Categorized: + * + * { + * "foo_option", + * "Advanced > Speed hack coprocessor X", + * "Speed hack coprocessor X", + * "Setting 'Advanced > Speed hack coprocessor X' to 'true' or 'Turbo' provides increased performance at the expense of reduced accuracy", + * "Setting 'Speed hack coprocessor X' to 'true' or 'Turbo' provides increased performance at the expense of reduced accuracy", + * "advanced_settings", + * { + * { "false", NULL }, + * { "true", NULL }, + * { "unstable", "Turbo (Unstable)" }, + * { NULL, NULL }, + * }, + * "false" + * } + * + * Only strings are operated on. The possible values will + * generally be displayed and stored as-is by the frontend. + */ + +#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL 68 + /* const struct retro_core_options_v2_intl * -- + * Allows an implementation to signal the environment + * which variables it might want to check for later using + * GET_VARIABLE. + * This allows the frontend to present these variables to + * a user dynamically. + * This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION + * returns an API version of >= 2. + * This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES. + * This should be called instead of RETRO_ENVIRONMENT_SET_CORE_OPTIONS. + * This should be called instead of RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL. + * This should be called instead of RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2. + * This should be called the first time as early as + * possible (ideally in retro_set_environment). + * Afterwards it may be called again for the core to communicate + * updated options to the frontend, but the number of core + * options must not change from the number in the initial call. + * If RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION returns an API + * version of >= 2, this callback is guaranteed to succeed + * (i.e. callback return value does not indicate success) + * If callback returns true, frontend has core option category + * support. + * If callback returns false, frontend does not have core option + * category support. + * + * This is fundamentally the same as RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2, + * with the addition of localisation support. The description of the + * RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 callback should be consulted + * for further details. + * + * 'data' points to a retro_core_options_v2_intl struct. + * + * - retro_core_options_v2_intl::us is a pointer to a + * retro_core_options_v2 struct defining the US English + * core options implementation. It must point to a valid struct. + * + * - retro_core_options_v2_intl::local is a pointer to a + * retro_core_options_v2 struct defining core options for + * the current frontend language. It may be NULL (in which case + * retro_core_options_v2_intl::us is used by the frontend). Any items + * missing from this struct will be read from + * retro_core_options_v2_intl::us instead. + * + * NOTE: Default core option values are always taken from the + * retro_core_options_v2_intl::us struct. Any default values in + * the retro_core_options_v2_intl::local struct will be ignored. + */ + +#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK 69 + /* const struct retro_core_options_update_display_callback * -- + * Allows a frontend to signal that a core must update + * the visibility of any dynamically hidden core options, + * and enables the frontend to detect visibility changes. + * Used by the frontend to update the menu display status + * of core options without requiring a call of retro_run(). + * Must be called in retro_set_environment(). + */ + +#define RETRO_ENVIRONMENT_SET_VARIABLE 70 + /* const struct retro_variable * -- + * Allows an implementation to notify the frontend + * that a core option value has changed. + * + * retro_variable::key and retro_variable::value + * must match strings that have been set previously + * via one of the following: + * + * - RETRO_ENVIRONMENT_SET_VARIABLES + * - RETRO_ENVIRONMENT_SET_CORE_OPTIONS + * - RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL + * - RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 + * - RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL + * + * After changing a core option value via this + * callback, RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE + * will return true. + * + * If data is NULL, no changes will be registered + * and the callback will return true; an + * implementation may therefore pass NULL in order + * to test whether the callback is supported. + */ + +#define RETRO_ENVIRONMENT_GET_THROTTLE_STATE (71 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* struct retro_throttle_state * -- + * Allows an implementation to get details on the actual rate + * the frontend is attempting to call retro_run(). + */ + /* VFS functionality */ /* File paths: @@ -2781,6 +3156,213 @@ struct retro_system_info bool block_extract; }; +/* Defines overrides which modify frontend handling of + * specific content file types. + * An array of retro_system_content_info_override is + * passed to RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE + * NOTE: In the following descriptions, references to + * retro_load_game() may be replaced with + * retro_load_game_special() */ +struct retro_system_content_info_override +{ + /* A list of file extensions for which the override + * should apply, delimited by a 'pipe' character + * (e.g. "md|sms|gg") + * Permitted file extensions are limited to those + * included in retro_system_info::valid_extensions + * and/or retro_subsystem_rom_info::valid_extensions */ + const char *extensions; + + /* Overrides the need_fullpath value set in + * retro_system_info and/or retro_subsystem_rom_info. + * To reiterate: + * + * If need_fullpath is true and retro_load_game() is called: + * - retro_game_info::path is guaranteed to contain a valid + * path to an existent file + * - retro_game_info::data and retro_game_info::size are invalid + * + * If need_fullpath is false and retro_load_game() is called: + * - retro_game_info::path may be NULL + * - retro_game_info::data and retro_game_info::size are guaranteed + * to be valid + * + * In addition: + * + * If need_fullpath is true and retro_load_game() is called: + * - retro_game_info_ext::full_path is guaranteed to contain a valid + * path to an existent file + * - retro_game_info_ext::archive_path may be NULL + * - retro_game_info_ext::archive_file may be NULL + * - retro_game_info_ext::dir is guaranteed to contain a valid path + * to the directory in which the content file exists + * - retro_game_info_ext::name is guaranteed to contain the + * basename of the content file, without extension + * - retro_game_info_ext::ext is guaranteed to contain the + * extension of the content file in lower case format + * - retro_game_info_ext::data and retro_game_info_ext::size + * are invalid + * + * If need_fullpath is false and retro_load_game() is called: + * - If retro_game_info_ext::file_in_archive is false: + * - retro_game_info_ext::full_path is guaranteed to contain + * a valid path to an existent file + * - retro_game_info_ext::archive_path may be NULL + * - retro_game_info_ext::archive_file may be NULL + * - retro_game_info_ext::dir is guaranteed to contain a + * valid path to the directory in which the content file exists + * - retro_game_info_ext::name is guaranteed to contain the + * basename of the content file, without extension + * - retro_game_info_ext::ext is guaranteed to contain the + * extension of the content file in lower case format + * - If retro_game_info_ext::file_in_archive is true: + * - retro_game_info_ext::full_path may be NULL + * - retro_game_info_ext::archive_path is guaranteed to + * contain a valid path to an existent compressed file + * inside which the content file is located + * - retro_game_info_ext::archive_file is guaranteed to + * contain a valid path to an existent content file + * inside the compressed file referred to by + * retro_game_info_ext::archive_path + * e.g. for a compressed file '/path/to/foo.zip' + * containing 'bar.sfc' + * > retro_game_info_ext::archive_path will be '/path/to/foo.zip' + * > retro_game_info_ext::archive_file will be 'bar.sfc' + * - retro_game_info_ext::dir is guaranteed to contain a + * valid path to the directory in which the compressed file + * (containing the content file) exists + * - retro_game_info_ext::name is guaranteed to contain + * EITHER + * 1) the basename of the compressed file (containing + * the content file), without extension + * OR + * 2) the basename of the content file inside the + * compressed file, without extension + * In either case, a core should consider 'name' to + * be the canonical name/ID of the the content file + * - retro_game_info_ext::ext is guaranteed to contain the + * extension of the content file inside the compressed file, + * in lower case format + * - retro_game_info_ext::data and retro_game_info_ext::size are + * guaranteed to be valid */ + bool need_fullpath; + + /* If need_fullpath is false, specifies whether the content + * data buffer available in retro_load_game() is 'persistent' + * + * If persistent_data is false and retro_load_game() is called: + * - retro_game_info::data and retro_game_info::size + * are valid only until retro_load_game() returns + * - retro_game_info_ext::data and retro_game_info_ext::size + * are valid only until retro_load_game() returns + * + * If persistent_data is true and retro_load_game() is called: + * - retro_game_info::data and retro_game_info::size + * are valid until retro_deinit() returns + * - retro_game_info_ext::data and retro_game_info_ext::size + * are valid until retro_deinit() returns */ + bool persistent_data; +}; + +/* Similar to retro_game_info, but provides extended + * information about the source content file and + * game memory buffer status. + * And array of retro_game_info_ext is returned by + * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT + * NOTE: In the following descriptions, references to + * retro_load_game() may be replaced with + * retro_load_game_special() */ +struct retro_game_info_ext +{ + /* - If file_in_archive is false, contains a valid + * path to an existent content file (UTF-8 encoded) + * - If file_in_archive is true, may be NULL */ + const char *full_path; + + /* - If file_in_archive is false, may be NULL + * - If file_in_archive is true, contains a valid path + * to an existent compressed file inside which the + * content file is located (UTF-8 encoded) */ + const char *archive_path; + + /* - If file_in_archive is false, may be NULL + * - If file_in_archive is true, contain a valid path + * to an existent content file inside the compressed + * file referred to by archive_path (UTF-8 encoded) + * e.g. for a compressed file '/path/to/foo.zip' + * containing 'bar.sfc' + * > archive_path will be '/path/to/foo.zip' + * > archive_file will be 'bar.sfc' */ + const char *archive_file; + + /* - If file_in_archive is false, contains a valid path + * to the directory in which the content file exists + * (UTF-8 encoded) + * - If file_in_archive is true, contains a valid path + * to the directory in which the compressed file + * (containing the content file) exists (UTF-8 encoded) */ + const char *dir; + + /* Contains the canonical name/ID of the content file + * (UTF-8 encoded). Intended for use when identifying + * 'complementary' content named after the loaded file - + * i.e. companion data of a different format (a CD image + * required by a ROM), texture packs, internally handled + * save files, etc. + * - If file_in_archive is false, contains the basename + * of the content file, without extension + * - If file_in_archive is true, then string is + * implementation specific. A frontend may choose to + * set a name value of: + * EITHER + * 1) the basename of the compressed file (containing + * the content file), without extension + * OR + * 2) the basename of the content file inside the + * compressed file, without extension + * RetroArch sets the 'name' value according to (1). + * A frontend that supports routine loading of + * content from archives containing multiple unrelated + * content files may set the 'name' value according + * to (2). */ + const char *name; + + /* - If file_in_archive is false, contains the extension + * of the content file in lower case format + * - If file_in_archive is true, contains the extension + * of the content file inside the compressed file, + * in lower case format */ + const char *ext; + + /* String of implementation specific meta-data. */ + const char *meta; + + /* Memory buffer of loaded game content. Will be NULL: + * IF + * - retro_system_info::need_fullpath is true and + * retro_system_content_info_override::need_fullpath + * is unset + * OR + * - retro_system_content_info_override::need_fullpath + * is true */ + const void *data; + + /* Size of game content memory buffer, in bytes */ + size_t size; + + /* True if loaded content file is inside a compressed + * archive */ + bool file_in_archive; + + /* - If data is NULL, value is unset/ignored + * - If data is non-NULL: + * - If persistent_data is false, data and size are + * valid only until retro_load_game() returns + * - If persistent_data is true, data and size are + * are valid until retro_deinit() returns */ + bool persistent_data; +}; + struct retro_game_geometry { unsigned base_width; /* Nominal video width of game. */ @@ -2892,6 +3474,143 @@ struct retro_core_options_intl struct retro_core_option_definition *local; }; +struct retro_core_option_v2_category +{ + /* Variable uniquely identifying the + * option category. Valid key characters + * are [a-z, A-Z, 0-9, _, -] */ + const char *key; + + /* Human-readable category description + * > Used as category menu label when + * frontend has core option category + * support */ + const char *desc; + + /* Human-readable category information + * > Used as category menu sublabel when + * frontend has core option category + * support + * > Optional (may be NULL or an empty + * string) */ + const char *info; +}; + +struct retro_core_option_v2_definition +{ + /* Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE. + * Valid key characters are [a-z, A-Z, 0-9, _, -] */ + const char *key; + + /* Human-readable core option description + * > Used as menu label when frontend does + * not have core option category support + * e.g. "Video > Aspect Ratio" */ + const char *desc; + + /* Human-readable core option description + * > Used as menu label when frontend has + * core option category support + * e.g. "Aspect Ratio", where associated + * retro_core_option_v2_category::desc + * is "Video" + * > If empty or NULL, the string specified by + * desc will be used as the menu label + * > Will be ignored (and may be set to NULL) + * if category_key is empty or NULL */ + const char *desc_categorized; + + /* Human-readable core option information + * > Used as menu sublabel */ + const char *info; + + /* Human-readable core option information + * > Used as menu sublabel when frontend + * has core option category support + * (e.g. may be required when info text + * references an option by name/desc, + * and the desc/desc_categorized text + * for that option differ) + * > If empty or NULL, the string specified by + * info will be used as the menu sublabel + * > Will be ignored (and may be set to NULL) + * if category_key is empty or NULL */ + const char *info_categorized; + + /* Variable specifying category (e.g. "video", + * "audio") that will be assigned to the option + * if frontend has core option category support. + * > Categorized options will be displayed in a + * subsection/submenu of the frontend core + * option interface + * > Specified string must match one of the + * retro_core_option_v2_category::key values + * in the associated retro_core_option_v2_category + * array; If no match is not found, specified + * string will be considered as NULL + * > If specified string is empty or NULL, option will + * have no category and will be shown at the top + * level of the frontend core option interface */ + const char *category_key; + + /* Array of retro_core_option_value structs, terminated by NULL */ + struct retro_core_option_value values[RETRO_NUM_CORE_OPTION_VALUES_MAX]; + + /* Default core option value. Must match one of the values + * in the retro_core_option_value array, otherwise will be + * ignored */ + const char *default_value; +}; + +struct retro_core_options_v2 +{ + /* Array of retro_core_option_v2_category structs, + * terminated by NULL + * > If NULL, all entries in definitions array + * will have no category and will be shown at + * the top level of the frontend core option + * interface + * > Will be ignored if frontend does not have + * core option category support */ + struct retro_core_option_v2_category *categories; + + /* Array of retro_core_option_v2_definition structs, + * terminated by NULL */ + struct retro_core_option_v2_definition *definitions; +}; + +struct retro_core_options_v2_intl +{ + /* Pointer to a retro_core_options_v2 struct + * > US English implementation + * > Must point to a valid struct */ + struct retro_core_options_v2 *us; + + /* Pointer to a retro_core_options_v2 struct + * - Implementation for current frontend language + * - May be NULL */ + struct retro_core_options_v2 *local; +}; + +/* Used by the frontend to monitor changes in core option + * visibility. May be called each time any core option + * value is set via the frontend. + * - On each invocation, the core must update the visibility + * of any dynamically hidden options using the + * RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY environment + * callback. + * - On the first invocation, returns 'true' if the visibility + * of any core option has changed since the last call of + * retro_load_game() or retro_load_game_special(). + * - On each subsequent invocation, returns 'true' if the + * visibility of any core option has changed since the last + * time the function was called. */ +typedef bool (RETRO_CALLCONV *retro_core_options_update_display_callback_t)(void); +struct retro_core_options_update_display_callback +{ + retro_core_options_update_display_callback_t callback; +}; + struct retro_game_info { const char *path; /* Path to game, UTF-8 encoded. @@ -2938,6 +3657,84 @@ 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; +}; + +/* During normal operation. Rate will be equal to the core's internal FPS. */ +#define RETRO_THROTTLE_NONE 0 + +/* While paused or stepping single frames. Rate will be 0. */ +#define RETRO_THROTTLE_FRAME_STEPPING 1 + +/* During fast forwarding. + * Rate will be 0 if not specifically limited to a maximum speed. */ +#define RETRO_THROTTLE_FAST_FORWARD 2 + +/* During slow motion. Rate will be less than the core's internal FPS. */ +#define RETRO_THROTTLE_SLOW_MOTION 3 + +/* While rewinding recorded save states. Rate can vary depending on the rewind + * speed or be 0 if the frontend is not aiming for a specific rate. */ +#define RETRO_THROTTLE_REWINDING 4 + +/* While vsync is active in the video driver and the target refresh rate is + * lower than the core's internal FPS. Rate is the target refresh rate. */ +#define RETRO_THROTTLE_VSYNC 5 + +/* When the frontend does not throttle in any way. Rate will be 0. + * An example could be if no vsync or audio output is active. */ +#define RETRO_THROTTLE_UNBLOCKED 6 + +struct retro_throttle_state +{ + /* The current throttling mode. Should be one of the values above. */ + unsigned mode; + + /* How many times per second the frontend aims to call retro_run. + * Depending on the mode, it can be 0 if there is no known fixed rate. + * This won't be accurate if the total processing time of the core and + * the frontend is longer than what is available for one frame. */ + float rate; +}; + /* Callbacks */ /* Environment callback. Gives implementations a way of performing diff --git a/src/drivers/libretro/libretro.c b/src/drivers/libretro/libretro.c index 2c2501b..2041d3c 100644 --- a/src/drivers/libretro/libretro.c +++ b/src/drivers/libretro/libretro.c @@ -141,6 +141,7 @@ enum RetroZapperInputModes{RetroLightgun, RetroMouse, RetroPointer}; static enum RetroZapperInputModes zappermode = RetroLightgun; static bool libretro_supports_bitmasks = false; +static bool libretro_supports_option_categories = false; /* emulator-specific variables */ @@ -162,8 +163,8 @@ unsigned dendy = 0; static unsigned systemRegion = 0; static unsigned opt_region = 0; -static unsigned opt_showAdvSoundOptions = 0; -static unsigned opt_showAdvSystemOptions = 0; +static bool opt_showAdvSoundOptions = true; +static bool opt_showAdvSystemOptions = true; #if defined(PSP) || defined(PS2) static __attribute__((aligned(16))) uint16_t retro_palette[256]; @@ -615,7 +616,7 @@ struct st_palettes palettes[] = { #define NES_NTSC_WIDTH (((NES_NTSC_OUT_WIDTH(256) + 3) >> 2) << 2) static unsigned use_ntsc = 0; -static unsigned burst_phase; +static unsigned burst_phase = 0; static nes_ntsc_t nes_ntsc; static nes_ntsc_setup_t ntsc_setup; static uint16_t *ntsc_video_out = NULL; /* for ntsc blit buffer */ @@ -625,6 +626,9 @@ static void NTSCFilter_Cleanup(void) if (ntsc_video_out) free(ntsc_video_out); ntsc_video_out = NULL; + + use_ntsc = 0; + burst_phase = 0; } static void NTSCFilter_Init(void) @@ -862,25 +866,163 @@ void retro_set_controller_port_device(unsigned port, unsigned device) } } +/* Core options 'update display' callback */ +static bool update_option_visibility(void) +{ + struct retro_variable var = {0}; + bool updated = false; + size_t i, size; + + /* If frontend supports core option categories, + * then fceumm_show_adv_system_options and + * fceumm_show_adv_sound_options are ignored + * and no options should be hidden */ + if (libretro_supports_option_categories) + return false; + + var.key = "fceumm_show_adv_system_options"; + var.value = NULL; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + bool opt_showAdvSystemOptions_prev = opt_showAdvSystemOptions; + + opt_showAdvSystemOptions = true; + if (strcmp(var.value, "disabled") == 0) + opt_showAdvSystemOptions = false; + + if (opt_showAdvSystemOptions != opt_showAdvSystemOptions_prev) + { + struct retro_core_option_display option_display; + unsigned i; + unsigned size; + char options_list[][25] = { + "fceumm_overclocking", + "fceumm_ramstate", + "fceumm_nospritelimit", + "fceumm_up_down_allowed", + "fceumm_show_crosshair" + }; + + option_display.visible = opt_showAdvSystemOptions; + size = sizeof(options_list) / sizeof(options_list[0]); + for (i = 0; i < size; i++) + { + option_display.key = options_list[i]; + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, + &option_display); + } + + updated = true; + } + } + + var.key = "fceumm_show_adv_sound_options"; + var.value = NULL; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + bool opt_showAdvSoundOptions_prev = opt_showAdvSoundOptions; + + opt_showAdvSoundOptions = true; + if (strcmp(var.value, "disabled") == 0) + opt_showAdvSoundOptions = false; + + if (opt_showAdvSoundOptions != opt_showAdvSoundOptions_prev) + { + struct retro_core_option_display option_display; + unsigned i; + unsigned size; + char options_list[][25] = { + "fceumm_sndvolume", + "fceumm_sndquality", + "fceumm_swapduty", + "fceumm_apu_1", + "fceumm_apu_2", + "fceumm_apu_3", + "fceumm_apu_4", + "fceumm_apu_5" + }; + + option_display.visible = opt_showAdvSoundOptions; + size = sizeof(options_list) / sizeof(options_list[0]); + for (i = 0; i < size; i++) + { + option_display.key = options_list[i]; + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, + &option_display); + } + + updated = true; + } + } + + return updated; +} + static void set_variables(void) { + struct retro_core_option_display option_display; unsigned i = 0, index = 0; + option_display.visible = false; + /* Initialize main core option struct */ - for (i = 0; i < MAX_CORE_OPTIONS; i++) - option_defs_us[i] = option_defs_empty; + memset(&option_defs_us, 0, sizeof(option_defs_us)); /* Write common core options to main struct */ - while (option_defs_common[index].key) { - option_defs_us[index] = option_defs_common[index]; + while (option_defs_us_common[index].key) { + memcpy(&option_defs_us[index], &option_defs_us_common[index], + sizeof(struct retro_core_option_v2_definition)); index++; } /* Append dipswitch settings to core options if available */ - index += set_dipswitch_variables(index, option_defs_us); - option_defs_us[index] = option_defs_empty; + set_dipswitch_variables(index, option_defs_us); - libretro_set_core_options(environ_cb); + libretro_supports_option_categories = false; + libretro_set_core_options(environ_cb, + &libretro_supports_option_categories); + + /* If frontend supports core option categories, + * fceumm_show_adv_system_options and + * fceumm_show_adv_sound_options are unused + * and should be hidden */ + if (libretro_supports_option_categories) + { + option_display.key = "fceumm_show_adv_system_options"; + + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, + &option_display); + + option_display.key = "fceumm_show_adv_sound_options"; + + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, + &option_display); + } + /* If frontend does not support core option + * categories, core options may be shown/hidden + * at runtime. In this case, register 'update + * display' callback, so frontend can update + * core options menu without calling retro_run() */ + else + { + struct retro_core_options_update_display_callback update_display_cb; + update_display_cb.callback = update_option_visibility; + + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK, + &update_display_cb); + } + + /* VS UNISystem games use internal palette regardless + * of user setting, so hide fceumm_palette option */ + if (GameInfo && (GameInfo->type == GIT_VSUNI)) + { + option_display.key = "fceumm_palette"; + + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, + &option_display); + } } void retro_set_environment(retro_environment_t cb) @@ -1461,68 +1603,7 @@ static void check_variables(bool startup) update_dipswitch(); - var.key = "fceumm_show_adv_system_options"; - var.value = NULL; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - unsigned newval = (!strcmp(var.value, "enabled")) ? 1 : 0; - if ((opt_showAdvSystemOptions != newval) || startup) - { - struct retro_core_option_display option_display; - unsigned i; - unsigned size; - char options_list[][25] = { - "fceumm_overclocking", - "fceumm_ramstate", - "fceumm_nospritelimit", - "fceumm_up_down_allowed", - "fceumm_show_crosshair" - }; - - opt_showAdvSystemOptions = newval; - option_display.visible = opt_showAdvSystemOptions; - size = sizeof(options_list) / sizeof(options_list[0]); - for (i = 0; i < size; i++) - { - option_display.key = options_list[i]; - environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display); - } - } - } - - var.key = "fceumm_show_adv_sound_options"; - var.value = NULL; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - unsigned newval = (!strcmp(var.value, "enabled")) ? 1 : 0; - if ((opt_showAdvSoundOptions != newval) || startup) - { - struct retro_core_option_display option_display; - unsigned i; - unsigned size; - char options_list[][25] = { - "fceumm_sndvolume", - "fceumm_sndquality", - "fceumm_swapduty", - "fceumm_apu_1", - "fceumm_apu_2", - "fceumm_apu_3", - "fceumm_apu_4", - "fceumm_apu_5" - }; - - opt_showAdvSoundOptions = newval; - option_display.visible = opt_showAdvSoundOptions; - size = sizeof(options_list) / sizeof(options_list[0]); - for (i = 0; i < size; i++) - { - option_display.key = options_list[i]; - environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display); - } - } - } + update_option_visibility(); } static int mzx = 0, mzy = 0; @@ -1838,12 +1919,12 @@ static void retro_run_blit(uint8_t *gfx) if (!ps2) { if (!environ_cb(RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE, (void **)&ps2) || !ps2) { - printf("Failed to get HW rendering interface!\n"); + FCEU_printf(" Failed to get HW rendering interface!\n"); return; } if (ps2->interface_version != RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION) { - printf("HW render interface mismatch, expected %u, got %u!\n", + FCEU_printf(" HW render interface mismatch, expected %u, got %u!\n", RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION, ps2->interface_version); return; } diff --git a/src/drivers/libretro/libretro_core_options.h b/src/drivers/libretro/libretro_core_options.h index e3deb8e..0df0a88 100644 --- a/src/drivers/libretro/libretro_core_options.h +++ b/src/drivers/libretro/libretro_core_options.h @@ -17,6 +17,8 @@ extern "C" { ******************************** */ +#define MAX_CORE_OPTIONS 34 + /* RETRO_LANGUAGE_ENGLISH */ /* Default language: @@ -26,13 +28,47 @@ extern "C" { * - Will be used as a fallback for any missing entries in * frontend language definition */ -#define MAX_CORE_OPTIONS 32 +struct retro_core_option_v2_category option_cats_us[] = { + { + "video", + "Video", +#ifdef HAVE_NTSC_FILTER + "Configure aspect ratio / display cropping / color palette / video filter options." +#else + "Configure aspect ratio / display cropping / color palette options." +#endif + }, + { + "audio", + "Audio", + "Configure sound quality / volume / channel enable settings." + }, + { + "input", + "Input", + "Configure turbo / light gun parameters." + }, + { + "hacks", + "Emulation Hacks", + "Configure processor overclocking and emulation accuracy parameters affecting low-level performance and compatibility." + }, + { + "dip_switch", + "DIP Switches", + "Configure arcade game settings." + }, + { NULL, NULL, NULL }, +}; -struct retro_core_option_definition option_defs_common[] = { +struct retro_core_option_v2_definition option_defs_us_common[] = { { "fceumm_region", "Region", + NULL, "Force core to use NTSC, PAL or Dendy region timings.", + NULL, + NULL, { { "Auto", NULL }, { "NTSC", NULL }, @@ -43,101 +79,56 @@ struct retro_core_option_definition option_defs_common[] = { "Auto", }, { - "fceumm_overclocking", - "Overclock", - "Enables or disables overclocking which can reduce slowdowns in some games. Postrender method is more compatible with every game with Vblank more effective for games like Contra Force.", - { - { "disabled", NULL }, - { "2x-Postrender", NULL }, - { "2x-VBlank", NULL }, - { NULL, NULL}, - }, - "disabled", - }, - { - "fceumm_ramstate", - "RAM Power-On Fill (Needs Restart)", - "Choose RAM startup during power up. Some games rely on initial ram values for random generator as an example.", - { - { "fill $ff", "$FF" }, - { "fill $00", "$00" }, - { "random", "random" }, - { NULL, NULL}, - }, - "fill $ff", - }, - { - "fceumm_nospritelimit", - "No Sprite Limit", - "Removes the 8-per-scanline hardware limit. This reduces sprite flickering but can cause some games to glitch since some use this for effects.", + "fceumm_show_adv_system_options", + "Show Advanced System Options", + NULL, + "Show advanced system options and tweaks.", + NULL, + NULL, { { "disabled", NULL }, { "enabled", NULL }, - { NULL, NULL}, - }, - "disabled", - }, -#ifdef HAVE_NTSC_FILTER - { - "fceumm_ntsc_filter", - "NTSC Filter", - "Enable blargg NTSC filters.", - { - { "disabled", NULL }, - { "composite", NULL }, - { "svideo", NULL }, - { "rgb", NULL }, - { "monochrome", NULL }, { NULL, NULL }, }, "disabled" }, -#endif { - "fceumm_palette", - "Color Palette", - "Choose from pre-generated palettes, a custom 64x3 palette from file or raw format (needs to use a nes-decoder shader).", + "fceumm_show_adv_sound_options", + "Show Advanced Sound Options", + NULL, + "Show advanced sound options and tweaks.", + NULL, + NULL, { - { "default", NULL }, - { "asqrealc", NULL }, - { "nintendo-vc", NULL }, - { "rgb", NULL }, - { "yuv-v3", NULL }, - { "unsaturated-final", NULL }, - { "sony-cxa2025as-us", NULL }, - { "pal", NULL }, - { "bmf-final2", NULL }, - { "bmf-final3", NULL }, - { "smooth-fbx", NULL }, - { "composite-direct-fbx", NULL }, - { "pvm-style-d93-fbx", NULL }, - { "ntsc-hardware-fbx", NULL }, - { "nes-classic-fbx-fs", NULL }, - { "nescap", NULL }, - { "wavebeam", NULL }, - { "raw", NULL }, - { "custom", NULL }, - { NULL, NULL}, + { "disabled", NULL }, + { "enabled", NULL }, + { NULL, NULL }, }, - "default", + "disabled" }, { "fceumm_aspect", "Aspect Ratio", + NULL, "Choose preferred aspect ratio.", + NULL, + "video", { { "8:7 PAR", NULL }, { "4:3", NULL }, - { "PP", NULL }, + { "PP", "Pixel Perfect" }, { NULL, NULL}, }, "8:7 PAR", }, -#ifdef PSP +#ifdef PSP /* overscan options */ { "fceumm_overscan", "Crop Overscan", - "Removes 8 pixel overscan from all sides", + NULL, + "Removes 8 pixel overscan from all sides of the screen.", + NULL, + "video", { { "enabled", NULL }, { "disabled", NULL }, @@ -149,7 +140,10 @@ struct retro_core_option_definition option_defs_common[] = { { "fceumm_overscan_h", "Crop Horizontal Overscan", - "Removes 8 pixel from left and right side of the screen to simulate overscan seen on standard CRT television.", + NULL, + "Removes 8 pixels from left and right sides of the screen to simulate overscan seen on standard CRT televisions.", + NULL, + "video", { { "disabled", NULL }, { "enabled", NULL }, @@ -157,10 +151,13 @@ struct retro_core_option_definition option_defs_common[] = { }, "disabled", }, - { + { "fceumm_overscan_v", "Crop Vertical Overscan", - "Removes 8 pixel from the top and bottom of the screen to simulate overscan seen on standard CRT television.", + NULL, + "Removes 8 pixels from the top and bottom of the screen to simulate overscan seen on standard CRT televisions.", + NULL, + "video", { { "disabled", NULL }, { "enabled", NULL }, @@ -170,9 +167,77 @@ struct retro_core_option_definition option_defs_common[] = { }, #endif /* overscan options */ { - "fceumm_up_down_allowed", - "Allow Opposing Directions", - "Allows simultaneous UP+DOWN or LEFT+RIGHT button combinations which can create different effects in some games.", + "fceumm_palette", + "Color Palette", + NULL, + "Choose from pre-generated palettes, a custom 64x3 palette from file or raw format (needs to use a nes-decoder shader).", + NULL, + "video", + { + { "default", "Default" }, + { "asqrealc", "AspiringSquire's Real" }, + { "nintendo-vc", "Nintendo Virtual Console" }, + { "rgb", "Nintendo RGB PPU" }, + { "yuv-v3", "FBX's YUV-V3" }, + { "unsaturated-final", "FBX's Unsaturated-Final" }, + { "sony-cxa2025as-us", "Sony CXA2025AS US" }, + { "pal", "PAL" }, + { "bmf-final2", "BMF's Final 2" }, + { "bmf-final3", "BMF's Final 3" }, + { "smooth-fbx", "FBX's Smooth" }, + { "composite-direct-fbx", "FBX's Composite Direct" }, + { "pvm-style-d93-fbx", "FBX's PVM Style D93" }, + { "ntsc-hardware-fbx", "FBX's NTSC Hardware" }, + { "nes-classic-fbx-fs", "FBX's NES-Classic FS" }, + { "nescap", "RGBSource's NESCAP" }, + { "wavebeam", "nakedarthur's Wavebeam" }, + { "raw", "Raw" }, + { "custom", "Custom" }, + { NULL, NULL}, + }, + "default", + }, +#ifdef HAVE_NTSC_FILTER + { + "fceumm_ntsc_filter", + "NTSC Filter", + NULL, + "Enable blargg NTSC filters.", + NULL, + "video", + { + { "disabled", NULL }, + { "composite", "Composite" }, + { "svideo", "S-Video" }, + { "rgb", "RGB" }, + { "monochrome", "Monochrome" }, + { NULL, NULL }, + }, + "disabled" + }, +#endif + { + "fceumm_sndquality", + "Sound Quality", + NULL, + "Enable higher quality sound. Increases performance requirements.", + NULL, + "audio", + { + { "Low", NULL }, + { "High", NULL }, + { "Very High", NULL }, + { NULL, NULL}, + }, + "Low", + }, + { + "fceumm_swapduty", + "Swap Audio Duty Cycles", + "Swap Duty Cycles", + "Simulates the sound from famiclones that have the pulse wave channels duty cycle bits reversed.", + NULL, + "audio", { { "disabled", NULL }, { "enabled", NULL }, @@ -180,10 +245,106 @@ struct retro_core_option_definition option_defs_common[] = { }, "disabled", }, + { + "fceumm_sndvolume", + "Master Volume", + NULL, + "Change master volume level.", + NULL, + "audio", + { + { "0", "0%" }, + { "1", "10%" }, + { "2", "20%" }, + { "3", "30%" }, + { "4", "40%" }, + { "5", "50%" }, + { "6", "60%" }, + { "7", "70%" }, + { "8", "80%" }, + { "9", "90%" }, + { "10", "100%" }, + { NULL, NULL}, + }, + "7", + }, + { + "fceumm_apu_1", + "Audio Channel 1 (Square 1)", + "Channel 1 (Square 1)", + "Enables or disables pulse wave generator audio output 1.", + NULL, + "audio", + { + { "enabled", NULL }, + { "disabled", NULL }, + { NULL, NULL}, + }, + "enabled", + }, + { + "fceumm_apu_2", + "Audio Channel 2 (Square 2)", + "Channel 2 (Square 2)", + "Enables or disables pulse wave generator audio output 2.", + NULL, + "audio", + { + { "enabled", NULL }, + { "disabled", NULL }, + { NULL, NULL}, + }, + "enabled", + }, + { + "fceumm_apu_3", + "Audio Channel 3 (Triangle)", + "Channel 3 (Triangle)", + "Enables or disables triangle wave generator audio output.", + NULL, + "audio", + { + { "enabled", NULL }, + { "disabled", NULL }, + { NULL, NULL}, + }, + "enabled", + }, + { + "fceumm_apu_4", + "Audio Channel 4 (Noise)", + "Channel 4 (Noise)", + "Enables or disables noise generator audio output.", + NULL, + "audio", + { + { "enabled", NULL }, + { "disabled", NULL }, + { NULL, NULL}, + }, + "enabled", + }, + { + "fceumm_apu_5", + "Audio Channel 5 (PCM)", + "Channel 5 (PCM)", + "Enables or disables delta modulation channel audio output.", + NULL, + "audio", + { + { "enabled", NULL }, + { "disabled", NULL }, + { NULL, NULL}, + }, + "enabled", + }, { "fceumm_turbo_enable", "Turbo Enable", + NULL, "Enables or disables turbo buttons.", + NULL, + "input", { { "None", NULL }, { "Player 1", NULL }, @@ -196,7 +357,10 @@ struct retro_core_option_definition option_defs_common[] = { { "fceumm_turbo_delay", "Turbo Delay (in frames)", + NULL, "Repeat rate of turbo buttons in frames.", + NULL, + "input", { { "1", NULL }, { "2", NULL }, @@ -213,19 +377,25 @@ struct retro_core_option_definition option_defs_common[] = { { "fceumm_zapper_mode", "Zapper Mode", + NULL, "Selects device to use for zapper games.", + NULL, + "input", { - { "lightgun", NULL }, - { "touchscreen", NULL }, - { "mouse", NULL }, + { "lightgun", "Lightgun" }, + { "touchscreen", "Touchscreen" }, + { "mouse", "Mouse" }, { NULL, NULL}, }, "lightgun", }, { "fceumm_show_crosshair", - "Show Crosshair", + "Show Zapper Crosshair", + NULL, "Shows or hides on-screen crosshairs when using a zapper.", + NULL, + "input", { { "enabled", NULL }, { "disabled", NULL }, @@ -236,7 +406,10 @@ struct retro_core_option_definition option_defs_common[] = { { "fceumm_zapper_tolerance", "Zapper Tolerance", + NULL, "Sets how many pixels from target area is on target.", + NULL, + "input", { { "0", NULL }, { "1", NULL }, @@ -264,21 +437,12 @@ struct retro_core_option_definition option_defs_common[] = { "6", }, { - "fceumm_sndquality", - "Sound Quality", - "Enable higher quality sounds in exchange for more processing power required", - { - { "Low", NULL }, - { "High", NULL }, - { "Very High", NULL }, - { NULL, NULL}, - }, - "Low", - }, - { - "fceumm_swapduty", - "Swap Duty Cycles", - "Simulates the sound from famiclones has the pulse wave channels duty cycle bits reversed.", + "fceumm_up_down_allowed", + "Allow Opposing Directions", + NULL, + "Allows simultaneous UP+DOWN or LEFT+RIGHT button combinations which can create different effects in some games.", + NULL, + "input", { { "disabled", NULL }, { "enabled", NULL }, @@ -287,156 +451,68 @@ struct retro_core_option_definition option_defs_common[] = { "disabled", }, { - "fceumm_sndvolume", - "Master Volume", - "Change master volume level", + "fceumm_nospritelimit", + "No Sprite Limit", + NULL, + "Removes the 8-per-scanline hardware limit. This reduces sprite flickering but can cause some games to glitch since some use this for effects.", + NULL, + "hacks", { - { "0", NULL }, - { "1", NULL }, - { "2", NULL }, - { "3", NULL }, - { "4", NULL }, - { "5", NULL }, - { "6", NULL }, - { "7", NULL }, - { "8", NULL }, - { "9", NULL }, - { "10", NULL }, + { "disabled", NULL }, + { "enabled", NULL }, { NULL, NULL}, }, - "7", + "disabled", }, { - "fceumm_apu_1", - "Channel 1 (Square 1)", - "Enables or disables pulse wave generator audio output 1.", + "fceumm_overclocking", + "Overclock", + NULL, + "Enables or disables overclocking which can reduce slowdowns in some games. Postrender method is more compatible with every game with Vblank more effective for games like Contra Force.", + NULL, + "hacks", { - { "enabled", NULL }, - { "disabled", NULL }, + { "disabled", NULL }, + { "2x-Postrender", NULL }, + { "2x-VBlank", NULL }, { NULL, NULL}, }, - "enabled", + "disabled", }, { - "fceumm_apu_2", - "Channel 2 (Square 2)", - "Enables or disables pulse wave generator audio output 2.", + "fceumm_ramstate", + "RAM Power-On Fill (Restart)", + NULL, + "Choose RAM startup during power up. Some games rely on initial ram values for random generator as an example.", + NULL, + "hacks", { - { "enabled", NULL }, - { "disabled", NULL }, + { "fill $ff", "$FF" }, + { "fill $00", "$00" }, + { "random", "Random" }, { NULL, NULL}, }, - "enabled", + "fill $ff", }, - { - "fceumm_apu_3", - "Channel 3 (Triangle)", - "Enables or disables triangle wave generator audio output.", - { - { "enabled", NULL }, - { "disabled", NULL }, - { NULL, NULL}, - }, - "enabled", - }, - { - "fceumm_apu_4", - "Channel 4 (Noise)", - "Enables or disables noise generator audio output.", - { - { "enabled", NULL }, - { "disabled", NULL }, - { NULL, NULL}, - }, - "enabled", - }, - { - "fceumm_apu_5", - "Channel 5 (PCM)", - "Enables or disables delta modulation channel audio output.", - { - { "enabled", NULL }, - { "disabled", NULL }, - { NULL, NULL}, - }, - "enabled", - }, - { - "fceumm_show_adv_system_options", - "Show Advanced System Options", - "Show advanced system options and tweaks.", - { - { "disabled", NULL }, - { "enabled", NULL }, - { NULL, NULL }, - }, - "disabled" - }, - { - "fceumm_show_adv_sound_options", - "Show Advanced Sound Options", - "Show advanced sound options and tweaks.", - { - { "disabled", NULL }, - { "enabled", NULL }, - { NULL, NULL }, - }, - "disabled" - }, - - { NULL, NULL, NULL, { {0} }, NULL }, + { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL }, }; -struct retro_core_option_definition option_defs_empty = { - NULL, NULL, NULL, { {0} }, NULL +struct retro_core_option_v2_definition option_defs_us[MAX_CORE_OPTIONS]; + +struct retro_core_options_v2 options_us = { + option_cats_us, + option_defs_us }; -struct retro_core_option_definition option_defs_us[MAX_CORE_OPTIONS]; - -/* 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 */ - /* ******************************** * Language Mapping ******************************** */ -struct retro_core_option_definition *option_defs_intl[RETRO_LANGUAGE_LAST] = { - option_defs_us, /* RETRO_LANGUAGE_ENGLISH */ +#ifndef HAVE_NO_LANGEXTRA +struct retro_core_options_v2 *options_intl[RETRO_LANGUAGE_LAST] = { + &options_us, /* RETRO_LANGUAGE_ENGLISH */ NULL, /* RETRO_LANGUAGE_JAPANESE */ NULL, /* RETRO_LANGUAGE_FRENCH */ NULL, /* RETRO_LANGUAGE_SPANISH */ @@ -456,6 +532,7 @@ struct retro_core_option_definition *option_defs_intl[RETRO_LANGUAGE_LAST] = { NULL, /* RETRO_LANGUAGE_GREEK */ NULL, /* RETRO_LANGUAGE_TURKISH */ }; +#endif /* ******************************** @@ -470,41 +547,61 @@ struct retro_core_option_definition *option_defs_intl[RETRO_LANGUAGE_LAST] = { * be as painless as possible for core devs) */ -static INLINE void libretro_set_core_options(retro_environment_t environ_cb) +static INLINE void libretro_set_core_options(retro_environment_t environ_cb, + bool *categories_supported) { - unsigned version = 0; + unsigned version = 0; +#ifndef HAVE_NO_LANGEXTRA + unsigned language = 0; +#endif - if (!environ_cb) + if (!environ_cb || !categories_supported) return; - if (environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version) && (version >= 1)) - { - struct retro_core_options_intl core_options_intl; - unsigned language = 0; + *categories_supported = false; - core_options_intl.us = option_defs_us; + if (!environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version)) + version = 0; + + if (version >= 2) + { +#ifndef HAVE_NO_LANGEXTRA + struct retro_core_options_v2_intl core_options_intl; + + core_options_intl.us = &options_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]; + core_options_intl.local = options_intl[language]; - environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_intl); + *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL, + &core_options_intl); +#else + *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2, + &options_us); +#endif } else { - size_t i; + size_t i, j; size_t option_index = 0; size_t num_options = 0; + struct retro_core_option_definition + *option_v1_defs_us = NULL; +#ifndef HAVE_NO_LANGEXTRA + size_t num_options_intl = 0; + struct retro_core_option_v2_definition + *option_defs_intl = NULL; + struct retro_core_option_definition + *option_v1_defs_intl = NULL; + struct retro_core_options_intl + core_options_v1_intl; +#endif 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' */ + /* Determine total number of options */ while (true) { if (option_defs_us[num_options].key) @@ -513,92 +610,193 @@ static INLINE void libretro_set_core_options(retro_environment_t environ_cb) 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++) + if (version >= 1) { - 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; + /* Allocate US array */ + option_v1_defs_us = (struct retro_core_option_definition *) + calloc(num_options + 1, sizeof(struct retro_core_option_definition)); - values_buf[i] = NULL; - - /* Skip options that are irrelevant when using the - * old style core options interface */ - if ((strcmp(key, "fceumm_advance_sound_options") == 0)) - continue; - - if (desc) + /* Copy parameters from option_defs_us array */ + for (i = 0; i < num_options; i++) { - size_t num_values = 0; + struct retro_core_option_v2_definition *option_def_us = &option_defs_us[i]; + struct retro_core_option_value *option_values = option_def_us->values; + struct retro_core_option_definition *option_v1_def_us = &option_v1_defs_us[i]; + struct retro_core_option_value *option_v1_values = option_v1_def_us->values; - /* Determine number of values */ + option_v1_def_us->key = option_def_us->key; + option_v1_def_us->desc = option_def_us->desc; + option_v1_def_us->info = option_def_us->info; + option_v1_def_us->default_value = option_def_us->default_value; + + /* Values must be copied individually... */ + while (option_values->value) + { + option_v1_values->value = option_values->value; + option_v1_values->label = option_values->label; + + option_values++; + option_v1_values++; + } + } + +#ifndef HAVE_NO_LANGEXTRA + if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) && + (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH) && + options_intl[language]) + option_defs_intl = options_intl[language]->definitions; + + if (option_defs_intl) + { + /* Determine number of intl options */ 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++; - } + if (option_defs_intl[num_options_intl].key) + num_options_intl++; else break; } - /* Build values string */ - if (num_values > 1) + /* Allocate intl array */ + option_v1_defs_intl = (struct retro_core_option_definition *) + calloc(num_options_intl + 1, sizeof(struct retro_core_option_definition)); + + /* Copy parameters from option_defs_intl array */ + for (i = 0; i < num_options_intl; i++) { - size_t j; + struct retro_core_option_v2_definition *option_def_intl = &option_defs_intl[i]; + struct retro_core_option_value *option_values = option_def_intl->values; + struct retro_core_option_definition *option_v1_def_intl = &option_v1_defs_intl[i]; + struct retro_core_option_value *option_v1_values = option_v1_def_intl->values; - buf_len += num_values - 1; - buf_len += strlen(desc); + option_v1_def_intl->key = option_def_intl->key; + option_v1_def_intl->desc = option_def_intl->desc; + option_v1_def_intl->info = option_def_intl->info; + option_v1_def_intl->default_value = option_def_intl->default_value; - 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++) + /* Values must be copied individually... */ + while (option_values->value) { - if (j != default_index) - { - strcat(values_buf[i], "|"); - strcat(values_buf[i], values[j].value); - } + option_v1_values->value = option_values->value; + option_v1_values->label = option_values->label; + + option_values++; + option_v1_values++; } } } - variables[option_index].key = key; - variables[option_index].value = values_buf[i]; - option_index++; + core_options_v1_intl.us = option_v1_defs_us; + core_options_v1_intl.local = option_v1_defs_intl; + + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_v1_intl); +#else + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, option_v1_defs_us); +#endif + } + else + { + /* 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, "fceumm_show_adv_system_options") == 0) || + (strcmp(key, "fceumm_advance_sound_options") == 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) + { + 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); } - /* Set variables */ - environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables); - error: - /* Clean up */ + + if (option_v1_defs_us) + { + free(option_v1_defs_us); + option_v1_defs_us = NULL; + } + +#ifndef HAVE_NO_LANGEXTRA + if (option_v1_defs_intl) + { + free(option_v1_defs_intl); + option_v1_defs_intl = NULL; + } +#endif + if (values_buf) { for (i = 0; i < num_options; i++) diff --git a/src/drivers/libretro/libretro_core_options_intl.h b/src/drivers/libretro/libretro_core_options_intl.h new file mode 100644 index 0000000..038553a --- /dev/null +++ b/src/drivers/libretro/libretro_core_options_intl.h @@ -0,0 +1,91 @@ +#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: 2.0 + ******************************** + * + * - 2.0: Add support for core options v2 interface + * - 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 diff --git a/src/drivers/libretro/libretro_dipswitch.c b/src/drivers/libretro/libretro_dipswitch.c index e31116c..accdb96 100644 --- a/src/drivers/libretro/libretro_dipswitch.c +++ b/src/drivers/libretro/libretro_dipswitch.c @@ -1069,11 +1069,7 @@ enum { DPSW_NWC, }; -static struct retro_core_option_definition option_defs_empty = { - NULL, NULL, NULL, { {0} }, NULL -}; - -static struct retro_core_option_definition vscoreopt[MAX_CORE_OPTIONS]; +static struct retro_core_option_v2_definition vscoreopt[MAX_CORE_OPTIONS]; static VSUNIGAME *vsgame = NULL; static char *core_key[MAX_CORE_OPTIONS]; @@ -1098,7 +1094,7 @@ static const char *str_to_corekey(char *s) return str; } -static void make_core_options(struct retro_core_option_definition *vs_core_options) +static void make_core_options(struct retro_core_option_v2_definition *vs_core_options) { unsigned i, j; @@ -1109,6 +1105,9 @@ static void make_core_options(struct retro_core_option_definition *vs_core_optio const char *option_name = vsgame->core_options[i].option_name; char key[100] = {0}; + memset(&vs_core_options[i], 0, + sizeof(struct retro_core_option_v2_definition)); + /* Set core key and sanitize string */ sprintf(key, "fceumm_dipswitch_%s-%s", game_name, option_name); core_key[i] = calloc(strlen(key) + 1, sizeof(char)); @@ -1118,8 +1117,8 @@ static void make_core_options(struct retro_core_option_definition *vs_core_optio /* Set desc */ vs_core_options[i].desc = option_name; - /* Set info */ - vs_core_options[i].info = NULL; + /* Set category_key */ + vs_core_options[i].category_key = "dip_switch"; /* Set core values */ for (j = 0; j < numValues[i]; j++) { @@ -1127,8 +1126,6 @@ static void make_core_options(struct retro_core_option_definition *vs_core_optio vs_core_options[i].values[j].value = var_value; } - vs_core_options[i].values[j] = vars_empty; - /* Set default value. Top entry used as default */ vs_core_options[i].default_value = vsgame->core_options[i].settings[0].name; } @@ -1241,11 +1238,14 @@ static void update_dipswitch_vsuni(void) } /* Nintendo World Championships 1990 */ -static struct retro_core_option_definition dipswitch_nwc[] = { +static struct retro_core_option_v2_definition dipswitch_nwc[] = { { "fceumm_dipswitch_nwc", "Gameplay Duration in minutes (Restart)", + NULL, "Sets the game timer in minutes.", + NULL, + "dip_switch", { { "0", "5:00" }, { "1", "5:19" }, @@ -1263,12 +1263,11 @@ static struct retro_core_option_definition dipswitch_nwc[] = { { "13", "9:04" }, { "14", "9:23" }, { "15", "9:42" }, - { NULL, NULL}, + { NULL, NULL }, }, "4", }, - - { NULL, NULL, NULL, { {0} }, NULL }, + { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL }, }; static void update_dipswitch_nwc(void) @@ -1292,7 +1291,7 @@ static void update_dipswitch_nwc(void) } } -size_t set_dipswitch_variables(unsigned current_index, struct retro_core_option_definition *vars) +void set_dipswitch_variables(unsigned current_index, struct retro_core_option_v2_definition *vars) { unsigned index = current_index; int dipsw_size = 0; @@ -1310,8 +1309,7 @@ size_t set_dipswitch_variables(unsigned current_index, struct retro_core_option_ dipswitch_type = DPSW_VSUNI; /* Initialize dipswitch struct with empty values */ - for (i = 0; i < MAX_CORE_OPTIONS; i++) - vscoreopt[i] = option_defs_empty; + memset(&vscoreopt, 0, sizeof(vscoreopt)); /* Count number of core options and the number of values for each */ for (i = 0; i < MAX_CORE_OPTIONS; i++) { @@ -1328,12 +1326,13 @@ size_t set_dipswitch_variables(unsigned current_index, struct retro_core_option_ /* Append dipswitch struct to main core options struct */ while (vscoreopt[dipsw_size].key) { - vars[index] = vscoreopt[dipsw_size]; + memcpy(&vars[index], &vscoreopt[dipsw_size], + sizeof(struct retro_core_option_v2_definition)); index++; dipsw_size++; } } - return (dipsw_size); + return; } /* Nintendo World Championship cart (Mapper 105)*/ @@ -1342,15 +1341,16 @@ size_t set_dipswitch_variables(unsigned current_index, struct retro_core_option_ dipswitch_type = DPSW_NWC; while (dipswitch_nwc[dipsw_size].key) { - vars[index] = dipswitch_nwc[dipsw_size]; + memcpy(&vars[index], &dipswitch_nwc[dipsw_size], + sizeof(struct retro_core_option_v2_definition)); index++; dipsw_size++; } - return (dipsw_size); + return; } dipswitch_type = DPSW_NONE; - return (0); + return; } void update_dipswitch(void) diff --git a/src/drivers/libretro/libretro_dipswitch.h b/src/drivers/libretro/libretro_dipswitch.h index bf6ace7..a0ef579 100644 --- a/src/drivers/libretro/libretro_dipswitch.h +++ b/src/drivers/libretro/libretro_dipswitch.h @@ -3,7 +3,7 @@ #include -size_t set_dipswitch_variables(unsigned current_index, struct retro_core_option_definition *vars); +void set_dipswitch_variables(unsigned current_index, struct retro_core_option_v2_definition *vars); void update_dipswitch(void); void DPSW_Cleanup(void); diff --git a/src/ntsc/nes_ntsc_config.h b/src/ntsc/nes_ntsc_config.h index 1a89293..56876d6 100644 --- a/src/ntsc/nes_ntsc_config.h +++ b/src/ntsc/nes_ntsc_config.h @@ -19,7 +19,7 @@ if you enable emphasis above. */ /* Each raw pixel input value is passed through this. You might want to mask the pixel index if you use the high bits as flags, etc. */ -#define NES_NTSC_ADJ_IN( in, deemp ) ( in & 0x3F ) | ( deemp << 6 ) +#define NES_NTSC_ADJ_IN( in, deemp ) (( in & 0x3F ) | ((deemp & 0x7) << 6)) /* For each pixel, this is the basic operation: output_color = color_palette [NES_NTSC_ADJ_IN( NES_NTSC_IN_T )] */