#include "menu.h" #include #include #include #include #include #include #include "emumain.h" #include "shared.h" #include "psplib/pl_file.h" #include "psplib/image.h" #include "psplib/ui.h" #include "psplib/pl_menu.h" #include "psplib/ctrl.h" #include "psplib/pl_util.h" #include "psplib/pl_psp.h" #include "psplib/pl_ini.h" #include "psplib/pl_rewind.h" #define TAB_QUICKLOAD 0 #define TAB_STATE 1 #define TAB_CONTROL 2 #define TAB_OPTION 3 #define TAB_SYSTEM 4 #define TAB_ABOUT 5 #define TAB_MAX TAB_SYSTEM #define OPTION_DISPLAY_MODE 0x01 #define OPTION_SYNC_FREQ 0x02 #define OPTION_FRAMESKIP 0x03 #define OPTION_VSYNC 0x04 #define OPTION_CLOCK_FREQ 0x05 #define OPTION_SHOW_FPS 0x06 #define OPTION_CONTROL_MODE 0x07 #define OPTION_ANIMATE 0x08 #define OPTION_AUTOFIRE 0x09 #define OPTION_REWIND_SAVE_RATE 0x0A #define OPTION_REWIND_REPLAY_DELAY 0x0B #define SYSTEM_SCRNSHOT 0x11 #define SYSTEM_RESET 0x12 #define SYSTEM_VERT_STRIP 0x13 #define SYSTEM_SOUND_ENGINE 0x14 #define SYSTEM_SOUND_BOOST 0x15 extern PspImage *Screen; extern pl_rewind Rewinder; EmulatorOptions Options; static int ControlsModified; static int TabIndex; static int ResumeEmulation; static PspImage *Background; static PspImage *NoSaveIcon; static const char *QuickloadFilter[] = { "BIN", "SMS", "GG", "ZIP", '\0' }, PresentSlotText[] = "\026\244\020 Save\t\026\001\020 Load\t\026\243\020 Delete", EmptySlotText[] = "\026\244\020 Save", ControlHelpText[] = "\026\250\020 Change mapping\t\026\243\020 Load defaults"; pl_file_path CurrentGame = "", GamePath, SaveStatePath, ScreenshotPath; #define SET_AS_CURRENT_GAME(filename) \ strncpy(CurrentGame, filename, sizeof(CurrentGame) - 1) #define CURRENT_GAME (CurrentGame) #define GAME_LOADED (CurrentGame[0] != '\0') #define WIDTH 256 #define HEIGHT 192 /* Tab labels */ static const char *TabLabel[] = { "Game", "Save/Load", "Controls", "Options", "System", "About" }; static void LoadOptions(); static int SaveOptions(); static void InitButtonConfig(); static int SaveButtonConfig(); static int LoadButtonConfig(); static void DisplayStateTab(); static PspImage* LoadStateIcon(const char *path); static int LoadState(const char *path); static PspImage* SaveState(const char *path, PspImage *icon); static int OnMenuItemChanged(const struct PspUiMenu *uimenu, pl_menu_item* item, const pl_menu_option* option); static int OnMenuOk(const void *uimenu, const void* sel_item); static int OnMenuButtonPress(const struct PspUiMenu *uimenu, pl_menu_item* sel_item, u32 button_mask); static int OnSplashButtonPress(const struct PspUiSplash *splash, u32 button_mask); static void OnSplashRender(const void *uiobject, const void *null); static int OnGenericCancel(const void *uiobject, const void *param); static void OnGenericRender(const void *uiobject, const void *item_obj); static int OnGenericButtonPress(const PspUiFileBrowser *browser, const char *path, u32 button_mask); static int OnSaveStateOk(const void *gallery, const void *item); static int OnSaveStateButtonPress(const PspUiGallery *gallery, pl_menu_item* item, u32 button_mask); static int OnQuickloadOk(const void *browser, const void *path); void OnSystemRender(const void *uiobject, const void *item_obj); /* Menu options */ PL_MENU_OPTIONS_BEGIN(ToggleOptions) PL_MENU_OPTION("Disabled", 0) PL_MENU_OPTION("Enabled", 1) PL_MENU_OPTIONS_END PL_MENU_OPTIONS_BEGIN(ScreenSizeOptions) PL_MENU_OPTION("Actual size", DISPLAY_MODE_UNSCALED) PL_MENU_OPTION("4:3 scaled (2x)", DISPLAY_MODE_2X) PL_MENU_OPTION("4:3 scaled (3x)", DISPLAY_MODE_3X) PL_MENU_OPTION("4:3 scaled (fit height)", DISPLAY_MODE_FIT_HEIGHT) PL_MENU_OPTION("16:9 scaled (fit screen)", DISPLAY_MODE_FILL_SCREEN) PL_MENU_OPTIONS_END PL_MENU_OPTIONS_BEGIN(FrameLimitOptions) PL_MENU_OPTION("Disabled", 0) PL_MENU_OPTION("60 fps (NTSC)", 60) PL_MENU_OPTIONS_END PL_MENU_OPTIONS_BEGIN(FrameSkipOptions) PL_MENU_OPTION("No skipping", 0) PL_MENU_OPTION("Skip 1 frame", 1) PL_MENU_OPTION("Skip 2 frames", 2) PL_MENU_OPTION("Skip 3 frames", 3) PL_MENU_OPTION("Skip 4 frames", 4) PL_MENU_OPTION("Skip 5 frames", 5) PL_MENU_OPTIONS_END PL_MENU_OPTIONS_BEGIN(PspClockFreqOptions) PL_MENU_OPTION("222 MHz", 222) PL_MENU_OPTION("266 MHz", 266) PL_MENU_OPTION("300 MHz", 300) PL_MENU_OPTION("333 MHz", 333) PL_MENU_OPTIONS_END PL_MENU_OPTIONS_BEGIN(AutofireOptions) PL_MENU_OPTION("Once every 3 frames", 2) PL_MENU_OPTION("Once every 10 frames", 9) PL_MENU_OPTION("Once every 30 frames", 29) PL_MENU_OPTION("Once every 60 frames", 59) PL_MENU_OPTIONS_END PL_MENU_OPTIONS_BEGIN(ControlModeOptions) PL_MENU_OPTION("\026\242\020 cancels, \026\241\020 confirms (US)", 0) PL_MENU_OPTION("\026\241\020 cancels, \026\242\020 confirms (Japan)", 1) PL_MENU_OPTIONS_END PL_MENU_OPTIONS_BEGIN(RewindSaveRateOptions) PL_MENU_OPTION("Smoother", 2) PL_MENU_OPTION("Longer", 5) PL_MENU_OPTIONS_END PL_MENU_OPTIONS_BEGIN(RewindReplayDelayOptions) PL_MENU_OPTION("50 ms", 50) PL_MENU_OPTION("100 ms", 100) PL_MENU_OPTION("500 ms", 500) PL_MENU_OPTION("1 s", 1000) PL_MENU_OPTION("2 s", 2000) PL_MENU_OPTIONS_END PL_MENU_OPTIONS_BEGIN(ButtonMapOptions) /* Unmapped */ PL_MENU_OPTION("None", 0) /* Special */ PL_MENU_OPTION("Special: Open Menu", SPC|SPC_MENU) PL_MENU_OPTION("Special: Rewind", SPC|SPC_REWIND) /* Joystick */ PL_MENU_OPTION("Joystick Up", JOY|INPUT_UP) PL_MENU_OPTION("Joystick Down", JOY|INPUT_DOWN) PL_MENU_OPTION("Joystick Left", JOY|INPUT_LEFT) PL_MENU_OPTION("Joystick Right", JOY|INPUT_RIGHT) PL_MENU_OPTION("Joystick Button A", JOY|INPUT_A) PL_MENU_OPTION("Joystick Button B", JOY|INPUT_B) PL_MENU_OPTION("Joystick Button C", JOY|INPUT_C) PL_MENU_OPTION("Joystick Button I (autofire)", AFI|INPUT_BUTTON1) PL_MENU_OPTION("Joystick Button II (autofire)", AFI|INPUT_BUTTON2) /* Joystick */ PL_MENU_OPTION("Start (GG) / Pause (SMS)", JOY|INPUT_START) PL_MENU_OPTIONS_END /* Menu items */ PL_MENU_ITEMS_BEGIN(OptionMenuDef) PL_MENU_HEADER("Video") PL_MENU_ITEM("Screen size", OPTION_DISPLAY_MODE, ScreenSizeOptions, "\026\250\020 Change screen size") PL_MENU_HEADER("Input") PL_MENU_ITEM("Rate of autofire", OPTION_AUTOFIRE, AutofireOptions, "\026\250\020 Adjust rate of autofire") PL_MENU_HEADER("Performance") PL_MENU_ITEM("Frame limiter", OPTION_SYNC_FREQ, FrameLimitOptions, "\026\250\020 Change screen update frequency") PL_MENU_ITEM("Frame skipping", OPTION_FRAMESKIP, FrameSkipOptions, "\026\250\020 Change number of frames skipped per update") PL_MENU_ITEM("VSync", OPTION_VSYNC, ToggleOptions, "\026\250\020 Enable to reduce tearing; disable to increase speed") PL_MENU_ITEM("PSP clock frequency", OPTION_CLOCK_FREQ, PspClockFreqOptions, "\026\250\020 Larger values: faster emulation, faster battery depletion (default: 222MHz)") PL_MENU_ITEM("Show FPS counter", OPTION_SHOW_FPS, ToggleOptions, "\026\250\020 Show/hide the frames-per-second counter") /* PL_MENU_HEADER("Time rewind") PL_MENU_ITEM("Rewind recording mode", OPTION_REWIND_SAVE_RATE, RewindSaveRateOptions, "\026\250\020 Change rewind saving frequency") PL_MENU_ITEM("Rewind delay", OPTION_REWIND_REPLAY_DELAY, RewindReplayDelayOptions, "\026\250\020 Change delay between frames") */ PL_MENU_HEADER("Menu") PL_MENU_ITEM("Button mode", OPTION_CONTROL_MODE, ControlModeOptions, "\026\250\020 Change OK and Cancel button mapping") PL_MENU_ITEM("Animations", OPTION_ANIMATE, ToggleOptions, "\026\250\020 Enable/disable in-menu animations") PL_MENU_ITEMS_END PL_MENU_ITEMS_BEGIN(ControlMenuDef) PL_MENU_ITEM(PSP_CHAR_ANALUP, MAP_ANALOG_UP, ButtonMapOptions, ControlHelpText) PL_MENU_ITEM(PSP_CHAR_ANALDOWN, MAP_ANALOG_DOWN, ButtonMapOptions, ControlHelpText) PL_MENU_ITEM(PSP_CHAR_ANALLEFT, MAP_ANALOG_LEFT, ButtonMapOptions, ControlHelpText) PL_MENU_ITEM(PSP_CHAR_ANALRIGHT, MAP_ANALOG_RIGHT, ButtonMapOptions, ControlHelpText) PL_MENU_ITEM(PSP_CHAR_UP, MAP_BUTTON_UP, ButtonMapOptions, ControlHelpText) PL_MENU_ITEM(PSP_CHAR_DOWN, MAP_BUTTON_DOWN, ButtonMapOptions, ControlHelpText) PL_MENU_ITEM(PSP_CHAR_LEFT, MAP_BUTTON_LEFT, ButtonMapOptions, ControlHelpText) PL_MENU_ITEM(PSP_CHAR_RIGHT, MAP_BUTTON_RIGHT, ButtonMapOptions, ControlHelpText) PL_MENU_ITEM(PSP_CHAR_SQUARE, MAP_BUTTON_SQUARE, ButtonMapOptions, ControlHelpText) PL_MENU_ITEM(PSP_CHAR_CROSS, MAP_BUTTON_CROSS, ButtonMapOptions, ControlHelpText) PL_MENU_ITEM(PSP_CHAR_CIRCLE, MAP_BUTTON_CIRCLE, ButtonMapOptions, ControlHelpText) PL_MENU_ITEM(PSP_CHAR_TRIANGLE, MAP_BUTTON_TRIANGLE, ButtonMapOptions, ControlHelpText) PL_MENU_ITEM(PSP_CHAR_LTRIGGER, MAP_BUTTON_LTRIGGER, ButtonMapOptions, ControlHelpText) PL_MENU_ITEM(PSP_CHAR_RTRIGGER, MAP_BUTTON_RTRIGGER, ButtonMapOptions, ControlHelpText) PL_MENU_ITEM(PSP_CHAR_SELECT, MAP_BUTTON_SELECT, ButtonMapOptions, ControlHelpText) PL_MENU_ITEM(PSP_CHAR_START, MAP_BUTTON_START, ButtonMapOptions, ControlHelpText) PL_MENU_ITEM(PSP_CHAR_LTRIGGER"+"PSP_CHAR_RTRIGGER, MAP_BUTTON_LRTRIGGERS, ButtonMapOptions, ControlHelpText) PL_MENU_ITEM(PSP_CHAR_START"+"PSP_CHAR_SELECT, MAP_BUTTON_STARTSELECT, ButtonMapOptions, ControlHelpText) PL_MENU_ITEMS_END PL_MENU_ITEMS_BEGIN(SystemMenuDef) PL_MENU_HEADER("Video") PL_MENU_ITEM("Vertical bar", SYSTEM_VERT_STRIP, ToggleOptions, "\026\250\020 Show/hide the leftmost vertical bar (SMS)") PL_MENU_HEADER("System") PL_MENU_ITEM("Reset", SYSTEM_RESET, NULL, "\026\001\020 Reset") PL_MENU_ITEM("Save screenshot", SYSTEM_SCRNSHOT, NULL, "\026\001\020 Save screenshot") PL_MENU_ITEMS_END PspUiSplash SplashScreen = { OnSplashRender, OnGenericCancel, OnSplashButtonPress, NULL }; PspUiGallery SaveStateGallery = { OnGenericRender, /* OnRender() */ OnSaveStateOk, /* OnOk() */ OnGenericCancel, /* OnCancel() */ OnSaveStateButtonPress, /* OnButtonPress() */ NULL /* Userdata */ }; PspUiMenu OptionUiMenu = { OnGenericRender, /* OnRender() */ OnMenuOk, /* OnOk() */ OnGenericCancel, /* OnCancel() */ OnMenuButtonPress, /* OnButtonPress() */ OnMenuItemChanged, /* OnItemChanged() */ }; PspUiMenu ControlUiMenu = { OnGenericRender, /* OnRender() */ OnMenuOk, /* OnOk() */ OnGenericCancel, /* OnCancel() */ OnMenuButtonPress, /* OnButtonPress() */ OnMenuItemChanged, /* OnItemChanged() */ }; PspUiFileBrowser QuickloadBrowser = { OnGenericRender, OnQuickloadOk, OnGenericCancel, OnGenericButtonPress, QuickloadFilter, 0 }; PspUiMenu SystemUiMenu = { OnSystemRender, /* OnRender() */ OnMenuOk, /* OnOk() */ OnGenericCancel, /* OnCancel() */ OnMenuButtonPress, /* OnButtonPress() */ OnMenuItemChanged, /* OnItemChanged() */ }; /* Game configuration (includes button maps) */ struct ButtonConfig ActiveConfig; /* Default configuration */ struct ButtonConfig DefaultConfig = { { JOY|INPUT_UP, /* Analog Up */ JOY|INPUT_DOWN, /* Analog Down */ JOY|INPUT_LEFT, /* Analog Left */ JOY|INPUT_RIGHT, /* Analog Right */ JOY|INPUT_UP, /* D-pad Up */ JOY|INPUT_DOWN, /* D-pad Down */ JOY|INPUT_LEFT, /* D-pad Left */ JOY|INPUT_RIGHT, /* D-pad Right */ JOY|INPUT_A,/* Square */ JOY|INPUT_B,/* Cross */ JOY|INPUT_C,/* Circle */ 0, /* Triangle */ 0, /* L Trigger */ 0, /* R Trigger */ 0, /* Select */ JOY|INPUT_START, /* Start */ SPC|SPC_MENU, /* L+R Triggers */ 0, /* Start+Select */ } }; /* Button masks */ const u64 ButtonMask[] = { PSP_CTRL_LTRIGGER | PSP_CTRL_RTRIGGER, PSP_CTRL_START | PSP_CTRL_SELECT, PSP_CTRL_ANALUP, PSP_CTRL_ANALDOWN, PSP_CTRL_ANALLEFT, PSP_CTRL_ANALRIGHT, PSP_CTRL_UP, PSP_CTRL_DOWN, PSP_CTRL_LEFT, PSP_CTRL_RIGHT, PSP_CTRL_SQUARE, PSP_CTRL_CROSS, PSP_CTRL_CIRCLE, PSP_CTRL_TRIANGLE, PSP_CTRL_LTRIGGER, PSP_CTRL_RTRIGGER, PSP_CTRL_SELECT, PSP_CTRL_START, 0 /* End */ }; /* Button map ID's */ const int ButtonMapId[] = { MAP_BUTTON_LRTRIGGERS, MAP_BUTTON_STARTSELECT, MAP_ANALOG_UP, MAP_ANALOG_DOWN, MAP_ANALOG_LEFT, MAP_ANALOG_RIGHT, MAP_BUTTON_UP, MAP_BUTTON_DOWN, MAP_BUTTON_LEFT, MAP_BUTTON_RIGHT, MAP_BUTTON_SQUARE, MAP_BUTTON_CROSS, MAP_BUTTON_CIRCLE, MAP_BUTTON_TRIANGLE, MAP_BUTTON_LTRIGGER, MAP_BUTTON_RTRIGGER, MAP_BUTTON_SELECT, MAP_BUTTON_START, -1 /* End */ }; void InitMenu() { /* Reset variables */ TabIndex = TAB_ABOUT; Background = NULL; /* Initialize paths */ sprintf(SaveStatePath, "%ssavedata/", pl_psp_get_app_directory()); sprintf(ScreenshotPath, "%sscreenshot/", pl_psp_get_app_directory()); sprintf(GamePath, "%s", pl_psp_get_app_directory()); if (!pl_file_exists(SaveStatePath)) pl_file_mkdir_recursive(SaveStatePath); /* Initialize options */ LoadOptions(); InitEmulator(); /* Load the background image */ pl_file_path background; snprintf(background, sizeof(background) - 1, "%sbackground.png", pl_psp_get_app_directory()); Background = pspImageLoadPng(background); //Background = pspImageLoadPng("background.png"); /* Init NoSaveState icon image */ NoSaveIcon = pspImageCreate(136, 114, PSP_IMAGE_16BPP); pspImageClear(NoSaveIcon, RGB(0x0c,0,0x3f)); /* Initialize state menu */ int i; pl_menu_item *item; for (i = 0; i < 10; i++) { item = pl_menu_append_item(&SaveStateGallery.Menu, i, NULL); pl_menu_set_item_help_text(item, EmptySlotText); } /* Initialize menus */ pl_menu_create(&SystemUiMenu.Menu, SystemMenuDef); pl_menu_create(&OptionUiMenu.Menu, OptionMenuDef); pl_menu_create(&ControlUiMenu.Menu, ControlMenuDef); /* Load default configuration */ LoadButtonConfig(); /* Initialize UI components */ UiMetric.Background = Background; UiMetric.Font = &PspStockFont; UiMetric.Left = 16; UiMetric.Top = 48; UiMetric.Right = 944; UiMetric.Bottom = 500; UiMetric.OkButton = (!Options.ControlMode) ? PSP_CTRL_CROSS : PSP_CTRL_CIRCLE; UiMetric.CancelButton = (!Options.ControlMode) ? PSP_CTRL_CIRCLE : PSP_CTRL_CROSS; UiMetric.ScrollbarColor = PSP_COLOR_GRAY; UiMetric.ScrollbarBgColor = 0x44ffffff; UiMetric.ScrollbarWidth = 10; UiMetric.TextColor = PSP_COLOR_GRAY; UiMetric.SelectedColor = PSP_COLOR_YELLOW; UiMetric.SelectedBgColor = COLOR(0xff,0xff,0xff,0x44); UiMetric.StatusBarColor = PSP_COLOR_WHITE; UiMetric.BrowserFileColor = PSP_COLOR_GRAY; UiMetric.BrowserDirectoryColor = PSP_COLOR_YELLOW; UiMetric.GalleryIconsPerRow = 5; UiMetric.GalleryIconMarginWidth = 8; UiMetric.MenuItemMargin = 20; UiMetric.MenuSelOptionBg = PSP_COLOR_BLACK; UiMetric.MenuOptionBoxColor = PSP_COLOR_GRAY; UiMetric.MenuOptionBoxBg = COLOR(0, 0, 33, 0xBB); UiMetric.MenuDecorColor = PSP_COLOR_YELLOW; UiMetric.DialogFogColor = COLOR(0, 0, 0, 88); UiMetric.TitlePadding = 4; UiMetric.TitleColor = PSP_COLOR_WHITE; UiMetric.MenuFps = 30; UiMetric.TabBgColor = COLOR(0x74,0x74,0xbe,0xff); UiMetric.BrowserScreenshotPath = ScreenshotPath; UiMetric.BrowserScreenshotDelay = 30; } void DisplayMenu() { int i; pl_menu_item *item; /* Menu loop */ do { ResumeEmulation = 0; /* Set normal clock frequency */ //pl_psp_set_clock_freq(222); /* Set buttons to autorepeat */ pspCtrlSetPollingMode(PSP_CTRL_AUTOREPEAT); do { /* Display appropriate tab */ switch (TabIndex) { case TAB_STATE: DisplayStateTab(); break; case TAB_CONTROL: /* Load current button mappings */ for (item = ControlUiMenu.Menu.items, i = 0; item; item = item->next, i++) pl_menu_select_option_by_value(item, (void*)ActiveConfig.ButtonMap[i]); ControlsModified = 0; pspUiOpenMenu(&ControlUiMenu, NULL); if (ControlsModified) SaveButtonConfig(); break; case TAB_QUICKLOAD: pspUiOpenBrowser(&QuickloadBrowser, (GAME_LOADED) ? CURRENT_GAME : GamePath); break; case TAB_SYSTEM: item = pl_menu_find_item_by_id(&SystemUiMenu.Menu, SYSTEM_VERT_STRIP); pl_menu_select_option_by_value(item, (void*)Options.VertStrip); pspUiOpenMenu(&SystemUiMenu, NULL); break; case TAB_OPTION: /* Init menu options */ item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_DISPLAY_MODE); pl_menu_select_option_by_value(item, (void*)Options.DisplayMode); item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_SYNC_FREQ); pl_menu_select_option_by_value(item, (void*)Options.UpdateFreq); item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_FRAMESKIP); pl_menu_select_option_by_value(item, (void*)(int)Options.Frameskip); item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_VSYNC); pl_menu_select_option_by_value(item, (void*)Options.VSync); item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_CLOCK_FREQ); pl_menu_select_option_by_value(item, (void*)Options.ClockFreq); item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_SHOW_FPS); pl_menu_select_option_by_value(item, (void*)Options.ShowFps); item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_CONTROL_MODE); pl_menu_select_option_by_value(item, (void*)Options.ControlMode); item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_ANIMATE); pl_menu_select_option_by_value(item, (void*)UiMetric.Animate); item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_AUTOFIRE); pl_menu_select_option_by_value(item, (void*)Options.AutoFire); if ((item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_REWIND_SAVE_RATE))) pl_menu_select_option_by_value(item, (void*)Options.RewindSaveRate); if ((item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_REWIND_REPLAY_DELAY))) pl_menu_select_option_by_value(item, (void*)Options.RewindReplayDelay); pspUiOpenMenu(&OptionUiMenu, NULL); break; case TAB_ABOUT: pspUiSplashScreen(&SplashScreen); break; } } while (!ExitPSP && !ResumeEmulation); if (!ExitPSP) { /* Set clock frequency during emulation */ //pl_psp_set_clock_freq(Options.ClockFreq); /* Set buttons to normal mode */ pspCtrlSetPollingMode(PSP_CTRL_NORMAL); /* Resume emulation */ if (ResumeEmulation) { if (UiMetric.Animate) pspUiFadeout(); RunEmulator(); if (UiMetric.Animate) pspUiFadeout(); } } } while (!ExitPSP); } int OnGenericCancel(const void *uiobject, const void* param) { if (GAME_LOADED) ResumeEmulation = 1; return 1; } void OnSplashRender(const void *splash, const void *null) { int fh, i, x, y, height; const char *lines[] = { PSP_APP_NAME" version "PSP_APP_VER" ("__DATE__")", "\026https://github.com/frangarcj/Genesis-Plus-GX", " ", "2015 Frangarcj", "2006 eke-eke", "1998-2004 Charles MacDonald", NULL }; fh = pspFontGetLineHeight(UiMetric.Font); for (i = 0; lines[i]; i++); height = fh * (i - 1); /* Render lines */ for (i = 0, y = SCR_HEIGHT / 2 - height / 2; lines[i]; i++, y += fh) { x = SCR_WIDTH / 2 - pspFontGetTextWidth(UiMetric.Font, lines[i]) / 2; pspVideoPrint(UiMetric.Font, x, y, lines[i], PSP_COLOR_GRAY); } /* Render PSP status */ OnGenericRender(splash, null); } int OnSplashButtonPress(const struct PspUiSplash *splash, u32 button_mask) { return OnGenericButtonPress(NULL, NULL, button_mask); } /* Handles drawing of generic items */ void OnGenericRender(const void *uiobject, const void *item_obj) { /* Draw tabs */ int height = pspFontGetLineHeight(UiMetric.Font); int width; int i, x; for (i = 0, x = 5; i <= TAB_MAX; i++, x += width + 10) { width = -10; if (!GAME_LOADED && (i == TAB_STATE || i == TAB_SYSTEM)) continue; /* Determine width of text */ width = pspFontGetTextWidth(UiMetric.Font, TabLabel[i]); /* Draw background of active tab */ if (i == TabIndex) pspVideoFillRect(x - 5, 0, x + width + 5, height + 1, UiMetric.TabBgColor); /* Draw name of tab */ pspVideoPrint(UiMetric.Font, x, 0, TabLabel[i], PSP_COLOR_WHITE); } } int OnGenericButtonPress(const PspUiFileBrowser *browser, const char *path, u32 button_mask) { int tab_index; /* If L or R are pressed, switch tabs */ if (button_mask & PSP_CTRL_LTRIGGER) { TabIndex--; do { tab_index = TabIndex; if (!GAME_LOADED && (TabIndex == TAB_STATE || TabIndex == TAB_SYSTEM)) TabIndex--; if (TabIndex < 0) TabIndex = TAB_MAX; } while (tab_index != TabIndex); } else if (button_mask & PSP_CTRL_RTRIGGER) { TabIndex++; do { tab_index = TabIndex; if (!GAME_LOADED && (TabIndex == TAB_STATE || TabIndex == TAB_SYSTEM)) TabIndex++; if (TabIndex > TAB_MAX) TabIndex = 0; } while (tab_index != TabIndex); } else if ((button_mask & (PSP_CTRL_START | PSP_CTRL_SELECT)) == (PSP_CTRL_START | PSP_CTRL_SELECT)) { if (pl_util_save_vram_seq(ScreenshotPath, "ui")) pspUiAlert("Saved successfully"); else pspUiAlert("ERROR: Not saved"); return 0; } else return 0; return 1; } int OnMenuItemChanged(const struct PspUiMenu *uimenu, pl_menu_item* item, const pl_menu_option* option) { if (uimenu == &ControlUiMenu) { ControlsModified = 1; ActiveConfig.ButtonMap[item->id] = (unsigned int)option->value; } else { switch(item->id) { case SYSTEM_VERT_STRIP: Options.VertStrip = (int)option->value; break; case OPTION_DISPLAY_MODE: Options.DisplayMode = (int)option->value; break; case OPTION_SYNC_FREQ: Options.UpdateFreq = (int)option->value; break; case OPTION_FRAMESKIP: Options.Frameskip = (int)option->value; break; case OPTION_VSYNC: Options.VSync = (int)option->value; break; case OPTION_CLOCK_FREQ: Options.ClockFreq = (int)option->value; break; case OPTION_SHOW_FPS: Options.ShowFps = (int)option->value; break; case OPTION_CONTROL_MODE: Options.ControlMode = (int)option->value; UiMetric.OkButton = (!(int)option->value) ? PSP_CTRL_CROSS : PSP_CTRL_CIRCLE; UiMetric.CancelButton = (!(int)option->value) ? PSP_CTRL_CIRCLE : PSP_CTRL_CROSS; break; case OPTION_ANIMATE: UiMetric.Animate = (int)option->value; break; case OPTION_AUTOFIRE: Options.AutoFire = (int)option->value; break; case OPTION_REWIND_SAVE_RATE: Options.RewindSaveRate = (int)option->value; break; case OPTION_REWIND_REPLAY_DELAY: Options.RewindReplayDelay = (int)option->value; break; } SaveOptions(); } return 1; } int OnMenuOk(const void *uimenu, const void* sel_item) { if (uimenu == &ControlUiMenu) { /* Save to MS */ if (SaveButtonConfig()) pspUiAlert("Changes saved"); else pspUiAlert("ERROR: Changes not saved"); } else if (uimenu == &SystemUiMenu) { switch (((const pl_menu_item*)sel_item)->id) { case SYSTEM_RESET: /* Reset system */ if (pspUiConfirm("Reset the system?")) { ResumeEmulation = 1; system_reset(); pl_rewind_reset(&Rewinder); return 1; } break; case SYSTEM_SCRNSHOT: /* Save screenshot */ if (!pl_util_save_image_seq(ScreenshotPath, pl_file_get_filename(CURRENT_GAME), Screen)) pspUiAlert("ERROR: Screenshot not saved"); else pspUiAlert("Screenshot saved successfully"); break; } } return 0; } int OnMenuButtonPress(const struct PspUiMenu *uimenu, pl_menu_item* sel_item, u32 button_mask) { if (uimenu == &ControlUiMenu) { if (button_mask & PSP_CTRL_TRIANGLE) { pl_menu_item *item; int i; /* Load default mapping */ InitButtonConfig(); ControlsModified = 1; /* Modify the menu */ for (item = ControlUiMenu.Menu.items, i = 0; item; item = item->next, i++) pl_menu_select_option_by_value(item, (void*)DefaultConfig.ButtonMap[i]); return 0; } } return OnGenericButtonPress(NULL, NULL, button_mask); } int OnQuickloadOk(const void *browser, const void *path) { int first_time = 0; if (!GAME_LOADED) first_time = 1; if (!load_rom((char*)path)) { pspUiAlert("Error loading cartridge"); return 0; } SET_AS_CURRENT_GAME((char*)path); pl_file_get_parent_directory((const char*)path, GamePath, sizeof(GamePath)); /* Reset selected state */ SaveStateGallery.Menu.selected = NULL; if (first_time) { pspUiFlashMessage("Initializing for first-time use\nPlease wait..."); audio_init(SOUND_FREQUENCY, 0); system_init(); //error_init(); system_reset(); } else{ system_init(); system_reset(); audio_reset(); } pl_rewind_reset(&Rewinder); ResumeEmulation = 1; return 1; } int OnSaveStateOk(const void *gallery, const void *item) { if (!GAME_LOADED) return 0; char *path; const char *config_name = pl_file_get_filename(CURRENT_GAME); path = (char*)malloc(strlen(SaveStatePath) + strlen(config_name) + 8); sprintf(path, "%s%s.s%02i", SaveStatePath, config_name, ((const pl_menu_item*)item)->id); if (pl_file_exists(path) && pspUiConfirm("Load state?")) { if (LoadState(path)) { ResumeEmulation = 1; pl_rewind_reset(&Rewinder); pl_menu_find_item_by_id(&(((const PspUiGallery*)gallery)->Menu), ((const pl_menu_item*)item)->id); free(path); return 1; } pspUiAlert("ERROR: State failed to load"); } free(path); return 0; } int OnSaveStateButtonPress(const PspUiGallery *gallery, pl_menu_item *sel, u32 button_mask) { if (!GAME_LOADED) return 0; if (button_mask & PSP_CTRL_SQUARE || button_mask & PSP_CTRL_TRIANGLE) { char caption[32]; char *path; const char *config_name = pl_file_get_filename(CURRENT_GAME); path = (char*)malloc(strlen(SaveStatePath) + strlen(config_name) + 8); sprintf(path, "%s%s.s%02i", SaveStatePath, config_name, sel->id); do /* not a real loop; flow control construct */ { if (button_mask & PSP_CTRL_SQUARE) { if (pl_file_exists(path) && !pspUiConfirm("Overwrite existing state?")) break; pspUiFlashMessage("Saving, please wait ..."); PspImage *icon; if (!(icon = SaveState(path, Screen))) { pspUiAlert("ERROR: State not saved"); break; } SceIoStat stat; /* Trash the old icon (if any) */ if (sel->param && sel->param != NoSaveIcon) pspImageDestroy((PspImage*)sel->param); /* Update icon, help text */ sel->param = icon; pl_menu_set_item_help_text(sel, PresentSlotText); /* Get file modification time/date */ if (sceIoGetstat(path, &stat) < 0) sprintf(caption, "ERROR"); else sprintf(caption, "%02i/%02i/%02i %02i:%02i", stat.st_mtime.month, stat.st_mtime.day, stat.st_mtime.year - (stat.st_mtime.year / 100) * 100, stat.st_mtime.hour, stat.st_mtime.minute); pl_menu_set_item_caption(sel, caption); } else if (button_mask & PSP_CTRL_TRIANGLE) { if (!pl_file_exists(path) || !pspUiConfirm("Delete state?")) break; if (!pl_file_rm(path)) { pspUiAlert("ERROR: State not deleted"); break; } /* Trash the old icon (if any) */ if (sel->param && sel->param != NoSaveIcon) pspImageDestroy((PspImage*)sel->param); /* Update icon, caption */ sel->param = NoSaveIcon; pl_menu_set_item_help_text(sel, EmptySlotText); pl_menu_set_item_caption(sel, "Empty"); } } while (0); if (path) free(path); return 0; } return OnGenericButtonPress(NULL, NULL, button_mask); } /* Handles any special drawing for the system menu */ void OnSystemRender(const void *uiobject, const void *item_obj) { int w, h, x, y; w = Screen->Viewport.Width*1.5; h = Screen->Viewport.Height*1.5; x = SCR_WIDTH - w - 16; y = SCR_HEIGHT - h - 80; /* Draw a small representation of the screen */ pspVideoShadowRect(x, y, x + w - 1, y + h - 1, PSP_COLOR_BLACK, 3); pspVideoPutImage(Screen, x, y, w, h); pspVideoDrawRect(x, y, x + w - 1, y + h - 1, PSP_COLOR_GRAY); OnGenericRender(uiobject, item_obj); } static void DisplayStateTab() { if (!GAME_LOADED) { TabIndex++; return; } pl_menu_item *item, *sel; SceIoStat stat; char caption[32]; ScePspDateTime latest; const char *config_name = pl_file_get_filename(CURRENT_GAME); char *path = (char*)malloc(strlen(SaveStatePath) + strlen(config_name) + 8); char *game_name = strdup(config_name); char *dot = strrchr(game_name, '.'); if (dot) *dot='\0'; memset(&latest, 0, sizeof(latest)); /* Initialize icons */ sel = SaveStateGallery.Menu.items; for (item = SaveStateGallery.Menu.items; item; item = item->next) { sprintf(path, "%s%s.s%02i", SaveStatePath, config_name, item->id); if (pl_file_exists(path)) { if (sceIoGetstat(path, &stat) < 0) sprintf(caption, "ERROR"); else { /* Determine the latest save state */ if (pl_util_date_compare(&latest, &stat.st_mtime) < 0) { sel = item; latest = stat.st_mtime; } sprintf(caption, "%02i/%02i/%02i %02i:%02i", stat.st_mtime.month, stat.st_mtime.day, stat.st_mtime.year - (stat.st_mtime.year / 100) * 100, stat.st_mtime.hour, stat.st_mtime.minute); } pl_menu_set_item_caption(item, caption); item->param = LoadStateIcon(path); pl_menu_set_item_help_text(item, PresentSlotText); } else { pl_menu_set_item_caption(item, "Empty"); item->param = NoSaveIcon; pl_menu_set_item_help_text(item, EmptySlotText); } } free(path); /* Highlight the latest save state if none are selected */ if (SaveStateGallery.Menu.selected == NULL) SaveStateGallery.Menu.selected = sel; pspUiOpenGallery(&SaveStateGallery, game_name); free(game_name); /* Destroy any icons */ for (item = SaveStateGallery.Menu.items; item; item = item->next) if (item->param != NULL && item->param != NoSaveIcon) pspImageDestroy((PspImage*)item->param); } /* Initialize game configuration */ static void InitButtonConfig() { memcpy(&ActiveConfig, &DefaultConfig, sizeof(struct ButtonConfig)); } /* Load game configuration */ static int LoadButtonConfig() { pl_file_path path; snprintf(path, sizeof(path) - 1, "%sbuttons.cnf", pl_psp_get_app_directory()); /* Open file for reading */ FILE *file = fopen(path, "r"); /* If no configuration, load defaults */ if (!file) { InitButtonConfig(); return 1; } /* Read contents of struct */ int nread = fread(&ActiveConfig, sizeof(struct ButtonConfig), 1, file); fclose(file); if (nread != 1) { InitButtonConfig(); return 0; } return 1; } /* Save game configuration */ static int SaveButtonConfig() { pl_file_path path; snprintf(path, sizeof(path) - 1, "%sbuttons.cnf", pl_psp_get_app_directory()); /* Open file for writing */ FILE *file = fopen(path, "w"); if (!file) return 0; /* Write contents of struct */ int nwritten = fwrite(&ActiveConfig, sizeof(struct ButtonConfig), 1, file); fclose(file); return (nwritten == 1); } /* Load options */ void LoadOptions() { pl_file_path path; snprintf(path, sizeof(path) - 1, "%ssmsplus.ini", pl_psp_get_app_directory()); /* Initialize INI structure */ pl_ini_file init; pl_ini_load(&init, path); /* Load values */ Options.DisplayMode = pl_ini_get_int(&init, "Video", "Display Mode", DISPLAY_MODE_2X); Options.UpdateFreq = pl_ini_get_int(&init, "Video", "Update Frequency", 60); Options.Frameskip = pl_ini_get_int(&init, "Video", "Frameskip", 0); Options.VSync = pl_ini_get_int(&init, "Video", "VSync", 0); Options.ClockFreq = pl_ini_get_int(&init, "Video", "PSP Clock Frequency", 333); Options.ShowFps = pl_ini_get_int(&init, "Video", "Show FPS", 0); Options.ControlMode = pl_ini_get_int(&init, "Menu", "Control Mode", 0); UiMetric.Animate = pl_ini_get_int(&init, "Menu", "Animate", 1); Options.VertStrip = pl_ini_get_int(&init, "Game", "Vertical Strip", 1); Options.AutoFire = pl_ini_get_int(&init, "Input", "Autofire", 2); Options.RewindSaveRate = pl_ini_get_int(&init, "Enhancements", "Rewind Save Rate", 5); Options.RewindReplayDelay = pl_ini_get_int(&init, "Enhancements", "Rewind Replay Delay", 50); pl_ini_get_string(&init, "File", "Game Path", NULL, GamePath, sizeof(GamePath)); /* Clean up */ pl_ini_destroy(&init); } /* Save options */ static int SaveOptions() { pl_file_path path; snprintf(path, sizeof(path) - 1, "%ssmsplus.ini", pl_psp_get_app_directory()); /* Initialize INI structure */ pl_ini_file init; pl_ini_create(&init); /* Set values */ pl_ini_set_int(&init, "Video", "Display Mode", Options.DisplayMode); pl_ini_set_int(&init, "Video", "Update Frequency", Options.UpdateFreq); pl_ini_set_int(&init, "Video", "Frameskip", Options.Frameskip); pl_ini_set_int(&init, "Video", "VSync", Options.VSync); pl_ini_set_int(&init, "Video", "PSP Clock Frequency",Options.ClockFreq); pl_ini_set_int(&init, "Video", "Show FPS", Options.ShowFps); pl_ini_set_int(&init, "Menu", "Control Mode", Options.ControlMode); pl_ini_set_int(&init, "Menu", "Animate", UiMetric.Animate); pl_ini_set_int(&init, "Game", "Vertical Strip", Options.VertStrip); pl_ini_set_int(&init, "Input", "Autofire", Options.AutoFire); pl_ini_set_int(&init, "Enhancements", "Rewind Save Rate", Options.RewindSaveRate); pl_ini_set_int(&init, "Enhancements", "Rewind Replay Delay", Options.RewindReplayDelay); pl_ini_set_string(&init, "File", "Game Path", GamePath); /* Save INI file */ int status = pl_ini_save(&init, path); /* Clean up */ pl_ini_destroy(&init); return status; } /* Load state icon */ PspImage* LoadStateIcon(const char *path) { /* Open file for reading */ FILE *f = fopen(path, "r"); if (!f) return NULL; /* Load image */ PspImage *image = pspImageLoadPngFd(f); fclose(f); return image; } /* Load state */ int LoadState(const char *path) { /* Open file for reading */ FILE *f = fopen(path, "r"); if (!f) return 0; /* Load image into temporary object */ PspImage *image = pspImageLoadPngFd(f); pspImageDestroy(image); //system_load_state(f); fclose(f); return 1; } /* Save state */ PspImage* SaveState(const char *path, PspImage *icon) { /* Open file for writing */ FILE *f; if (!(f = fopen(path, "w"))) return NULL; /* Create thumbnail */ PspImage *thumb; thumb = (icon->Viewport.Width < 200) ? pspImageCreateCopy(icon) : pspImageCreateThumbnail(icon); if (!thumb) { fclose(f); return NULL; } /* Write the thumbnail */ if (!pspImageSavePngFd(f, thumb)) { pspImageDestroy(thumb); fclose(f); return NULL; } /* Save state */ //system_save_state(f); fclose(f); return thumb; } /* Release menu resources */ void TrashMenu() { TrashEmulator(); /* Save options */ SaveOptions(); /* Trash menus */ pl_menu_destroy(&SystemUiMenu.Menu); pl_menu_destroy(&OptionUiMenu.Menu); pl_menu_destroy(&ControlUiMenu.Menu); pl_menu_destroy(&SaveStateGallery.Menu); /* Trash images */ if (Background) pspImageDestroy(Background); if (NoSaveIcon) pspImageDestroy(NoSaveIcon); } /* Save or load SRAM */ void system_manage_sram(uint8 *sram, int slot, int mode) { FILE *fd; const char *config_name = pl_file_get_filename(CURRENT_GAME); char *path = (char*)malloc(sizeof(char) * (strlen(SaveStatePath) + strlen(config_name) + 8)); sprintf(path, "%s%s.srm", SaveStatePath, config_name); /*switch(mode) { case SRAM_SAVE: if(sms.save) { fd = fopen(path, "w"); if(fd) { fwrite(sram, 0x8000, 1, fd); fclose(fd); } } break; case SRAM_LOAD: fd = fopen(path, "r"); if(fd) { sms.save = 1; fread(sram, 0x8000, 1, fd); fclose(fd); } else {*/ /* No SRAM file, so initialize memory */ /* memset(sram, 0x00, 0x8000); } break; } */ free(path); }