X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=platform%2Fcommon%2Fmenu_pico.c;h=7b0cd78c8efb1fe45449e30a1e6f2d9beccf3ca3;hb=refs%2Fremotes%2Fgithub%2Fmaster;hp=44b5bdd5629d4a02272abd24db4bd739faef97c3;hpb=9a1f192a146e9b9752ec1a760745b1261fe9bdec;p=picodrive.git diff --git a/platform/common/menu_pico.c b/platform/common/menu_pico.c index 44b5bdd5..53e52b87 100644 --- a/platform/common/menu_pico.c +++ b/platform/common/menu_pico.c @@ -1,6 +1,7 @@ /* * PicoDrive * (C) notaz, 2010,2011 + * (C) irixxxx, 2023,2024 * * This work is licensed under the terms of MAME license. * See COPYING file in the top-level directory. @@ -14,24 +15,31 @@ #include "input_pico.h" #include "version.h" -#include +#include "../libpicofe/plat.h" + +#include #include -#ifdef PANDORA +#if defined(PANDORA) || defined(__PS2__) #define MENU_X2 1 #else #define MENU_X2 0 #endif +#define COL_ROM PXMAKE(0xbf, 0xbf, 0xff) +#define COL_OTH PXMAKE(0xaf, 0xff, 0xaf) + // FIXME +#ifndef REVISION #define REVISION "0" +#endif static const char *rom_exts[] = { - "zip", - "bin", "smd", "gen", "md", - "iso", "cso", "cue", + "zip", "bin", + "pco", "smd", "gen", "md", + "iso", "cso", "cue", "chd", "32x", - "sms", + "sms", "gg", "sg", "sc", NULL }; @@ -49,48 +57,60 @@ static unsigned short fname2color(const char *fname) } for (i = 0; rom_exts[i] != NULL; i++) - if (strcasecmp(ext, rom_exts[i]) == 0) return 0xbdff; // FIXME: mk defines + if (strcasecmp(ext, rom_exts[i]) == 0) return COL_ROM; for (i = 0; i < array_size(other_exts); i++) - if (strcasecmp(ext, other_exts[i]) == 0) return 0xaff5; - return 0xffff; + if (strcasecmp(ext, other_exts[i]) == 0) return COL_OTH; + return PXMAKE(0xff, 0xff, 0xff); } -#include "../libpicofe/menu.c" +#include static const char *men_dummy[] = { NULL }; +static int menu_w, menu_h; /* platform specific options and handlers */ #if defined(__GP2X__) -#include "../gp2x/menu.c" +#include +#elif defined(__PSP__) +#include +#elif defined(__PS2__) +#include #elif defined(PANDORA) -#include "../pandora/menu.c" +#include #else -#define MENU_OPTIONS_GFX -#define MENU_OPTIONS_ADV +#include #endif -static void make_bg(int no_scale) +static void make_bg(int no_scale, int from_screen) { unsigned short *src = (void *)g_menubg_src_ptr; - int w = g_screen_width, h = g_screen_height; + int w = g_menubg_src_w ? g_menubg_src_w : g_screen_width; + int h = g_menubg_src_h ? g_menubg_src_h : g_screen_height; + int pp = g_menubg_src_pp ? g_menubg_src_pp : g_screen_ppitch; short *dst; int x, y; - if (src == NULL) { - memset(g_menubg_ptr, 0, g_menuscreen_w * g_menuscreen_h * 2); - return; + if (from_screen) { + src = g_screen_ptr; + w = g_screen_width; + h = g_screen_height; + pp = g_screen_ppitch; } + memset(g_menubg_ptr, 0, g_menuscreen_w * g_menuscreen_h * 2); + if (src == NULL) + return; + if (!no_scale && g_menuscreen_w / w >= 2 && g_menuscreen_h / h >= 2) { - unsigned int t, *d = g_menubg_ptr; + u32 t, *d = g_menubg_ptr; d += (g_menuscreen_h / 2 - h * 2 / 2) * g_menuscreen_w / 2; d += (g_menuscreen_w / 2 - w * 2 / 2) / 2; - for (y = 0; y < h; y++, src += w, d += g_menuscreen_w*2/2) { + for (y = 0; y < h; y++, src += pp, d += g_menuscreen_w*2/2) { for (x = 0; x < w; x++) { t = src[x]; - t = ((t & 0xf79e)>>1) - ((t & 0xc618)>>3); + t = (PXMASKH(t,1)>>1) - (PXMASKH(t,3)>>3); t |= t << 16; d[x] = d[x + g_menuscreen_w / 2] = t; } @@ -107,27 +127,47 @@ static void make_bg(int no_scale) (g_menuscreen_w / 2 - w / 2); // darken the active framebuffer - for (; h > 0; dst += g_menuscreen_w, src += g_screen_width, h--) + for (; h > 0; dst += g_menuscreen_w, src += pp, h--) menu_darken_bg(dst, src, w, 1); } -static void menu_enter(int is_rom_loaded) +static void copy_bg(int dir) +{ + unsigned short *bg = (void *)g_menubg_ptr; + unsigned short *sc = (void *)g_menuscreen_ptr; + int h = g_menuscreen_h; + + for (; h > 0; sc += g_menuscreen_pp, bg += g_menuscreen_w, h--) { + if (dir) + memcpy(bg, sc, g_menuscreen_w * 2); + else + memcpy(sc, bg, g_menuscreen_w * 2); + } +} + +static void menu_draw_prep(void) { - if (is_rom_loaded) + if (menu_w == g_menuscreen_w && menu_h == g_menuscreen_h) + return; + menu_w = g_menuscreen_w, menu_h = g_menuscreen_h; + + if (PicoGameLoaded) { - make_bg(0); + make_bg(0, 0); } else { + int pos; char buff[256]; + pos = plat_get_skin_dir(buff, 256); + strcpy(buff + pos, "background.png"); // should really only happen once, on startup.. - emu_make_path(buff, "skin/background.png", sizeof(buff)); - if (readpng(g_menubg_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h) < 0) + memset(g_menubg_ptr, 0, g_menuscreen_w * g_menuscreen_h * 2); + if (readpng(g_menubg_ptr, buff, READPNG_BG, + g_menuscreen_w, g_menuscreen_h) < 0) memset(g_menubg_ptr, 0, g_menuscreen_w * g_menuscreen_h * 2); } - - plat_video_menu_enter(is_rom_loaded); } static void draw_savestate_bg(int slot) @@ -146,11 +186,18 @@ static void draw_savestate_bg(int slot) /* do a frame and fetch menu bg */ pemu_forced_frame(0, 0); - make_bg(0); + make_bg(0, 1); PicoTmpStateRestore(tmp_state); } +static void menu_enter(int is_rom_loaded) +{ + plat_video_menu_enter(is_rom_loaded); + menu_w = menu_h = 0; + menu_draw_prep(); +} + // --------- loading ROM screen ---------- static int cdload_called = 0; @@ -164,8 +211,9 @@ static void load_progress_cb(int percent) len = g_menuscreen_w; menu_draw_begin(0, 1); - dst = (unsigned short *)g_menuscreen_ptr + g_menuscreen_w * me_sfont_h * 2; - for (ln = me_sfont_h - 2; ln > 0; ln--, dst += g_menuscreen_w) + copy_bg(0); + dst = (unsigned short *)g_menuscreen_ptr + g_menuscreen_pp * me_sfont_h * 2; + for (ln = me_sfont_h - 2; ln > 0; ln--, dst += g_menuscreen_pp) memset(dst, 0xff, len * 2); menu_draw_end(); } @@ -176,17 +224,19 @@ static void cdload_progress_cb(const char *fname, int percent) unsigned short *dst; menu_draw_begin(0, 1); - dst = (unsigned short *)g_menuscreen_ptr + g_menuscreen_w * me_sfont_h * 2; - memset(dst, 0xff, g_menuscreen_w * (me_sfont_h - 2) * 2); + dst = (unsigned short *)g_menuscreen_ptr + g_menuscreen_pp * me_sfont_h * 2; + + copy_bg(0); + menuscreen_memset_lines(dst, 0xff, me_sfont_h - 2); - smalltext_out16(1, 3 * me_sfont_h, "Processing CD image / MP3s", 0xffff); - smalltext_out16(1, 4 * me_sfont_h, fname, 0xffff); - dst += g_menuscreen_w * me_sfont_h * 3; + smalltext_out16(1, 3 * me_sfont_h, "Processing CD image / MP3s", PXMAKE(0xff, 0xff, 0xff)); + smalltext_out16(1, 4 * me_sfont_h, fname, PXMAKE(0xff, 0xff, 0xff)); + dst += g_menuscreen_pp * me_sfont_h * 3; if (len > g_menuscreen_w) len = g_menuscreen_w; - for (ln = (me_sfont_h - 2); ln > 0; ln--, dst += g_menuscreen_w) + for (ln = (me_sfont_h - 2); ln > 0; ln--, dst += g_menuscreen_pp) memset(dst, 0xff, len * 2); menu_draw_end(); @@ -196,18 +246,16 @@ static void cdload_progress_cb(const char *fname, int percent) void menu_romload_prepare(const char *rom_name) { const char *p = rom_name + strlen(rom_name); - int i; while (p > rom_name && *p != '/') p--; - /* fill all buffers, callbacks won't update in full */ - for (i = 0; i < 3; i++) { - menu_draw_begin(1, 1); - smalltext_out16(1, 1, "Loading", 0xffff); - smalltext_out16(1, me_sfont_h, p, 0xffff); - menu_draw_end(); - } + menu_draw_begin(1, 1); + smalltext_out16(1, 1, "Loading", PXMAKE(0xff, 0xff, 0xff)); + smalltext_out16(1, me_sfont_h, p, PXMAKE(0xff, 0xff, 0xff)); + /* copy menu to bg for callbacks. OK since we are not in menu_loop here */ + copy_bg(1); + menu_draw_end(); PicoCartLoadProgressCB = load_progress_cb; PicoCDLoadProgressCB = cdload_progress_cb; @@ -220,8 +268,9 @@ void menu_romload_end(void) PicoCDLoadProgressCB = NULL; menu_draw_begin(0, 1); + copy_bg(0); smalltext_out16(1, (cdload_called ? 6 : 3) * me_sfont_h, - "Starting emulation...", 0xffff); + "Starting emulation...", PXMAKE(0xff, 0xff, 0xff)); menu_draw_end(); } @@ -241,12 +290,12 @@ static void draw_patchlist(int sel) if (pos < 0) continue; if (pos >= max_cnt) break; active = PicoPatches[i].active; - smalltext_out16(14, pos * me_sfont_h, active ? "ON " : "OFF", active ? 0xfff6 : 0xffff); - smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h, PicoPatches[i].name, active ? 0xfff6 : 0xffff); + smalltext_out16(14, pos * me_sfont_h, active ? "ON " : "OFF", PXMAKE(0xff, 0xff, active ? 0xff : 0xb0)); + smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h, PicoPatches[i].name, PXMAKE(0xff, 0xff, active ? 0xff : 0xb0)); } pos = start + i; if (pos < max_cnt) - smalltext_out16(14, pos * me_sfont_h, "done", 0xffff); + smalltext_out16(14, pos * me_sfont_h, "done", PXMAKE(0xff, 0xff, 0xff)); text_out16(5, max_cnt / 2 * me_sfont_h, ">"); menu_draw_end(); @@ -278,7 +327,7 @@ static void menu_loop_patches(void) // -------------- key config -------------- -// PicoPad[] format: MXYZ SACB RLDU +// PicoIn.pad[] format: MXYZ SACB RLDU me_bind_action me_ctrl_actions[] = { { "UP ", 0x0001 }, @@ -301,18 +350,21 @@ me_bind_action me_ctrl_actions[] = me_bind_action emuctrl_actions[] = { - { "Load State ", PEV_STATE_LOAD }, - { "Save State ", PEV_STATE_SAVE }, - { "Prev Save Slot ", PEV_SSLOT_PREV }, - { "Next Save Slot ", PEV_SSLOT_NEXT }, - { "Switch Renderer ", PEV_SWITCH_RND }, - { "Volume Down ", PEV_VOL_DOWN }, - { "Volume Up ", PEV_VOL_UP }, - { "Fast forward ", PEV_FF }, - { "Enter Menu ", PEV_MENU }, - { "Pico Next page ", PEV_PICO_PNEXT }, - { "Pico Prev page ", PEV_PICO_PPREV }, - { "Pico Switch input", PEV_PICO_SWINP }, + { "Load State ", PEV_STATE_LOAD }, + { "Save State ", PEV_STATE_SAVE }, + { "Prev Save Slot ", PEV_SSLOT_PREV }, + { "Next Save Slot ", PEV_SSLOT_NEXT }, + { "Switch Renderer", PEV_SWITCH_RND }, + { "Volume Down ", PEV_VOL_DOWN }, + { "Volume Up ", PEV_VOL_UP }, + { "Fast forward ", PEV_FF }, + { "Reset Game ", PEV_RESET }, + { "Enter Menu ", PEV_MENU }, + { "Pico Next page ", PEV_PICO_PNEXT }, + { "Pico Prev page ", PEV_PICO_PPREV }, + { "Pico Storyware ", PEV_PICO_STORY }, + { "Pico Pad ", PEV_PICO_PAD }, + { "Pico Pen state ", PEV_PICO_PENST }, { NULL, 0 } }; @@ -325,6 +377,12 @@ static int key_config_loop_wrap(int id, int keys) case MA_CTRL_PLAYER2: key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1); break; + case MA_CTRL_PLAYER3: + key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 2); + break; + case MA_CTRL_PLAYER4: + key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 3); + break; case MA_CTRL_EMU: key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1); break; @@ -352,22 +410,23 @@ static const char *mgn_dev_name(int id, int *offs) return name; } -static int mh_saveloadcfg(int id, int keys); -static const char *mgn_saveloadcfg(int id, int *offs); +const char *indev0_names[] = { "none", "3 button pad", "6 button pad", "Team player", "4 way play", NULL }; +const char *indev1_names[] = { "none", "3 button pad", "6 button pad", NULL }; -const char *indev_names[] = { "none", "3 button pad", "6 button pad", NULL }; +static char h_play34[] = "Works only for Mega Drive/CD/32X games having\n" + "support for Team player or 4 way play"; static menu_entry e_menu_keyconfig[] = { mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap), mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap), - mee_handler_id("Emulator controls", MA_CTRL_EMU, key_config_loop_wrap), - mee_enum ("Input device 1", MA_OPT_INPUT_DEV0, currentConfig.input_dev0, indev_names), - mee_enum ("Input device 2", MA_OPT_INPUT_DEV1, currentConfig.input_dev1, indev_names), + mee_handler_id_h("Player 3", MA_CTRL_PLAYER3, key_config_loop_wrap, h_play34), + mee_handler_id_h("Player 4", MA_CTRL_PLAYER4, key_config_loop_wrap, h_play34), + mee_handler_id("Emulator hotkeys", MA_CTRL_EMU, key_config_loop_wrap), + mee_enum ("Input device 1", MA_OPT_INPUT_DEV0, currentConfig.input_dev0, indev0_names), + mee_enum ("Input device 2", MA_OPT_INPUT_DEV1, currentConfig.input_dev1, indev1_names), mee_range ("Turbo rate", MA_CTRL_TURBO_RATE, currentConfig.turbo_rate, 1, 30), mee_range ("Analog deadzone", MA_CTRL_DEADZONE, currentConfig.analog_deadzone, 1, 99), - mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_saveloadcfg, mgn_saveloadcfg), - mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_saveloadcfg, mgn_saveloadcfg), mee_label (""), mee_label ("Input devices:"), mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name), @@ -383,9 +442,14 @@ static menu_entry e_menu_keyconfig[] = static int menu_loop_keyconfig(int id, int keys) { static int sel = 0; + int it = 0, x = me_id2offset(e_menu_keyconfig, MA_CTRL_DEV_FIRST); + + while (in_get_dev_name(it, 1, 1)) + it++; + for (it += x; x && e_menu_keyconfig[x].name; x++) + e_menu_keyconfig[x].enabled = x < it; - me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, PicoGameLoaded); - me_loop(e_menu_keyconfig, &sel); + me_loop_d(e_menu_keyconfig, &sel, menu_draw_prep, NULL); PicoSetInputDevice(0, currentConfig.input_dev0); PicoSetInputDevice(1, currentConfig.input_dev1); @@ -393,59 +457,58 @@ static int menu_loop_keyconfig(int id, int keys) return 0; } -// ------------ SCD options menu ------------ +// ------------ MD options menu ------------ -static const char *mgn_cdopt_ra(int id, int *offs) +static const char h_renderer[] = "16bit is more accurate, 8bit is faster"; +static const char h_fmsound[] = "Disabling improves performance, but breaks sound"; +static const char h_dacnoise[] = "FM chips in the 1st Mega Drive model have DAC noise,\n" + "newer models used different chips without this"; +static const char h_fmfilter[] = "Improves sound accuracy but is noticeably slower,\n" + "best quality if native rate isn't working"; +static const char h_picopen[] = "Enabling resets Pico display and d-pad input back to\n" + "screen if the Pico pen button is pressed"; + +static menu_entry e_menu_md_options[] = { - *offs = -5; - if (PicoCDBuffers <= 0) - return " OFF"; - sprintf(static_buff, "%5iK", PicoCDBuffers * 2); - return static_buff; -} + mee_enum_h ("Renderer", MA_OPT_RENDERER, currentConfig.renderer, renderer_names, h_renderer), + mee_onoff_h ("FM audio", MA_OPT2_ENABLE_YM2612, PicoIn.opt, POPT_EN_FM, h_fmsound), + mee_onoff_h ("FM filter", MA_OPT_FM_FILTER, PicoIn.opt, POPT_EN_FM_FILTER, h_fmfilter), + mee_onoff_h ("FM DAC noise", MA_OPT2_ENABLE_YM_DAC, PicoIn.opt, POPT_EN_FM_DAC, h_dacnoise), + mee_onoff_h ("Pen button shows screen", MA_OPT_PICO_PEN, currentConfig.EmuOpt, EOPT_PICO_PEN, h_picopen), + mee_end, +}; -static int mh_cdopt_ra(int id, int keys) +static int menu_loop_md_options(int id, int keys) { - if (keys & PBTN_LEFT) { - PicoCDBuffers >>= 1; - if (PicoCDBuffers < 2) - PicoCDBuffers = 0; - } else { - if (PicoCDBuffers <= 0) - PicoCDBuffers = 1; - PicoCDBuffers <<= 1; - if (PicoCDBuffers > 8*1024) - PicoCDBuffers = 8*1024; // 16M - } + static int sel = 0; + if (renderer_names[0] == NULL) + me_enable(e_menu_md_options, MA_OPT_RENDERER, 0); + me_loop_d(e_menu_md_options, &sel, menu_draw_prep, NULL); + return 0; } +// ------------ SCD options menu ------------ + static const char h_cdleds[] = "Show power/CD LEDs of emulated console"; static const char h_cdda[] = "Play audio tracks from mp3s/wavs/bins"; static const char h_cdpcm[] = "Emulate PCM audio chip for effects/voices/music"; static const char h_srcart[] = "Emulate the save RAM cartridge accessory\n" "most games don't need this"; -static const char h_scfx[] = "Emulate scale/rotate ASIC chip for graphics effects\n" - "disable to improve performance"; -static const char h_bsync[] = "More accurate mode for CPUs (needed for some games)\n" - "disable to improve performance"; static menu_entry e_menu_cd_options[] = { + mee_onoff_h("SaveRAM cart", MA_CDOPT_SAVERAM, PicoIn.opt, POPT_EN_MCD_RAMCART, h_srcart), mee_onoff_h("CD LEDs", MA_CDOPT_LEDS, currentConfig.EmuOpt, EOPT_EN_CD_LEDS, h_cdleds), - mee_onoff_h("CDDA audio", MA_CDOPT_CDDA, PicoOpt, POPT_EN_MCD_CDDA, h_cdda), - mee_onoff_h("PCM audio", MA_CDOPT_PCM, PicoOpt, POPT_EN_MCD_PCM, h_cdpcm), - mee_cust ("ReadAhead buffer", MA_CDOPT_READAHEAD, mh_cdopt_ra, mgn_cdopt_ra), - mee_onoff_h("SaveRAM cart", MA_CDOPT_SAVERAM, PicoOpt, POPT_EN_MCD_RAMCART, h_srcart), - mee_onoff_h("Scale/Rot. fx (slow)", MA_CDOPT_SCALEROT_CHIP, PicoOpt, POPT_EN_MCD_GFX, h_scfx), - mee_onoff_h("Better sync (slow)", MA_CDOPT_BETTER_SYNC, PicoOpt, POPT_EN_MCD_PSYNC, h_bsync), + mee_onoff_h("CDDA audio", MA_CDOPT_CDDA, PicoIn.opt, POPT_EN_MCD_CDDA, h_cdda), + mee_onoff_h("PCM audio", MA_CDOPT_PCM, PicoIn.opt, POPT_EN_MCD_PCM, h_cdpcm), mee_end, }; static int menu_loop_cd_options(int id, int keys) { static int sel = 0; - me_loop(e_menu_cd_options, &sel); + me_loop_d(e_menu_cd_options, &sel, menu_draw_prep, NULL); return 0; } @@ -481,19 +544,14 @@ static const char *mgn_opt_sh2cycles(int id, int *offs) return static_buff; } -static const char h_32x_enable[] = "Enable emulation of the 32X addon"; static const char h_pwm[] = "Disabling may improve performance, but break sound"; -static const char h_sh2cycles[] = "Cycles/millisecond (similar to DOSBox)\n" - "lower values speed up emulation but break games\n" - "at least 11000 recommended for compatibility"; +static const char h_pwmopt[] = "Enabling may improve performance, but break sound"; static menu_entry e_menu_32x_options[] = { - mee_onoff_h ("32X enabled", MA_32XOPT_ENABLE_32X, PicoOpt, POPT_EN_32X, h_32x_enable), mee_enum ("32X renderer", MA_32XOPT_RENDERER, currentConfig.renderer32x, renderer_names32x), - mee_onoff_h ("PWM sound", MA_32XOPT_PWM, PicoOpt, POPT_EN_PWM, h_pwm), - mee_cust_h ("Master SH2 cycles", MA_32XOPT_MSH2_CYCLES, mh_opt_sh2cycles, mgn_opt_sh2cycles, h_sh2cycles), - mee_cust_h ("Slave SH2 cycles", MA_32XOPT_SSH2_CYCLES, mh_opt_sh2cycles, mgn_opt_sh2cycles, h_sh2cycles), + mee_onoff_h ("PWM audio", MA_32XOPT_PWM, PicoIn.opt, POPT_EN_PWM, h_pwm), + mee_onoff_h ("PWM IRQ optimization", MA_OPT2_PWM_IRQ_OPT, PicoIn.opt, POPT_PWM_IRQ_OPT, h_pwmopt), mee_end, }; @@ -501,8 +559,9 @@ static int menu_loop_32x_options(int id, int keys) { static int sel = 0; - me_enable(e_menu_32x_options, MA_32XOPT_RENDERER, renderer_names32x[0] != NULL); - me_loop(e_menu_32x_options, &sel); + if (renderer_names32x[0] == NULL) + me_enable(e_menu_32x_options, MA_32XOPT_RENDERER, 0); + me_loop_d(e_menu_32x_options, &sel, menu_draw_prep, NULL); Pico32xSetClocks(currentConfig.msh2_khz * 1000, currentConfig.msh2_khz * 1000); @@ -511,21 +570,61 @@ static int menu_loop_32x_options(int id, int keys) #endif +// ------------ SMS options menu ------------ + +#ifndef NO_SMS + +static const char *sms_hardwares[] = { "auto", "Game Gear", "Master System", "SG-1000", "SC-3000", NULL }; +static const char *gg_ghosting_opts[] = { "OFF", "weak", "normal", NULL }; +static const char *sms_mappers[] = { "auto", "Sega", "Codemasters", "Korea", "Korea MSX", "Korea X-in-1", "Korea 4-Pak", "Korea Janggun", "Korea Nemesis", "Taiwan 8K RAM", "Korea XOR", "Sega 32K RAM", NULL }; +static const char *sms_tmspalette[] = { "SMS", "SG-1000", NULL }; + +static const char h_smsfm[] = "FM sound is only supported by few games,\n" + "some games may crash with FM enabled"; +static const char h_ghost[] = "Simulate the inertia of the GG LCD display"; +static const char h_smspal[] = "Selects the color palette used for SMS games\n" + "using the original TMS9918 graphics modes"; + +static menu_entry e_menu_sms_options[] = +{ + mee_enum ("System", MA_SMSOPT_HARDWARE, PicoIn.hwSelect, sms_hardwares), + mee_enum ("Cartridge mapping", MA_SMSOPT_MAPPER, PicoIn.mapper, sms_mappers), + mee_enum_h ("Game Gear LCD ghosting", MA_SMSOPT_GHOSTING, currentConfig.ghosting, gg_ghosting_opts, h_ghost), + mee_onoff_h ("FM Sound Unit", MA_OPT2_ENABLE_YM2413, PicoIn.opt, POPT_EN_YM2413, h_smsfm), + mee_enum_h ("SMS palette in TMS mode", MA_SMSOPT_TMSPALETTE, PicoIn.tmsPalette, sms_tmspalette, h_smspal), + mee_end, +}; + +static int menu_loop_sms_options(int id, int keys) +{ + static int sel = 0; + + me_loop_d(e_menu_sms_options, &sel, menu_draw_prep, NULL); + + return 0; +} + +#endif + // ------------ adv options menu ------------ +static const char h_gglcd[] = "Show full VDP image with borders if disabled"; +static const char h_ovrclk[] = "Will break some games, keep at 0"; +static const char h_dynarec[] = "Disabling dynarecs massively slows down 32X"; +static const char h_sh2cycles[] = "Cycles/millisecond (similar to DOSBox)\n" + "lower values speed up emulation but break games\n" + "at least 11000 recommended for compatibility"; + static menu_entry e_menu_adv_options[] = { - mee_onoff ("SRAM/BRAM saves", MA_OPT_SRAM_STATES, currentConfig.EmuOpt, EOPT_EN_SRAM), - mee_onoff ("Disable sprite limit", MA_OPT2_NO_SPRITE_LIM, PicoOpt, POPT_DIS_SPRITE_LIM), - mee_onoff ("Emulate Z80", MA_OPT2_ENABLE_Z80, PicoOpt, POPT_EN_Z80), - mee_onoff ("Emulate YM2612 (FM)", MA_OPT2_ENABLE_YM2612, PicoOpt, POPT_EN_FM), - mee_onoff ("Emulate SN76496 (PSG)", MA_OPT2_ENABLE_SN76496,PicoOpt, POPT_EN_PSG), - mee_onoff ("gzip savestates", MA_OPT2_GZIP_STATES, currentConfig.EmuOpt, EOPT_GZIP_SAVES), - mee_onoff ("Don't save last used ROM", MA_OPT2_NO_LAST_ROM, currentConfig.EmuOpt, EOPT_NO_AUTOSVCFG), - mee_onoff ("Disable idle loop patching",MA_OPT2_NO_IDLE_LOOPS,PicoOpt, POPT_DIS_IDLE_DET), mee_onoff ("Disable frame limiter", MA_OPT2_NO_FRAME_LIMIT,currentConfig.EmuOpt, EOPT_NO_FRMLIMIT), - mee_onoff ("Enable dynarecs", MA_OPT2_SVP_DYNAREC, PicoOpt, POPT_EN_SVP_DRC), - mee_onoff ("Status line in main menu", MA_OPT2_STATUS_LINE, currentConfig.EmuOpt, EOPT_SHOW_RTC), + mee_onoff ("Disable sprite limit", MA_OPT2_NO_SPRITE_LIM, PicoIn.opt, POPT_DIS_SPRITE_LIM), + mee_onoff ("Disable idle loop patching",MA_OPT2_NO_IDLE_LOOPS,PicoIn.opt, POPT_DIS_IDLE_DET), + mee_onoff_h ("Emulate Game Gear LCD", MA_OPT2_ENABLE_GGLCD ,PicoIn.opt, POPT_EN_GG_LCD, h_gglcd), + mee_range_h ("Overclock M68k (%)", MA_OPT2_OVERCLOCK_M68K,currentConfig.overclock_68k, 0, 1000, h_ovrclk), + mee_onoff_h ("Enable dynarecs", MA_OPT2_DYNARECS, PicoIn.opt, POPT_EN_DRC, h_dynarec), + mee_cust_h ("Master SH2 cycles", MA_32XOPT_MSH2_CYCLES, mh_opt_sh2cycles, mgn_opt_sh2cycles, h_sh2cycles), + mee_cust_h ("Slave SH2 cycles", MA_32XOPT_SSH2_CYCLES, mh_opt_sh2cycles, mgn_opt_sh2cycles, h_sh2cycles), MENU_OPTIONS_ADV mee_end, }; @@ -533,7 +632,103 @@ static menu_entry e_menu_adv_options[] = static int menu_loop_adv_options(int id, int keys) { static int sel = 0; - me_loop(e_menu_adv_options, &sel); + + me_loop_d(e_menu_adv_options, &sel, menu_draw_prep, NULL); + PicoIn.overclockM68k = currentConfig.overclock_68k; // int vs short + + return 0; +} + +// ------------ sound options menu ------------ + +static int sndrate_prevnext(int rate, int dir) +{ + const int *rates = plat_target.sound_rates; + int rate_count; + int i; + + for (rate_count = 0; rates[rate_count] != -1; rate_count++) + ; + for (i = 0; i < rate_count; i++) + if (rates[i] == rate) break; + + i += dir ? 1 : -1; + if (i >= rate_count) { + if (!(PicoIn.opt & POPT_EN_STEREO)) { + PicoIn.opt |= POPT_EN_STEREO; + return rates[0]; + } + return rates[rate_count-1]; + } + if (i < 0) { + if (PicoIn.opt & POPT_EN_STEREO) { + PicoIn.opt &= ~POPT_EN_STEREO; + return rates[rate_count-1]; + } + return rates[0]; + } + return rates[i]; +} + +static int mh_opt_snd(int id, int keys) +{ + PicoIn.sndRate = sndrate_prevnext(PicoIn.sndRate, keys & PBTN_RIGHT); + return 0; +} + +static const char *mgn_opt_sound(int id, int *offs) +{ + const char *str2; + *offs = -8; + str2 = (PicoIn.opt & POPT_EN_STEREO) ? "stereo" : "mono"; + if (PicoIn.sndRate > 52000 && PicoIn.sndRate < 54000) + sprintf(static_buff, "native %s", str2); + else sprintf(static_buff, "%5iHz %s", PicoIn.sndRate, str2); + return static_buff; +} + +static int mh_opt_alpha(int id, int keys) +{ + int val = (PicoIn.sndFilterAlpha * 100 + 0x08000) / 0x10000; + if (keys & PBTN_LEFT) val--; + if (keys & PBTN_RIGHT) val++; + if (val < 1) val = 1; + if (val > 99) val = 99; + PicoIn.sndFilterAlpha = val * 0x10000 / 100; + return 0; +} + +static const char *mgn_opt_alpha(int id, int *offs) +{ + int val = (PicoIn.sndFilterAlpha * 100 + 0x08000) / 0x10000; + sprintf(static_buff, "0.%02d", val); + return static_buff; +} + +static const char h_ensound[] = "Disabling turns off sound output, however all\n" + "enabled sound components are still emulated"; +static const char h_quality[] = "native: Mega Drive FM hardware rate (~53000Hz),\n" + "best quality, but may not work on some devices"; +static const char h_lowpass[] = "Low pass filter for sound closer to real hardware"; +static const char h_lpalpha[] = "Higher values have more impact"; + +static menu_entry e_menu_snd_options[] = +{ + mee_onoff_h ("Enable sound", MA_OPT_ENABLE_SOUND, currentConfig.EmuOpt, EOPT_EN_SOUND, h_ensound), + mee_cust_h ("Sound quality", MA_OPT_SOUND_QUALITY, mh_opt_snd, mgn_opt_sound, h_quality), + mee_onoff_h ("Sound filter", MA_OPT_SOUND_FILTER, PicoIn.opt, POPT_EN_SNDFILTER, h_lowpass), + mee_cust_h ("Filter strength", MA_OPT_SOUND_ALPHA, mh_opt_alpha, mgn_opt_alpha, h_lpalpha), + mee_end, +}; + +static int menu_loop_snd_options(int id, int keys) +{ + static int sel = 0; + + if (PicoIn.sndRate > 52000 && PicoIn.sndRate < 54000) + PicoIn.sndRate = 53000; + me_loop_d(e_menu_snd_options, &sel, menu_draw_prep, NULL); + return 0; } @@ -541,6 +736,14 @@ static int menu_loop_adv_options(int id, int keys) static const char h_gamma[] = "Gamma/brightness adjustment (default 1.00)"; +static const char *mgn_opt_fskip(int id, int *offs) +{ + if (currentConfig.Frameskip < 0) + return "Auto"; + sprintf(static_buff, "%d", currentConfig.Frameskip); + return static_buff; +} + static const char *mgn_aopt_gamma(int id, int *offs) { sprintf(static_buff, "%i.%02i", currentConfig.gamma / 100, currentConfig.gamma % 100); @@ -549,10 +752,11 @@ static const char *mgn_aopt_gamma(int id, int *offs) static menu_entry e_menu_gfx_options[] = { - mee_enum ("Video output mode", MA_OPT_VOUT_MODE, plat_target.vout_method, men_dummy), - mee_enum ("Renderer", MA_OPT_RENDERER, currentConfig.renderer, renderer_names), - mee_enum ("Filter", MA_OPT3_FILTERING, currentConfig.filter, men_dummy), - mee_range_cust_h("Gamma correction", MA_OPT2_GAMMA, currentConfig.gamma, 1, 300, mgn_aopt_gamma, h_gamma), + mee_enum ("Video output mode", MA_OPT_VOUT_MODE, plat_target.vout_method, men_dummy), + mee_range_cust("Frameskip", MA_OPT_FRAMESKIP, currentConfig.Frameskip, -1, 16, mgn_opt_fskip), + mee_range ("Max auto frameskip",MA_OPT2_MAX_FRAMESKIP, currentConfig.max_skip, 1, 10), + mee_enum ("Filter", MA_OPT3_FILTERING, currentConfig.filter, men_dummy), + mee_range_cust_h("Gamma correction",MA_OPT2_GAMMA, currentConfig.gamma, 1, 300, mgn_aopt_gamma, h_gamma), MENU_OPTIONS_GFX mee_end, }; @@ -561,40 +765,102 @@ static int menu_loop_gfx_options(int id, int keys) { static int sel = 0; - me_enable(e_menu_gfx_options, MA_OPT_RENDERER, renderer_names[0] != NULL); - me_loop(e_menu_gfx_options, &sel); + me_loop_d(e_menu_gfx_options, &sel, menu_draw_prep, NULL); return 0; } -// ------------ options menu ------------ +// ------------ UI options menu ------------ -static menu_entry e_menu_options[]; +static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL }; +static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n" + "loading state or both"; -static int sndrate_prevnext(int rate, int dir) +static menu_entry e_menu_ui_options[] = { - static const int rates[] = { 8000, 11025, 16000, 22050, 44100 }; - int i; + mee_onoff ("Show FPS", MA_OPT_SHOW_FPS, currentConfig.EmuOpt, EOPT_SHOW_FPS), + mee_enum_h ("Confirm save/load", MA_OPT_CONFIRM_STATES, currentConfig.confirm_save, men_confirm_save, h_confirm_save), + mee_onoff ("Don't save last used game", MA_OPT2_NO_LAST_ROM, currentConfig.EmuOpt, EOPT_NO_AUTOSVCFG), + mee_end, +}; - for (i = 0; i < 5; i++) - if (rates[i] == rate) break; +static int menu_loop_ui_options(int id, int keys) +{ + static int sel = 0; - i += dir ? 1 : -1; - if (i > 4) { - if (!(PicoOpt & POPT_EN_STEREO)) { - PicoOpt |= POPT_EN_STEREO; - return rates[0]; - } - return rates[4]; - } - if (i < 0) { - if (PicoOpt & POPT_EN_STEREO) { - PicoOpt &= ~POPT_EN_STEREO; - return rates[4]; - } - return rates[0]; + me_loop_d(e_menu_ui_options, &sel, menu_draw_prep, NULL); + + return 0; +} + +// ------------ options menu ------------ + +static int find_renderer(const char *names[], const char *which) +{ + int i = 0; + for (i = 0; *names; names++, i++) + if (strstr(*names, which)) return i; + return 0; +} + +static int mh_profile(int id, int keys) { + switch (id) { + case MA_PROFILE_ACCURATE: + currentConfig.renderer = find_renderer(renderer_names, "16bit"); + currentConfig.renderer32x = find_renderer(renderer_names32x, "accurate"); + PicoIn.sndRate = 44100; + PicoIn.opt |= POPT_EN_FM_FILTER | POPT_EN_FM | POPT_EN_MCD_CDDA; + PicoIn.opt &= ~POPT_PWM_IRQ_OPT; + break; + case MA_PROFILE_BALANCED: + currentConfig.renderer = find_renderer(renderer_names, "8bit"); + currentConfig.renderer32x = find_renderer(renderer_names32x, "fast"); + PicoIn.sndRate = 44100; + PicoIn.opt |= POPT_EN_FM | POPT_EN_MCD_CDDA; + PicoIn.opt &= ~(POPT_PWM_IRQ_OPT | POPT_EN_FM_FILTER); + break; + case MA_PROFILE_FAST: + currentConfig.renderer = find_renderer(renderer_names, "fast"); + currentConfig.renderer32x = find_renderer(renderer_names32x, "fastest"); + PicoIn.sndRate = 22050; + PicoIn.opt |= POPT_PWM_IRQ_OPT | POPT_EN_FM | POPT_EN_MCD_CDDA; + PicoIn.opt &= ~POPT_EN_FM_FILTER; + break; + case MA_PROFILE_BREAKING: + currentConfig.renderer = find_renderer(renderer_names, "fast"); + currentConfig.renderer32x = find_renderer(renderer_names32x, "fastest"); + PicoIn.sndRate = 16000; + PicoIn.opt |= POPT_PWM_IRQ_OPT; + PicoIn.opt &= ~(POPT_EN_FM_FILTER | POPT_EN_FM | POPT_EN_MCD_CDDA); + break; } - return rates[i]; + return 1; +} + +static menu_entry e_menu_profile[] = +{ + mee_label ("Select option profile and press OK:"), + mee_handler_id("accurate", MA_PROFILE_ACCURATE, mh_profile), + mee_handler_id("balanced", MA_PROFILE_BALANCED, mh_profile), + mee_handler_id("fast", MA_PROFILE_FAST, mh_profile), + mee_handler_id("breaking", MA_PROFILE_BREAKING, mh_profile), + mee_label (""), + mee_label ("Options changed by Option profiles:"), + mee_label (""), + mee_label ("Sound: Sound quality"), + mee_label ("MD: Renderer, FM audio, FM filter"), + mee_label ("32X: Renderer, PWM IRQ optimization"), + mee_label ("CD: CDDA audio"), + mee_end, +}; + +static int menu_loop_profile_options(int id, int keys) +{ + static int sel = 0; + + me_loop_d(e_menu_profile, &sel, menu_draw_prep, NULL); + + return 0; } static void region_prevnext(int right) @@ -604,33 +870,30 @@ static void region_prevnext(int right) int i; if (right) { - if (!PicoRegionOverride) { + if (!PicoIn.regionOverride) { for (i = 0; i < 6; i++) - if (rgn_orders[i] == PicoAutoRgnOrder) break; - if (i < 5) PicoAutoRgnOrder = rgn_orders[i+1]; - else PicoRegionOverride=1; + if (rgn_orders[i] == PicoIn.autoRgnOrder) break; + if (i < 5) PicoIn.autoRgnOrder = rgn_orders[i+1]; + else PicoIn.regionOverride=1; } else - PicoRegionOverride <<= 1; - if (PicoRegionOverride > 8) - PicoRegionOverride = 8; + PicoIn.regionOverride <<= 1; + if (PicoIn.regionOverride > 8) + PicoIn.regionOverride = 8; } else { - if (!PicoRegionOverride) { + if (!PicoIn.regionOverride) { for (i = 0; i < 6; i++) - if (rgn_orders[i] == PicoAutoRgnOrder) break; - if (i > 0) PicoAutoRgnOrder = rgn_orders[i-1]; + if (rgn_orders[i] == PicoIn.autoRgnOrder) break; + if (i > 0) PicoIn.autoRgnOrder = rgn_orders[i-1]; } else - PicoRegionOverride >>= 1; + PicoIn.regionOverride >>= 1; } } static int mh_opt_misc(int id, int keys) { switch (id) { - case MA_OPT_SOUND_QUALITY: - PsndRate = sndrate_prevnext(PsndRate, keys & PBTN_RIGHT); - break; case MA_OPT_REGION: region_prevnext(keys & PBTN_RIGHT); break; @@ -640,39 +903,6 @@ static int mh_opt_misc(int id, int keys) return 0; } -static int mh_saveloadcfg(int id, int keys) -{ - int ret; - - if (keys & (PBTN_LEFT|PBTN_RIGHT)) { // multi choice - config_slot += (keys & PBTN_LEFT) ? -1 : 1; - if (config_slot < 0) config_slot = 9; - else if (config_slot > 9) config_slot = 0; - me_enable(e_menu_options, MA_OPT_LOADCFG, config_slot != config_slot_current); - return 0; - } - - switch (id) { - case MA_OPT_SAVECFG: - case MA_OPT_SAVECFG_GAME: - if (emu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0)) - menu_update_msg("config saved"); - else - menu_update_msg("failed to write config"); - break; - case MA_OPT_LOADCFG: - ret = emu_read_config(rom_fname_loaded, 1); - if (!ret) ret = emu_read_config(NULL, 1); - if (ret) menu_update_msg("config loaded"); - else menu_update_msg("failed to load config"); - break; - default: - return 0; - } - - return 1; -} - static int mh_restore_defaults(int id, int keys) { emu_set_defconfig(); @@ -680,28 +910,11 @@ static int mh_restore_defaults(int id, int keys) return 1; } -static const char *mgn_opt_fskip(int id, int *offs) -{ - if (currentConfig.Frameskip < 0) - return "Auto"; - sprintf(static_buff, "%d", currentConfig.Frameskip); - return static_buff; -} - -static const char *mgn_opt_sound(int id, int *offs) -{ - const char *str2; - *offs = -8; - str2 = (PicoOpt & POPT_EN_STEREO) ? "stereo" : "mono"; - sprintf(static_buff, "%5iHz %s", PsndRate, str2); - return static_buff; -} - static const char *mgn_opt_region(int id, int *offs) { static const char *names[] = { "Auto", " Japan NTSC", " Japan PAL", " USA", " Europe" }; static const char *names_short[] = { "", " JP", " JP", " US", " EU" }; - int code = PicoRegionOverride; + int code = PicoIn.regionOverride; int u, i = 0; *offs = -6; @@ -714,7 +927,7 @@ static const char *mgn_opt_region(int id, int *offs) } else { strcpy(static_buff, "Auto:"); for (u = 0; u < 3; u++) { - code = (PicoAutoRgnOrder >> u*4) & 0xf; + code = (PicoIn.autoRgnOrder >> u*4) & 0xf; for (i = 0; code; code >>= 1, i++) ; strcat(static_buff, names_short[i]); @@ -723,37 +936,29 @@ static const char *mgn_opt_region(int id, int *offs) } } -static const char *mgn_saveloadcfg(int id, int *offs) -{ - static_buff[0] = 0; - if (config_slot != 0) - sprintf(static_buff, "[%i]", config_slot); - return static_buff; -} - -static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL }; -static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n" - "loading state or both"; +static const char h_hotkeysvld[] = "Slot used for save/load by emulator hotkey"; static menu_entry e_menu_options[] = { - mee_range ("Save slot", MA_OPT_SAVE_SLOT, state_slot, 0, 9), - mee_range_cust("Frameskip", MA_OPT_FRAMESKIP, currentConfig.Frameskip, -1, 16, mgn_opt_fskip), mee_cust ("Region", MA_OPT_REGION, mh_opt_misc, mgn_opt_region), - mee_onoff ("Show FPS", MA_OPT_SHOW_FPS, currentConfig.EmuOpt, EOPT_SHOW_FPS), - mee_onoff ("Enable sound", MA_OPT_ENABLE_SOUND, currentConfig.EmuOpt, EOPT_EN_SOUND), - mee_cust ("Sound Quality", MA_OPT_SOUND_QUALITY, mh_opt_misc, mgn_opt_sound), - mee_enum_h ("Confirm savestate", MA_OPT_CONFIRM_STATES,currentConfig.confirm_save, men_confirm_save, h_confirm_save), - mee_range ("", MA_OPT_CPU_CLOCKS, currentConfig.CPUclock, 20, 1200), - mee_handler ("[Display options]", menu_loop_gfx_options), - mee_handler ("[Sega/Mega CD options]", menu_loop_cd_options), + mee_range ("", MA_OPT_CPU_CLOCKS, currentConfig.CPUclock, 20, 3200), + mee_range_h ("Hotkey save/load slot", MA_OPT_SAVE_SLOT, state_slot, 0, 9, h_hotkeysvld), + mee_handler ("Configure controls", menu_loop_keyconfig), + mee_label (""), + mee_handler ("Option profiles", menu_loop_profile_options), + mee_handler ("Interface options", menu_loop_ui_options), + mee_handler ("Display options", menu_loop_gfx_options), + mee_handler ("Sound options", menu_loop_snd_options), + mee_handler ("MD/Genesis/Pico options", menu_loop_md_options), + mee_handler (" Sega/Mega CD add-on", menu_loop_cd_options), #ifndef NO_32X - mee_handler ("[32X options]", menu_loop_32x_options), + mee_handler (" 32X add-on", menu_loop_32x_options), +#endif +#ifndef NO_SMS + mee_handler ("SG/SMS/GG options", menu_loop_sms_options), #endif - mee_handler ("[Advanced options]", menu_loop_adv_options), - mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_saveloadcfg, mgn_saveloadcfg), - mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_saveloadcfg, mgn_saveloadcfg), - mee_cust_nosave("Load cfg from profile", MA_OPT_LOADCFG, mh_saveloadcfg, mgn_saveloadcfg), + mee_handler ("Advanced options", menu_loop_adv_options), + mee_handler ("Restore defaults", mh_restore_defaults), mee_end, }; @@ -762,10 +967,7 @@ static int menu_loop_options(int id, int keys) { static int sel = 0; - me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, PicoGameLoaded); - me_enable(e_menu_options, MA_OPT_LOADCFG, config_slot != config_slot_current); - - me_loop(e_menu_options, &sel); + me_loop_d(e_menu_options, &sel, menu_draw_prep, NULL); return 0; } @@ -809,7 +1011,7 @@ static void draw_text_debug(const char *str, int skip, int from) str = p; for (line = from; line < g_menuscreen_h / me_sfont_h; line++) { - smalltext_out16(1, line * me_sfont_h, str, 0xffff); + smalltext_out16(1, line * me_sfont_h, str, PXMAKE(0xff, 0xff, 0xff)); while (*p && *p != '\n') p++; if (*p == 0) @@ -827,21 +1029,24 @@ static void draw_text_debug(const char *str, int skip, int from) static void draw_frame_debug(void) { char layer_str[48] = "layers: "; - if (PicoDrawMask & PDRAW_LAYERB_ON) memcpy(layer_str + 8, "B", 1); - if (PicoDrawMask & PDRAW_LAYERA_ON) memcpy(layer_str + 10, "A", 1); - if (PicoDrawMask & PDRAW_SPRITES_LOW_ON) memcpy(layer_str + 12, "spr_lo", 6); - if (PicoDrawMask & PDRAW_SPRITES_HI_ON) memcpy(layer_str + 19, "spr_hi", 6); - if (PicoDrawMask & PDRAW_32X_ON) memcpy(layer_str + 26, "32x", 4); + struct PicoVideo *pv = &Pico.video; + + if (!(pv->debug_p & PVD_KILL_B)) memcpy(layer_str + 8, "B", 1); + if (!(pv->debug_p & PVD_KILL_A)) memcpy(layer_str + 10, "A", 1); + if (!(pv->debug_p & PVD_KILL_S_LO)) memcpy(layer_str + 12, "spr_lo", 6); + if (!(pv->debug_p & PVD_KILL_S_HI)) memcpy(layer_str + 19, "spr_hi", 6); + if (!(pv->debug_p & PVD_KILL_32X)) memcpy(layer_str + 26, "32x", 4); pemu_forced_frame(1, 0); - make_bg(1); + make_bg(1, 1); - smalltext_out16(4, 1, "build: r" REVISION " "__DATE__ " " __TIME__ " " COMPILER, 0xffff); - smalltext_out16(4, g_menuscreen_h - me_sfont_h, layer_str, 0xffff); + smalltext_out16(4, 1, "build: r" REVISION " "__DATE__ " " __TIME__ " " COMPILER, PXMAKE(0xff, 0xff, 0xff)); + smalltext_out16(4, g_menuscreen_h - me_sfont_h, layer_str, PXMAKE(0xff, 0xff, 0xff)); } static void debug_menu_loop(void) { + struct PicoVideo *pv = &Pico.video; int inp, mode = 0; int spr_offs = 0, dumped = 0; char *tmp; @@ -849,6 +1054,10 @@ static void debug_menu_loop(void) while (1) { menu_draw_begin(1, 0); + g_screen_ptr = g_menuscreen_ptr; + g_screen_width = g_menuscreen_w; + g_screen_height = g_menuscreen_h; + g_screen_ppitch = g_menuscreen_pp; switch (mode) { case 0: tmp = PDebugMain(); @@ -856,21 +1065,23 @@ static void debug_menu_loop(void) draw_text_debug(tmp, 0, 0); if (dumped) { smalltext_out16(g_menuscreen_w - 6 * me_sfont_h, - g_menuscreen_h - me_mfont_h, "dumped", 0xffff); + g_menuscreen_h - me_mfont_h, "dumped", PXMAKE(0xff, 0xff, 0xff)); dumped = 0; } break; case 1: draw_frame_debug(); break; case 2: pemu_forced_frame(1, 0); - make_bg(1); - PDebugShowSpriteStats((unsigned short *)g_menuscreen_ptr + (g_menuscreen_h/2 - 240/2)*g_menuscreen_w + - g_menuscreen_w/2 - 320/2, g_menuscreen_w); + make_bg(1, 1); + PDebugShowSpriteStats((unsigned short *)g_menuscreen_ptr + + (g_menuscreen_h/2 - 240/2) * g_menuscreen_pp + + g_menuscreen_w/2 - 320/2, g_menuscreen_pp); break; - case 3: memset(g_menuscreen_ptr, 0, g_menuscreen_w * g_menuscreen_h * 2); - PDebugShowPalette(g_menuscreen_ptr, g_menuscreen_w); - PDebugShowSprite((unsigned short *)g_menuscreen_ptr + g_menuscreen_w*120 + g_menuscreen_w/2 + 16, - g_menuscreen_w, spr_offs); + case 3: menuscreen_memset_lines(g_menuscreen_ptr, 0, g_menuscreen_h); + PDebugShowPalette(g_menuscreen_ptr, g_menuscreen_pp); + PDebugShowSprite((unsigned short *)g_menuscreen_ptr + + g_menuscreen_pp * 120 + g_menuscreen_w / 2 + 16, + g_menuscreen_pp, spr_offs); draw_text_debug(PDebugSpriteList(), spr_offs, 6); break; case 4: tmp = PDebug32x(); @@ -902,16 +1113,16 @@ static void debug_menu_loop(void) } break; case 1: - if (inp & PBTN_LEFT) PicoDrawMask ^= PDRAW_LAYERB_ON; - if (inp & PBTN_RIGHT) PicoDrawMask ^= PDRAW_LAYERA_ON; - if (inp & PBTN_DOWN) PicoDrawMask ^= PDRAW_SPRITES_LOW_ON; - if (inp & PBTN_UP) PicoDrawMask ^= PDRAW_SPRITES_HI_ON; - if (inp & PBTN_MA2) PicoDrawMask ^= PDRAW_32X_ON; + if (inp & PBTN_LEFT) pv->debug_p ^= PVD_KILL_B; + if (inp & PBTN_RIGHT) pv->debug_p ^= PVD_KILL_A; + if (inp & PBTN_DOWN) pv->debug_p ^= PVD_KILL_S_LO; + if (inp & PBTN_UP) pv->debug_p ^= PVD_KILL_S_HI; + if (inp & PBTN_MA2) pv->debug_p ^= PVD_KILL_32X; if (inp & PBTN_MOK) { - PsndOut = NULL; // just in case - PicoSkipFrame = 1; + PicoIn.sndOut = NULL; // just in case + PicoIn.skipFrame = 1; PicoFrame(); - PicoSkipFrame = 0; + PicoIn.skipFrame = 0; while (inp & PBTN_MOK) inp = in_menu_wait_any(NULL, -1); } break; @@ -926,13 +1137,28 @@ static void debug_menu_loop(void) // ------------ main menu ------------ +static void draw_frame_credits(void) +{ + smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__, PXMAKE(0xe0, 0xff, 0xe0)); +} + static const char credits[] = - "PicoDrive v" VERSION " (c) notaz, 2006-2013\n\n\n" + "PicoDrive v" VERSION "\n" + "(c) notaz, 2006-2013; irixxxx, 2018-2024\n\n" "Credits:\n" - "fDave: Cyclone 68000 core,\n" - " base code of PicoDrive\n" + "fDave: initial code\n" +#ifdef EMU_C68K + " Cyclone 68000 core\n" +#else + "Stef, Chui: FAME/C 68k core\n" +#endif +#ifdef _USE_DRZ80 "Reesy & FluBBa: DrZ80 core\n" - "MAME devs: YM2612 and SN76496 cores\n" +#else + "Stef, NJ: CZ80 core\n" +#endif + "MAME devs: SH2, YM2612 and SN76496 cores\n" + "Eke, Stef: some Sega CD code\n" "Inder, ketchupgun: graphics\n" #ifdef __GP2X__ "Squidge: mmuhack\n" @@ -949,7 +1175,7 @@ static void menu_main_draw_status(void) { static time_t last_bat_read = 0; static int last_bat_val = -1; - unsigned short *bp = g_screen_ptr; + unsigned short *bp = g_menuscreen_ptr; int bat_h = me_mfont_h * 2 / 3; int i, u, w, wfill, batt_val; struct tm *tmp; @@ -963,7 +1189,7 @@ static void menu_main_draw_status(void) tmp = gmtime(<ime); strftime(time_s, sizeof(time_s), "%H:%M", tmp); - text_out16(g_screen_width - me_mfont_w * 6, me_mfont_h + 2, time_s); + text_out16(g_menuscreen_w - me_mfont_w * 6, me_mfont_h + 2, time_s); if (ltime - last_bat_read > 10) { last_bat_read = ltime; @@ -976,25 +1202,27 @@ static void menu_main_draw_status(void) return; /* battery info */ - bp += (me_mfont_h * 2 + 2) * g_screen_width + g_screen_width - me_mfont_w * 3 - 3; + bp += (me_mfont_h * 2 + 2) * g_menuscreen_pp + g_menuscreen_w - me_mfont_w * 3 - 3; for (i = 0; i < me_mfont_w * 2; i++) bp[i] = menu_text_color; for (i = 0; i < me_mfont_w * 2; i++) - bp[i + g_screen_width * bat_h] = menu_text_color; + bp[i + g_menuscreen_pp * bat_h] = menu_text_color; for (i = 0; i <= bat_h; i++) - bp[i * g_screen_width] = - bp[i * g_screen_width + me_mfont_w * 2] = menu_text_color; + bp[i * g_menuscreen_pp] = + bp[i * g_menuscreen_pp + me_mfont_w * 2] = menu_text_color; for (i = 2; i < bat_h - 1; i++) - bp[i * g_screen_width - 1] = - bp[i * g_screen_width - 2] = menu_text_color; + bp[i * g_menuscreen_pp - 1] = + bp[i * g_menuscreen_pp - 2] = menu_text_color; w = me_mfont_w * 2 - 1; wfill = batt_val * w / 100; for (u = 1; u < bat_h; u++) for (i = 0; i < wfill; i++) - bp[(w - i) + g_screen_width * u] = menu_text_color; + bp[(w - i) + g_menuscreen_pp * u] = menu_text_color; } +static menu_entry e_menu_main[]; + static int main_menu_handler(int id, int keys) { const char *ret_name; @@ -1021,8 +1249,8 @@ static int main_menu_handler(int id, int keys) break; case MA_MAIN_LOAD_ROM: rom_fname_reload = NULL; - ret_name = menu_loop_romsel(rom_fname_loaded, - sizeof(rom_fname_loaded), rom_exts, NULL); + ret_name = menu_loop_romsel_d(rom_fname_loaded, + sizeof(rom_fname_loaded), rom_exts, NULL, menu_draw_prep); if (ret_name != NULL) { lprintf("selected file: %s\n", ret_name); rom_fname_reload = ret_name; @@ -1030,8 +1258,17 @@ static int main_menu_handler(int id, int keys) return 1; } break; + case MA_MAIN_CHANGE_CD: + if (PicoIn.AHW & PAHW_MCD) { + // if cd is loaded, cdd_unload() triggers eject and + // returns 1, else we'll select and load new CD here + if (!cdd_unload()) + menu_loop_tray(); + return 1; + } + break; case MA_MAIN_CREDITS: - draw_menu_message(credits, NULL); + draw_menu_message(credits, draw_frame_credits); in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70); break; case MA_MAIN_EXIT: @@ -1052,21 +1289,85 @@ static int main_menu_handler(int id, int keys) return 0; } +static const char *mgn_picopage(int id, int *offs) +{ + strcpy(static_buff, " "); + sprintf(static_buff, "%i", PicoPicohw.page); + return static_buff; +} + +static int mh_picopage(int id, int keys) +{ + if (keys & (PBTN_LEFT|PBTN_RIGHT)) { // multi choice + PicoPicohw.page += (keys & PBTN_LEFT) ? -1 : 1; + if (PicoPicohw.page < 0) PicoPicohw.page = 6; + else if (PicoPicohw.page > 6) PicoPicohw.page = 0; + return 0; + } + return 1; +} + +static const char *mgn_saveloadcfg(int id, int *offs) +{ + strcpy(static_buff, " "); + if (config_slot != 0) + sprintf(static_buff, "[%i]", config_slot); + return static_buff; +} + +static int mh_saveloadcfg(int id, int keys) +{ + int ret; + + if (keys & (PBTN_LEFT|PBTN_RIGHT)) { // multi choice + config_slot += (keys & PBTN_LEFT) ? -1 : 1; + if (config_slot < 0) config_slot = 9; + else if (config_slot > 9) config_slot = 0; + me_enable(e_menu_main, MA_OPT_LOADCFG, PicoGameLoaded && config_slot != config_slot_current); + return 0; + } + + switch (id) { + case MA_OPT_SAVECFG: + case MA_OPT_SAVECFG_GAME: + if (emu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0)) + menu_update_msg("config saved"); + else + menu_update_msg("failed to write config"); + break; + case MA_OPT_LOADCFG: + ret = emu_read_config(rom_fname_loaded, 1); + if (!ret) ret = emu_read_config(NULL, 1); + if (ret) menu_update_msg("config loaded"); + else menu_update_msg("failed to load config"); + break; + default: + return 0; + } + + return 1; +} + +static const char h_saveload[] = "Game options are overloading global options"; + static menu_entry e_menu_main[] = { mee_label ("PicoDrive " VERSION), mee_label (""), mee_label (""), - mee_label (""), mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler), - mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler), - mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler), + mee_handler_id("Save state", MA_MAIN_SAVE_STATE, main_menu_handler), + mee_handler_id("Load state", MA_MAIN_LOAD_STATE, main_menu_handler), mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler), - mee_handler_id("Load new ROM/ISO", MA_MAIN_LOAD_ROM, main_menu_handler), + mee_handler_id("Change CD", MA_MAIN_CHANGE_CD, main_menu_handler), + mee_cust_s_h ("Storyware page", MA_MAIN_PICO_PAGE, 0,mh_picopage, mgn_picopage, NULL), + mee_handler_id("Patches / GameGenie",MA_MAIN_PATCHES, main_menu_handler), + mee_handler_id("Load new game", MA_MAIN_LOAD_ROM, main_menu_handler), mee_handler ("Change options", menu_loop_options), - mee_handler ("Configure controls", menu_loop_keyconfig), + mee_cust_s_h ("Save global options",MA_OPT_SAVECFG, 0, mh_saveloadcfg, mgn_saveloadcfg, NULL), + mee_cust_s_h ("Save game options", MA_OPT_SAVECFG_GAME, 0, mh_saveloadcfg, mgn_saveloadcfg, h_saveload), + mee_cust_s_h ("Load game options", MA_OPT_LOADCFG, 0, mh_saveloadcfg, mgn_saveloadcfg, h_saveload), mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler), - mee_handler_id("Patches / GameGenie",MA_MAIN_PATCHES, main_menu_handler), mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler), mee_end, }; @@ -1079,11 +1380,15 @@ void menu_loop(void) me_enable(e_menu_main, MA_MAIN_SAVE_STATE, PicoGameLoaded); me_enable(e_menu_main, MA_MAIN_LOAD_STATE, PicoGameLoaded); me_enable(e_menu_main, MA_MAIN_RESET_GAME, PicoGameLoaded); - me_enable(e_menu_main, MA_MAIN_PATCHES, PicoPatches != NULL); + me_enable(e_menu_main, MA_MAIN_CHANGE_CD, PicoIn.AHW & PAHW_MCD); + me_enable(e_menu_main, MA_MAIN_PICO_PAGE, PicoIn.AHW & PAHW_PICO); + me_enable(e_menu_main, MA_MAIN_PATCHES, PicoPatches != NULL); + me_enable(e_menu_main, MA_OPT_SAVECFG_GAME, PicoGameLoaded); + me_enable(e_menu_main, MA_OPT_LOADCFG, PicoGameLoaded && config_slot != config_slot_current); menu_enter(PicoGameLoaded); in_set_config_int(0, IN_CFG_BLOCKING, 1); - me_loop_d(e_menu_main, &sel, NULL, menu_main_draw_status); + me_loop_d(e_menu_main, &sel, menu_draw_prep, menu_main_draw_status); if (PicoGameLoaded) { if (engineState == PGS_Menu) @@ -1104,8 +1409,8 @@ static int mh_tray_load_cd(int id, int keys) const char *ret_name; rom_fname_reload = NULL; - ret_name = menu_loop_romsel(rom_fname_loaded, - sizeof(rom_fname_loaded), rom_exts, NULL); + ret_name = menu_loop_romsel_d(rom_fname_loaded, + sizeof(rom_fname_loaded), rom_exts, NULL, menu_draw_prep); if (ret_name == NULL) return 0; @@ -1136,7 +1441,7 @@ int menu_loop_tray(void) menu_enter(PicoGameLoaded); in_set_config_int(0, IN_CFG_BLOCKING, 1); - me_loop(e_menu_tray, &sel); + me_loop_d(e_menu_tray, &sel, menu_draw_prep, NULL); if (engineState != PGS_RestartRun) { engineState = PGS_RestartRun; @@ -1165,19 +1470,36 @@ void menu_update_msg(const char *msg) /* hidden options for config engine only */ static menu_entry e_menu_hidden[] = { - mee_onoff("Accurate sprites", MA_OPT_ACC_SPRITES, PicoOpt, 0x080), - mee_onoff("autoload savestates", MA_OPT_AUTOLOAD_SAVE, g_autostateld_opt, 1), + mee_onoff("Accurate sprites", MA_OPT_ACC_SPRITES, PicoIn.opt, POPT_ACC_SPRITES), +// mee_range("Save slot", MA_OPT_SAVE_SLOT, state_slot, 0, 9), + +// mee_enum ("Confirm savestate", MA_OPT_CONFIRM_STATES, currentConfig.confirm_save, men_confirm_save), + mee_onoff("autoload savestates", MA_OPT_AUTOLOAD_SAVE, g_autostateld_opt, 1), + mee_onoff("SDL fullscreen mode", MA_OPT_VOUT_FULL, plat_target.vout_fullscreen, 1), + mee_onoff("Emulate Z80", MA_OPT2_ENABLE_Z80, PicoIn.opt, POPT_EN_Z80), + mee_onoff("Emulate YM2612 (FM)", MA_OPT2_ENABLE_YM2612, PicoIn.opt, POPT_EN_FM), + mee_onoff("Disable YM2612 SSG-EG", MA_OPT2_DISABLE_YM_SSG,PicoIn.opt, POPT_DIS_FM_SSGEG), + mee_onoff("Enable YM2612 DAC noise", MA_OPT2_ENABLE_YM_DAC, PicoIn.opt, POPT_EN_FM_DAC), + mee_onoff("Emulate SN76496 (PSG)", MA_OPT2_ENABLE_SN76496,PicoIn.opt, POPT_EN_PSG), + mee_onoff("Scale/Rot. fx", MA_CDOPT_SCALEROT_CHIP,PicoIn.opt, POPT_EN_MCD_GFX), + mee_onoff("32X enabled", MA_32XOPT_ENABLE_32X, PicoIn.opt, POPT_EN_32X), mee_end, }; static menu_entry *e_menu_table[] = { e_menu_options, + e_menu_ui_options, + e_menu_snd_options, e_menu_gfx_options, e_menu_adv_options, + e_menu_md_options, e_menu_cd_options, #ifndef NO_32X e_menu_32x_options, +#endif +#ifndef NO_SMS + e_menu_sms_options, #endif e_menu_keyconfig, e_menu_hidden, @@ -1222,7 +1544,7 @@ void menu_init(void) #if defined(_SVP_DRC) || defined(DRC_SH2) i = 1; #endif - me_enable(e_menu_adv_options, MA_OPT2_SVP_DYNAREC, i); + me_enable(e_menu_adv_options, MA_OPT2_DYNARECS, i); i = me_id2offset(e_menu_gfx_options, MA_OPT_VOUT_MODE); e_menu_gfx_options[i].data = plat_target.vout_methods;