Genesis-Plus-GX/psp2/menu.c

1290 lines
37 KiB
C

#include "menu.h"
#include <time.h>
#include <psp2/types.h>
#include <psp2/rtc.h>
#include <malloc.h>
#include <string.h>
#include <psp2/io/stat.h>
#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_OPTION("444 MHz", 444)
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", 444);
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);
}