#ifndef LIBRETRO_CORE_OPTIONS_H__ #define LIBRETRO_CORE_OPTIONS_H__ #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* ******************************** * Core Option Definitions ******************************** */ #define MAX_CORE_OPTIONS 35 /* RETRO_LANGUAGE_ENGLISH */ /* Default language: * - All other languages must include the same keys and values * - Will be used as a fallback in the event that frontend language * is not available * - Will be used as a fallback for any missing entries in * frontend language definition */ struct retro_core_option_v2_category option_cats_us[] = { { "system", "System", "Configure region / hardware add-on parameters." }, { "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_v2_definition option_defs_us_common[] = { { "fceumm_region", "Region", NULL, "Force core to use NTSC, PAL or Dendy region timings.", NULL, "system", { { "Auto", NULL }, { "NTSC", NULL }, { "PAL", NULL }, { "Dendy", NULL }, { NULL, NULL }, }, "Auto", }, { "fceumm_game_genie", "Game Genie Add-On (Restart)", NULL, "Enable emulation of a Game Genie add-on cartridge, allowing cheat codes to be entered when launching games. The Game Genie ROM file 'gamegenie.nes' must be present in the frontend's system directory. Does not apply to FDS or arcade content.", NULL, "system", { { "disabled", NULL }, { "enabled", NULL }, { NULL, NULL }, }, "disabled", }, { "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" }, { "fceumm_show_adv_sound_options", "Show Advanced Sound Options", NULL, "Show advanced sound options and tweaks.", NULL, NULL, { { "disabled", NULL }, { "enabled", NULL }, { NULL, NULL }, }, "disabled" }, { "fceumm_aspect", "Aspect Ratio", NULL, "Choose preferred aspect ratio.", NULL, "video", { { "8:7 PAR", NULL }, { "4:3", NULL }, { "PP", "Pixel Perfect" }, { NULL, NULL }, }, "8:7 PAR", }, #ifdef PSP /* overscan options */ { "fceumm_overscan", "Crop Overscan", NULL, "Removes 8 pixel overscan from all sides of the screen.", NULL, "video", { { "enabled", NULL }, { "disabled", NULL }, { NULL, NULL }, }, "enabled", }, #else { "fceumm_overscan_h", "Crop Horizontal Overscan", 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 }, { NULL, NULL }, }, "disabled", }, { "fceumm_overscan_v", "Crop Vertical Overscan", 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 }, { NULL, NULL }, }, "enabled", }, #endif /* overscan options */ { "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 }, { NULL, NULL }, }, "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 }, { "Player 2", NULL }, { "Both", NULL }, { NULL, NULL }, }, "None", }, { "fceumm_turbo_delay", "Turbo Delay (in frames)", NULL, "Repeat rate of turbo buttons in frames.", NULL, "input", { { "1", NULL }, { "2", NULL }, { "3", NULL }, { "5", NULL }, { "10", NULL }, { "15", NULL }, { "30", NULL }, { "60", NULL }, { NULL, NULL }, }, "3", }, { "fceumm_zapper_mode", "Zapper Mode", NULL, "Selects device to use for zapper games.", NULL, "input", { { "lightgun", "Lightgun" }, { "touchscreen", "Touchscreen" }, { "mouse", "Mouse" }, { NULL, NULL }, }, "lightgun", }, { "fceumm_show_crosshair", "Show Zapper Crosshair", NULL, "Shows or hides on-screen crosshairs when using a zapper.", NULL, "input", { { "enabled", NULL }, { "disabled", NULL }, { NULL, NULL }, }, "enabled", }, { "fceumm_zapper_tolerance", "Zapper Tolerance", NULL, "Sets how many pixels from target area is on target.", NULL, "input", { { "0", NULL }, { "1", NULL }, { "2", NULL }, { "3", NULL }, { "4", NULL }, { "5", NULL }, { "6", NULL }, { "7", NULL }, { "8", NULL }, { "9", NULL }, { "10", NULL }, { "11", NULL }, { "12", NULL }, { "13", NULL }, { "14", NULL }, { "15", NULL }, { "16", NULL }, { "17", NULL }, { "18", NULL }, { "19", NULL }, { "20", NULL }, { NULL, NULL }, }, "6", }, { "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 }, { NULL, NULL }, }, "disabled", }, { "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", { { "disabled", NULL }, { "enabled", NULL }, { NULL, NULL }, }, "disabled", }, { "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", { { "disabled", NULL }, { "2x-Postrender", NULL }, { "2x-VBlank", NULL }, { NULL, NULL }, }, "disabled", }, { "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", { { "fill $ff", "$FF" }, { "fill $00", "$00" }, { "random", "Random" }, { NULL, NULL }, }, "fill $ff", }, { NULL, NULL, NULL, 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 }; /* ******************************** * Language Mapping ******************************** */ #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 */ NULL, /* RETRO_LANGUAGE_GERMAN */ NULL, /* RETRO_LANGUAGE_ITALIAN */ NULL, /* RETRO_LANGUAGE_DUTCH */ NULL, /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */ NULL, /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */ NULL, /* RETRO_LANGUAGE_RUSSIAN */ NULL, /* RETRO_LANGUAGE_KOREAN */ NULL, /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */ NULL, /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */ NULL, /* RETRO_LANGUAGE_ESPERANTO */ NULL, /* RETRO_LANGUAGE_POLISH */ NULL, /* RETRO_LANGUAGE_VIETNAMESE */ NULL, /* RETRO_LANGUAGE_ARABIC */ NULL, /* RETRO_LANGUAGE_GREEK */ NULL, /* RETRO_LANGUAGE_TURKISH */ }; #endif /* ******************************** * Functions ******************************** */ /* Handles configuration/setting of core options. * Should only be called inside retro_set_environment(). * > We place the function body in the header to avoid the * necessity of adding more .c files (i.e. want this to * be as painless as possible for core devs) */ static INLINE void libretro_set_core_options(retro_environment_t environ_cb, bool *categories_supported) { unsigned version = 0; #ifndef HAVE_NO_LANGEXTRA unsigned language = 0; #endif if (!environ_cb || !categories_supported) return; *categories_supported = false; 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 = options_intl[language]; *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, 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 total number of options */ while (true) { if (option_defs_us[num_options].key) num_options++; else break; } if (version >= 1) { /* Allocate US array */ option_v1_defs_us = (struct retro_core_option_definition *) calloc(num_options + 1, sizeof(struct retro_core_option_definition)); /* Copy parameters from option_defs_us array */ for (i = 0; i < num_options; i++) { 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; 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 (option_defs_intl[num_options_intl].key) num_options_intl++; else break; } /* 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++) { 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; 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 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++; } } } 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); } 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++) { if (values_buf[i]) { free(values_buf[i]); values_buf[i] = NULL; } } free(values_buf); values_buf = NULL; } if (variables) { free(variables); variables = NULL; } } } #ifdef __cplusplus } #endif #endif