3 * Copyright (C) 2006 Exophase <exophase@gmail.com>
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public Licens e as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33 // Blatantly stolen and trimmed from MZX (megazeux.sourceforge.net)
37 #define FILE_LIST_ROWS ((int)((SDL_SCREEN_HEIGHT - 40) / FONT_HEIGHT))
38 #define FILE_LIST_POSITION 5
39 #define DIR_LIST_POSITION 260
43 #define FILE_LIST_ROWS 25
44 #define FILE_LIST_POSITION 5
45 #define DIR_LIST_POSITION 360
51 #define color16(red, green, blue) \
52 (blue << 11) | (green << 5) | red \
56 #define color16(red, green, blue) \
57 (red << 11) | (green << 5) | blue \
63 #define COLOR_BG color16(0, 0, 0)
67 #define COLOR_BG color16(2, 8, 10)
71 #define COLOR_ROM_INFO color16(22, 36, 26)
72 #define COLOR_ACTIVE_ITEM color16(31, 63, 31)
73 #define COLOR_INACTIVE_ITEM color16(13, 40, 18)
74 #define COLOR_FRAMESKIP_BAR color16(15, 31, 31)
75 #define COLOR_HELP_TEXT color16(16, 40, 24)
77 int sort_function(const void *dest_str_ptr, const void *src_str_ptr)
79 char *dest_str = *((char **)dest_str_ptr);
80 char *src_str = *((char **)src_str_ptr);
85 if(dest_str[0] == '.')
88 return strcasecmp(dest_str, src_str);
91 s32 load_file(u8 **wildcards, u8 *result)
94 struct dirent *current_file;
95 struct stat file_info;
96 u8 current_dir_name[MAX_PATH];
97 u8 current_dir_short[81];
98 u32 current_dir_length;
99 u32 total_filenames_allocated;
100 u32 total_dirnames_allocated;
106 u32 file_name_length;
108 u32 chosen_file, chosen_dir;
109 u32 dialog_result = 1;
110 s32 return_value = 1;
111 u32 current_file_selection;
112 u32 current_file_scroll_value;
113 u32 current_dir_selection;
114 u32 current_dir_scroll_value;
115 u32 current_file_in_scroll;
116 u32 current_dir_in_scroll;
117 u32 current_file_number, current_dir_number;
118 u32 current_column = 0;
121 gui_action_type gui_action;
123 while(return_value == 1)
125 current_file_selection = 0;
126 current_file_scroll_value = 0;
127 current_dir_selection = 0;
128 current_dir_scroll_value = 0;
129 current_file_in_scroll = 0;
130 current_dir_in_scroll = 0;
132 total_filenames_allocated = 32;
133 total_dirnames_allocated = 32;
134 file_list = (u8 **)malloc(sizeof(u8 *) * 32);
135 dir_list = (u8 **)malloc(sizeof(u8 *) * 32);
136 memset(file_list, 0, sizeof(u8 *) * 32);
137 memset(dir_list, 0, sizeof(u8 *) * 32);
144 getcwd(current_dir_name, MAX_PATH);
146 current_dir = opendir(current_dir_name);
151 current_file = readdir(current_dir);
157 file_name = current_file->d_name;
158 file_name_length = strlen(file_name);
160 if((stat(file_name, &file_info) >= 0) &&
161 ((file_name[0] != '.') || (file_name[1] == '.')))
163 if(S_ISDIR(file_info.st_mode))
166 (u8 *)malloc(file_name_length + 1);
168 sprintf(dir_list[num_dirs], "%s", file_name);
174 // Must match one of the wildcards, also ignore the .
175 if(file_name_length >= 4)
177 if(file_name[file_name_length - 4] == '.')
178 ext_pos = file_name_length - 4;
181 if(file_name[file_name_length - 3] == '.')
182 ext_pos = file_name_length - 3;
187 for(i = 0; wildcards[i] != NULL; i++)
189 if(!strcasecmp((file_name + ext_pos),
192 file_list[num_files] =
193 (u8 *)malloc(file_name_length + 1);
195 sprintf(file_list[num_files], "%s", file_name);
205 if(num_files == total_filenames_allocated)
207 file_list = (u8 **)realloc(file_list, sizeof(u8 *) *
208 total_filenames_allocated * 2);
209 memset(file_list + total_filenames_allocated, 0,
210 sizeof(u8 *) * total_filenames_allocated);
211 total_filenames_allocated *= 2;
214 if(num_dirs == total_dirnames_allocated)
216 dir_list = (u8 **)realloc(dir_list, sizeof(u8 *) *
217 total_dirnames_allocated * 2);
218 memset(dir_list + total_dirnames_allocated, 0,
219 sizeof(u8 *) * total_dirnames_allocated);
220 total_dirnames_allocated *= 2;
223 } while(current_file);
225 qsort((void *)file_list, num_files, sizeof(u8 *), sort_function);
226 qsort((void *)dir_list, num_dirs, sizeof(u8 *), sort_function);
228 closedir(current_dir);
230 current_dir_length = strlen(current_dir_name);
232 if(current_dir_length > 80)
236 snprintf(current_dir_short, 80,
237 "...%s", current_dir_name + current_dir_length - 77);
239 memcpy(current_dir_short, "...", 3);
240 memcpy(current_dir_short + 3,
241 current_dir_name + current_dir_length - 77, 77);
242 current_dir_short[80] = 0;
248 snprintf(current_dir_short, 80, "%s", current_dir_name);
250 memcpy(current_dir_short, current_dir_name,
251 current_dir_length + 1);
260 clear_screen(COLOR_BG);
268 print_string(current_dir_short, COLOR_ACTIVE_ITEM, COLOR_BG, 0, 0);
270 print_string("Press X to return to the main menu.",
271 COLOR_HELP_TEXT, COLOR_BG, 20, 220);
273 print_string("Press X to return to the main menu.",
274 COLOR_HELP_TEXT, COLOR_BG, 20, 260);
277 for(i = 0, current_file_number = i + current_file_scroll_value;
278 i < FILE_LIST_ROWS; i++, current_file_number++)
280 if(current_file_number < num_files)
282 if((current_file_number == current_file_selection) &&
283 (current_column == 0))
285 print_string(file_list[current_file_number], COLOR_ACTIVE_ITEM,
286 COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10));
290 print_string(file_list[current_file_number], COLOR_INACTIVE_ITEM,
291 COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10));
296 for(i = 0, current_dir_number = i + current_dir_scroll_value;
297 i < FILE_LIST_ROWS; i++, current_dir_number++)
299 if(current_dir_number < num_dirs)
301 if((current_dir_number == current_dir_selection) &&
302 (current_column == 1))
304 print_string(dir_list[current_dir_number], COLOR_ACTIVE_ITEM,
305 COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10));
309 print_string(dir_list[current_dir_number], COLOR_INACTIVE_ITEM,
310 COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10));
315 gui_action = get_gui_input();
320 if(current_column == 0)
322 if(current_file_selection < (num_files - 1))
324 current_file_selection++;
325 if(current_file_in_scroll == (FILE_LIST_ROWS - 1))
327 clear_screen(COLOR_BG);
328 current_file_scroll_value++;
332 current_file_in_scroll++;
338 if(current_dir_selection < (num_dirs - 1))
340 current_dir_selection++;
341 if(current_dir_in_scroll == (FILE_LIST_ROWS - 1))
343 clear_screen(COLOR_BG);
344 current_dir_scroll_value++;
348 current_dir_in_scroll++;
356 if(current_column == 0)
358 if(current_file_selection)
360 current_file_selection--;
361 if(current_file_in_scroll == 0)
363 clear_screen(COLOR_BG);
364 current_file_scroll_value--;
368 current_file_in_scroll--;
374 if(current_dir_selection)
376 current_dir_selection--;
377 if(current_dir_in_scroll == 0)
379 clear_screen(COLOR_BG);
380 current_dir_scroll_value--;
384 current_dir_in_scroll--;
391 if(current_column == 0)
399 if(current_column == 1)
407 if(current_column == 1)
410 chdir(dir_list[current_dir_selection]);
418 strcpy(result, file_list[current_file_selection]);
425 if(!strcmp(current_dir_name, "ms0:/PSP"))
440 for(i = 0; i < num_files; i++)
446 for(i = 0; i < num_dirs; i++)
453 clear_screen(COLOR_BG);
460 NUMBER_SELECTION_OPTION = 0x01,
461 STRING_SELECTION_OPTION = 0x02,
462 SUBMENU_OPTION = 0x04,
464 } menu_option_type_enum;
468 void (* init_function)();
469 void (* passive_function)();
470 struct _menu_option_type *options;
474 struct _menu_option_type
476 void (* action_function)();
477 void (* passive_function)();
478 struct _menu_type *sub_menu;
479 char *display_string;
485 menu_option_type_enum option_type;
488 typedef struct _menu_option_type menu_option_type;
489 typedef struct _menu_type menu_type;
491 #define make_menu(name, init_function, passive_function) \
492 menu_type name##_menu = \
497 sizeof(name##_options) / sizeof(menu_option_type) \
500 #define gamepad_config_option(display_string, number) \
503 menu_fix_gamepad_help, \
505 display_string ": %s", \
506 gamepad_config_buttons, \
507 gamepad_config_map + gamepad_config_line_to_button[number], \
508 sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \
509 gamepad_help[gamepad_config_map[ \
510 gamepad_config_line_to_button[number]]], \
512 STRING_SELECTION_OPTION \
515 #define analog_config_option(display_string, number) \
518 menu_fix_gamepad_help, \
520 display_string ": %s", \
521 gamepad_config_buttons, \
522 gamepad_config_map + number + 12, \
523 sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \
524 gamepad_help[gamepad_config_map[number + 12]], \
526 STRING_SELECTION_OPTION \
529 #define cheat_option(number) \
534 cheat_format_str[number], \
535 enable_disable_options, \
536 &(cheats[number].cheat_active), \
538 "Activate/deactivate this cheat code.", \
540 STRING_SELECTION_OPTION \
543 #define action_option(action_function, passive_function, display_string, \
544 help_string, line_number) \
558 #define submenu_option(sub_menu, display_string, help_string, line_number) \
566 sizeof(sub_menu) / sizeof(menu_option_type), \
572 #define selection_option(passive_function, display_string, options, \
573 option_ptr, num_options, help_string, line_number, type) \
587 #define action_selection_option(action_function, passive_function, \
588 display_string, options, option_ptr, num_options, help_string, line_number, \
600 type | ACTION_OPTION \
604 #define string_selection_option(passive_function, display_string, options, \
605 option_ptr, num_options, help_string, line_number) \
606 selection_option(passive_function, display_string ": %s", options, \
607 option_ptr, num_options, help_string, line_number, STRING_SELECTION_OPTION)\
609 #define numeric_selection_option(passive_function, display_string, \
610 option_ptr, num_options, help_string, line_number) \
611 selection_option(passive_function, display_string ": %d", NULL, option_ptr, \
612 num_options, help_string, line_number, NUMBER_SELECTION_OPTION) \
614 #define string_selection_action_option(action_function, passive_function, \
615 display_string, options, option_ptr, num_options, help_string, line_number) \
616 action_selection_option(action_function, passive_function, \
617 display_string ": %s", options, option_ptr, num_options, help_string, \
618 line_number, STRING_SELECTION_OPTION) \
620 #define numeric_selection_action_option(action_function, passive_function, \
621 display_string, option_ptr, num_options, help_string, line_number) \
622 action_selection_option(action_function, passive_function, \
623 display_string ": %d", NULL, option_ptr, num_options, help_string, \
624 line_number, NUMBER_SELECTION_OPTION) \
626 #define numeric_selection_action_hide_option(action_function, \
627 passive_function, display_string, option_ptr, num_options, help_string, \
629 action_selection_option(action_function, passive_function, \
630 display_string, NULL, option_ptr, num_options, help_string, \
631 line_number, NUMBER_SELECTION_OPTION) \
634 #define GAMEPAD_MENU_WIDTH 15
638 u32 gamepad_config_line_to_button[] =
639 { 8, 6, 7, 9, 1, 2, 3, 0, 4, 5, 11, 10 };
645 u32 gamepad_config_line_to_button[] =
646 { 0, 2, 1, 3, 8, 9, 10, 11, 6, 7, 4, 5 };
651 s32 load_game_config_file()
653 u8 game_config_filename[512];
656 change_ext(gamepak_filename, game_config_filename, ".cfg");
658 file_open(game_config_file, game_config_filename, read);
660 if(file_check_valid(game_config_file))
662 u32 file_size = file_length(game_config_filename, game_config_file);
664 // Sanity check: File size must be the right size
667 u32 file_options[file_size / 4];
669 file_read_array(game_config_file, file_options);
670 current_frameskip_type = file_options[0] % 3;
671 frameskip_value = file_options[1];
672 random_skip = file_options[2] % 2;
673 clock_speed = file_options[3];
675 if(clock_speed > 333)
681 if(frameskip_value < 0)
684 if(frameskip_value > 99)
685 frameskip_value = 99;
687 for(i = 0; i < 10; i++)
689 cheats[i].cheat_active = file_options[3 + i] % 2;
690 cheats[i].cheat_name[0] = 0;
693 file_close(game_config_file);
701 current_frameskip_type = auto_frameskip;
706 for(i = 0; i < 10; i++)
708 cheats[i].cheat_active = 0;
709 cheats[i].cheat_name[0] = 0;
715 s32 load_config_file()
719 #if (defined(PSP_BUILD) || defined(ARM_ARCH)) && !defined(_WIN32_WCE)
720 sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
722 sprintf(config_path, "%s\\%s", main_path, GPSP_CONFIG_FILENAME);
725 file_open(config_file, config_path, read);
727 if(file_check_valid(config_file))
729 u32 file_size = file_length(config_path, config_file);
731 // Sanity check: File size must be the right size
734 u32 file_options[file_size / 4];
736 s32 menu_button = -1;
737 file_read_array(config_file, file_options);
739 screen_scale = file_options[0] % 3;
740 screen_filter = file_options[1] % 2;
741 global_enable_audio = file_options[2] % 2;
744 audio_buffer_size_number = file_options[3] % 10;
746 audio_buffer_size_number = file_options[3] % 11;
749 update_backup_flag = file_options[4] % 2;
750 global_enable_analog = file_options[5] % 2;
751 analog_sensitivity_level = file_options[6] % 8;
754 scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2);
757 // Sanity check: Make sure there's a MENU or FRAMESKIP
758 // key, if not assign to triangle
761 for(i = 0; i < 16; i++)
763 gamepad_config_map[i] = file_options[7 + i] %
764 (BUTTON_ID_NONE + 1);
766 if(gamepad_config_map[i] == BUTTON_ID_MENU)
772 if(menu_button == -1)
774 gamepad_config_map[0] = BUTTON_ID_MENU;
778 file_close(config_file);
787 s32 save_game_config_file()
789 u8 game_config_filename[512];
792 change_ext(gamepak_filename, game_config_filename, ".cfg");
794 file_open(game_config_file, game_config_filename, write);
796 if(file_check_valid(game_config_file))
798 u32 file_options[14];
800 file_options[0] = current_frameskip_type;
801 file_options[1] = frameskip_value;
802 file_options[2] = random_skip;
803 file_options[3] = clock_speed;
805 for(i = 0; i < 10; i++)
807 file_options[4 + i] = cheats[i].cheat_active;
810 file_write_array(game_config_file, file_options);
812 file_close(game_config_file);
820 s32 save_config_file()
824 #if (defined(PSP_BUILD) || defined(ARM_ARCH)) && !defined(_WIN32_WCE)
825 sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
827 sprintf(config_path, "%s\\%s", main_path, GPSP_CONFIG_FILENAME);
830 file_open(config_file, config_path, write);
832 save_game_config_file();
834 if(file_check_valid(config_file))
836 u32 file_options[23];
839 file_options[0] = screen_scale;
840 file_options[1] = screen_filter;
841 file_options[2] = global_enable_audio;
842 file_options[3] = audio_buffer_size_number;
843 file_options[4] = update_backup_flag;
844 file_options[5] = global_enable_analog;
845 file_options[6] = analog_sensitivity_level;
848 for(i = 0; i < 16; i++)
850 file_options[7 + i] = gamepad_config_map[i];
854 file_write_array(config_file, file_options);
856 file_close(config_file);
873 u32 savestate_slot = 0;
875 void get_savestate_snapshot(u8 *savestate_filename)
877 u16 snapshot_buffer[240 * 160];
878 u8 savestate_timestamp_string[80];
880 file_open(savestate_file, savestate_filename, read);
882 if(file_check_valid(savestate_file))
884 u8 weekday_strings[7][11] =
886 "Sunday", "Monday", "Tuesday", "Wednesday",
887 "Thursday", "Friday", "Saturday"
889 time_t savestate_time_flat;
890 struct tm *current_time;
891 file_read_array(savestate_file, snapshot_buffer);
892 file_read_variable(savestate_file, savestate_time_flat);
894 file_close(savestate_file);
896 current_time = localtime(&savestate_time_flat);
897 sprintf(savestate_timestamp_string,
898 "%s %02d/%02d/%04d %02d:%02d:%02d ",
899 weekday_strings[current_time->tm_wday], current_time->tm_mon + 1,
900 current_time->tm_mday, current_time->tm_year + 1900,
901 current_time->tm_hour, current_time->tm_min, current_time->tm_sec);
903 savestate_timestamp_string[40] = 0;
904 print_string(savestate_timestamp_string, COLOR_HELP_TEXT, COLOR_BG,
909 memset(snapshot_buffer, 0, 240 * 160 * 2);
910 print_string_ext("No savestate exists for this slot.",
911 0xFFFF, 0x0000, 15, 75, snapshot_buffer, 240, 0);
912 print_string("---------- --/--/---- --:--:-- ", COLOR_HELP_TEXT,
917 blit_to_screen(snapshot_buffer, 240, 160, 230, 40);
921 void get_savestate_filename(u32 slot, u8 *name_buffer)
923 u8 savestate_ext[16];
925 sprintf(savestate_ext, "%d.svs", slot);
926 change_ext(gamepak_filename, name_buffer, savestate_ext);
928 get_savestate_snapshot(name_buffer);
931 void get_savestate_filename_noshot(u32 slot, u8 *name_buffer)
933 u8 savestate_ext[16];
935 sprintf(savestate_ext, "%d.svs", slot);
936 change_ext(gamepak_filename, name_buffer, savestate_ext);
942 invalidate_all_cache();
946 u32 menu(u16 *original_screen)
948 u32 clock_speed_number = (clock_speed / 33) - 1;
950 u32 _current_option = 0;
951 gui_action_type gui_action;
952 menu_enum _current_menu = MAIN_MENU;
955 u32 return_value = 0;
957 u8 savestate_ext[16];
958 u8 current_savestate_filename[512];
960 u8 cheat_format_str[10][41];
962 menu_type *current_menu;
963 menu_option_type *current_option;
964 menu_option_type *display_option;
965 u32 current_option_num;
967 auto void choose_menu();
968 auto void clear_help();
972 "Up button on GBA d-pad.",
973 "Down button on GBA d-pad.",
974 "Left button on GBA d-pad.",
975 "Right button on GBA d-pad.",
978 "Left shoulder button on GBA.",
979 "Right shoulder button on GBA.",
980 "Start button on GBA.",
981 "Select button on GBA.",
982 "Brings up the options menu.",
983 "Toggles fastforward on/off.",
984 "Loads the game state from the current slot.",
985 "Saves the game state to the current slot.",
986 "Rapidly press/release the A button on GBA.",
987 "Rapidly press/release the B button on GBA.",
988 "Rapidly press/release the L shoulder on GBA.",
989 "Rapidly press/release the R shoulder on GBA.",
990 "Increases the volume.",
991 "Decreases the volume.",
992 "Displays virtual/drawn frames per second.",
1004 clock_speed = (clock_speed_number + 1) * 33;
1011 u8 *file_ext[] = { ".gba", ".bin", ".zip", NULL };
1012 u8 load_filename[512];
1013 save_game_config_file();
1014 if(load_file(file_ext, load_filename) != -1)
1016 if(load_gamepak(load_filename) == -1)
1023 reg[CHANGED_PC_STATUS] = 1;
1027 choose_menu(current_menu);
1036 reg[CHANGED_PC_STATUS] = 1;
1042 void menu_change_state()
1044 get_savestate_filename(savestate_slot, current_savestate_filename);
1047 void menu_save_state()
1051 get_savestate_filename_noshot(savestate_slot,
1052 current_savestate_filename);
1053 save_state(current_savestate_filename, original_screen);
1055 menu_change_state();
1058 void menu_load_state()
1062 load_state(current_savestate_filename);
1068 void menu_load_state_file()
1070 u8 *file_ext[] = { ".svs", NULL };
1071 u8 load_filename[512];
1072 if(load_file(file_ext, load_filename) != -1)
1074 load_state(load_filename);
1080 choose_menu(current_menu);
1084 void menu_fix_gamepad_help()
1088 current_option->help_string =
1089 gamepad_help[gamepad_config_map[
1090 gamepad_config_line_to_button[current_option_num]]];
1094 void submenu_graphics_sound()
1099 void submenu_cheats_misc()
1104 void submenu_gamepad()
1109 void submenu_analog()
1114 void submenu_savestate()
1116 print_string("Savestate options:", COLOR_ACTIVE_ITEM, COLOR_BG, 10, 70);
1117 menu_change_state();
1122 strncpy(print_buffer, gamepak_filename, 80);
1123 print_string(print_buffer, COLOR_ROM_INFO, COLOR_BG, 10, 10);
1124 sprintf(print_buffer, "%s %s %s", gamepak_title,
1125 gamepak_code, gamepak_maker);
1126 print_string(print_buffer, COLOR_ROM_INFO, COLOR_BG, 10, 20);
1128 get_savestate_filename_noshot(savestate_slot,
1129 current_savestate_filename);
1132 u8 *yes_no_options[] = { "no", "yes" };
1133 u8 *enable_disable_options[] = { "disabled", "enabled" };
1135 u8 *scale_options[] =
1137 "unscaled 3:2", "scaled 3:2", "fullscreen 16:9"
1140 u8 *frameskip_options[] = { "automatic", "manual", "off" };
1141 u8 *frameskip_variation_options[] = { "uniform", "random" };
1144 u8 *audio_buffer_options[] =
1146 "16 bytes", "32 bytes", "64 bytes",
1147 "128 bytes", "256 bytes", "512 bytes", "1024 bytes", "2048 bytes",
1148 "4096 bytes", "8192 bytes", "16284 bytes"
1151 u8 *audio_buffer_options[] =
1153 "3072 bytes", "4096 bytes", "5120 bytes", "6144 bytes", "7168 bytes",
1154 "8192 bytes", "9216 bytes", "10240 bytes", "11264 bytes", "12288 bytes"
1159 u8 *update_backup_options[] = { "Exit only", "Automatic" };
1161 u8 *clock_speed_options[] =
1163 "33MHz", "66MHz", "100MHz", "133MHz", "166MHz", "200MHz", "233MHz",
1164 "266MHz", "300MHz", "333MHz"
1167 u8 *gamepad_config_buttons[] =
1193 // Marker for help information, don't go past this mark (except \n)------*
1194 menu_option_type graphics_sound_options[] =
1196 string_selection_option(NULL, "Display scaling", scale_options,
1197 (u32 *)(&screen_scale), 3,
1198 "Determines how the GBA screen is resized in relation to the entire\n"
1199 "screen. Select unscaled 3:2 for GBA resolution, scaled 3:2 for GBA\n"
1200 "aspect ratio scaled to fill the height of the PSP screen, and\n"
1201 "fullscreen to fill the entire PSP screen.", 2),
1202 string_selection_option(NULL, "Screen filtering", yes_no_options,
1203 (u32 *)(&screen_filter), 2,
1204 "Determines whether or not bilinear filtering should be used when\n"
1205 "scaling the screen. Selecting this will produce a more even and\n"
1206 "smooth image, at the cost of being blurry and having less vibrant\n"
1208 string_selection_option(NULL, "Frameskip type", frameskip_options,
1209 (u32 *)(¤t_frameskip_type), 3,
1210 "Determines what kind of frameskipping should be employed.\n"
1211 "Frameskipping may improve emulation speed of many games.\n"
1212 "Off: Do not skip any frames.\n"
1213 "Auto: Skip up to N frames (see next option) as needed.\n"
1214 "Manual: Always render only 1 out of N + 1 frames.", 5),
1215 numeric_selection_option(NULL, "Frameskip value", &frameskip_value, 100,
1216 "For auto frameskip, determines the maximum number of frames that\n"
1217 "are allowed to be skipped consecutively.\n"
1218 "For manual frameskip, determines the number of frames that will\n"
1219 "always be skipped.", 6),
1220 string_selection_option(NULL, "Framskip variation",
1221 frameskip_variation_options, &random_skip, 2,
1222 "If objects in the game flicker at a regular rate certain manual\n"
1223 "frameskip values may cause them to normally disappear. Change this\n"
1224 "value to 'random' to avoid this. Do not use otherwise, as it tends to\n"
1225 "make the image quality worse, especially in high motion games.", 7),
1226 string_selection_option(NULL, "Audio output", yes_no_options,
1227 &global_enable_audio, 2,
1228 "Select 'no' to turn off all audio output. This will not result in a\n"
1229 "significant change in performance.", 9),
1231 string_selection_option(NULL, "Audio buffer", audio_buffer_options,
1232 &audio_buffer_size_number, 11,
1234 string_selection_option(NULL, "Audio buffer", audio_buffer_options,
1235 &audio_buffer_size_number, 10,
1238 "Set the size (in bytes) of the audio buffer. Larger values may result\n"
1239 "in slightly better performance at the cost of latency; the lowest\n"
1240 "value will give the most responsive audio.\n"
1241 "This option requires gpSP to be restarted before it will take effect.",
1243 submenu_option(NULL, "Back", "Return to the main menu.", 12)
1246 make_menu(graphics_sound, submenu_graphics_sound, NULL);
1248 menu_option_type cheats_misc_options[] =
1260 string_selection_option(NULL, "Clock speed",
1261 clock_speed_options, &clock_speed_number, 10,
1262 "Change the clock speed of the device. Higher clock speed will yield\n"
1263 "better performance, but will use drain battery life further.", 11),
1264 string_selection_option(NULL, "Update backup",
1265 update_backup_options, &update_backup_flag, 2,
1266 "Determines when in-game save files should be written back to\n"
1267 "memstick. If set to 'automatic' writebacks will occur shortly after\n"
1268 "the game's backup is altered. On 'exit only' it will only be written\n"
1269 "back when you exit from this menu (NOT from using the home button).\n"
1270 "Use the latter with extreme care.", 12),
1271 submenu_option(NULL, "Back", "Return to the main menu.", 14)
1274 make_menu(cheats_misc, submenu_cheats_misc, NULL);
1276 menu_option_type savestate_options[] =
1278 numeric_selection_action_hide_option(menu_load_state, menu_change_state,
1279 "Load savestate from current slot", &savestate_slot, 10,
1280 "Select to load the game state from the current slot for this game.\n"
1281 "Press left + right to change the current slot.", 6),
1282 numeric_selection_action_hide_option(menu_save_state, menu_change_state,
1283 "Save savestate to current slot", &savestate_slot, 10,
1284 "Select to save the game state to the current slot for this game.\n"
1285 "Press left + right to change the current slot.", 7),
1286 numeric_selection_action_hide_option(menu_load_state_file,
1288 "Load savestate from file", &savestate_slot, 10,
1289 "Restore gameplay from a savestate file.\n"
1290 "Note: The same file used to save the state must be present.\n", 9),
1291 numeric_selection_option(menu_change_state,
1292 "Current savestate slot", &savestate_slot, 10,
1293 "Change the current savestate slot.\n", 11),
1294 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1297 make_menu(savestate, submenu_savestate, NULL);
1301 menu_option_type gamepad_config_options[] =
1303 gamepad_config_option("D-pad up ", 0),
1304 gamepad_config_option("D-pad down ", 1),
1305 gamepad_config_option("D-pad left ", 2),
1306 gamepad_config_option("D-pad right ", 3),
1307 gamepad_config_option("Circle ", 4),
1308 gamepad_config_option("Cross ", 5),
1309 gamepad_config_option("Square ", 6),
1310 gamepad_config_option("Triangle ", 7),
1311 gamepad_config_option("Left Trigger ", 8),
1312 gamepad_config_option("Right Trigger", 9),
1313 gamepad_config_option("Start ", 10),
1314 gamepad_config_option("Select ", 11),
1315 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1319 menu_option_type analog_config_options[] =
1321 analog_config_option("Analog up ", 0),
1322 analog_config_option("Analog down ", 1),
1323 analog_config_option("Analog left ", 2),
1324 analog_config_option("Analog right", 3),
1325 string_selection_option(NULL, "Enable analog", yes_no_options,
1326 &global_enable_analog, 2,
1327 "Select 'no' to block analog input entirely.", 7),
1328 numeric_selection_option(NULL, "Analog sensitivity",
1329 &analog_sensitivity_level, 10,
1330 "Determine sensitivity/responsiveness of the analog input.\n"
1331 "Lower numbers are less sensitive.", 8),
1332 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1339 menu_option_type gamepad_config_options[] =
1341 gamepad_config_option("D-pad up ", 0),
1342 gamepad_config_option("D-pad down ", 1),
1343 gamepad_config_option("D-pad left ", 2),
1344 gamepad_config_option("D-pad right ", 3),
1345 gamepad_config_option("A ", 4),
1346 gamepad_config_option("B ", 5),
1347 gamepad_config_option("X ", 6),
1348 gamepad_config_option("Y ", 7),
1349 gamepad_config_option("Left Trigger ", 8),
1350 gamepad_config_option("Right Trigger", 9),
1351 gamepad_config_option("Start ", 10),
1352 gamepad_config_option("Select ", 11),
1353 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1357 menu_option_type analog_config_options[] =
1359 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1366 menu_option_type gamepad_config_options[] =
1368 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1371 menu_option_type analog_config_options[] =
1373 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1378 make_menu(gamepad_config, submenu_gamepad, NULL);
1379 make_menu(analog_config, submenu_analog, NULL);
1381 menu_option_type main_options[] =
1383 submenu_option(&graphics_sound_menu, "Graphics and Sound options",
1384 "Select to set display parameters and frameskip behavior,\n"
1385 "audio on/off, audio buffer size, and audio filtering.", 0),
1386 numeric_selection_action_option(menu_load_state, NULL,
1387 "Load state from slot", &savestate_slot, 10,
1388 "Select to load the game state from the current slot for this game,\n"
1389 "if it exists (see the extended menu for more information)\n"
1390 "Press left + right to change the current slot.", 2),
1391 numeric_selection_action_option(menu_save_state, NULL,
1392 "Save state to slot", &savestate_slot, 10,
1393 "Select to save the game state to the current slot for this game.\n"
1394 "See the extended menu for more information.\n"
1395 "Press left + right to change the current slot.", 3),
1396 submenu_option(&savestate_menu, "Savestate options",
1397 "Select to enter a menu for loading, saving, and viewing the\n"
1398 "currently active savestate for this game (or to load a savestate\n"
1399 "file from another game)", 4),
1400 submenu_option(&gamepad_config_menu, "Configure gamepad input",
1401 "Select to change the in-game behavior of the PSP buttons and d-pad.",
1403 submenu_option(&analog_config_menu, "Configure analog input",
1404 "Select to change the in-game behavior of the PSP analog nub.", 7),
1405 submenu_option(&cheats_misc_menu, "Cheats and Miscellaneous options",
1406 "Select to manage cheats, set backup behavior, and set device clock\n"
1408 action_option(menu_load, NULL, "Load new game",
1409 "Select to load a new game (will exit a game if currently playing).",
1411 action_option(menu_restart, NULL, "Restart game",
1412 "Select to reset the GBA with the current game loaded.", 12),
1413 action_option(menu_exit, NULL, "Return to game",
1414 "Select to exit this menu and resume gameplay.", 13),
1415 action_option(menu_quit, NULL, "Exit gpSP",
1416 "Select to exit gpSP and return to the PSP XMB/loader.", 15)
1419 make_menu(main, submenu_main, NULL);
1421 void choose_menu(menu_type *new_menu)
1423 if(new_menu == NULL)
1424 new_menu = &main_menu;
1426 clear_screen(COLOR_BG);
1429 blit_to_screen(original_screen, 240, 160, 230, 40);
1432 current_menu = new_menu;
1433 current_option = new_menu->options;
1434 current_option_num = 0;
1435 if(current_menu->init_function)
1436 current_menu->init_function();
1441 for(i = 0; i < 6; i++)
1443 print_string_pad(" ", COLOR_BG, COLOR_BG, 30, 210 + (i * 10), 70);
1447 video_resolution_large();
1450 SDL_LockMutex(sound_mutex);
1455 SDL_UnlockMutex(sound_mutex);
1458 if(gamepak_filename[0] == 0)
1461 memset(original_screen, 0x00, 240 * 160 * 2);
1462 print_string_ext("No game loaded yet.", 0xFFFF, 0x0000,
1463 60, 75,original_screen, 240, 0);
1466 choose_menu(&main_menu);
1468 for(i = 0; i < 10; i++)
1472 sprintf(cheat_format_str[i], "cheat %d (none loaded)", i);
1476 sprintf(cheat_format_str[i], "cheat %d (%s): %%s", i,
1477 cheats[i].cheat_name);
1481 current_menu->init_function();
1485 display_option = current_menu->options;
1487 for(i = 0; i < current_menu->num_options; i++, display_option++)
1489 if(display_option->option_type & NUMBER_SELECTION_OPTION)
1491 sprintf(line_buffer, display_option->display_string,
1492 *(display_option->current_option));
1496 if(display_option->option_type & STRING_SELECTION_OPTION)
1498 sprintf(line_buffer, display_option->display_string,
1499 ((u32 *)display_option->options)[*(display_option->current_option)]);
1503 strcpy(line_buffer, display_option->display_string);
1506 if(display_option == current_option)
1508 print_string_pad(line_buffer, COLOR_ACTIVE_ITEM, COLOR_BG, 10,
1509 (display_option->line_number * 10) + 40, 36);
1513 print_string_pad(line_buffer, COLOR_INACTIVE_ITEM, COLOR_BG, 10,
1514 (display_option->line_number * 10) + 40, 36);
1518 print_string(current_option->help_string, COLOR_HELP_TEXT,
1523 gui_action = get_gui_input();
1528 current_option_num = (current_option_num + 1) %
1529 current_menu->num_options;
1531 current_option = current_menu->options + current_option_num;
1536 if(current_option_num)
1537 current_option_num--;
1539 current_option_num = current_menu->num_options - 1;
1541 current_option = current_menu->options + current_option_num;
1546 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1547 STRING_SELECTION_OPTION))
1549 *(current_option->current_option) =
1550 (*current_option->current_option + 1) %
1551 current_option->num_options;
1553 if(current_option->passive_function)
1554 current_option->passive_function();
1559 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1560 STRING_SELECTION_OPTION))
1562 u32 current_option_val = *(current_option->current_option);
1564 if(current_option_val)
1565 current_option_val--;
1567 current_option_val = current_option->num_options - 1;
1569 *(current_option->current_option) = current_option_val;
1571 if(current_option->passive_function)
1572 current_option->passive_function();
1577 if(current_menu == &main_menu)
1580 choose_menu(&main_menu);
1584 if(current_option->option_type & ACTION_OPTION)
1585 current_option->action_function();
1587 if(current_option->option_type & SUBMENU_OPTION)
1588 choose_menu(current_option->sub_menu);
1593 set_gba_resolution(screen_scale);
1594 video_resolution_small();
1596 clock_speed = (clock_speed_number + 1) * 33;
1599 scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2);
1604 return return_value;