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 20
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 (resolution_width * 3 / 4)
51 #define COLOR_BG color16(2, 8, 10)
53 #define color16(red, green, blue) \
54 (blue << 11) | (green << 5) | red \
58 #define COLOR_BG color16(0, 0, 0)
60 #define color16(red, green, blue) \
61 (red << 11) | (green << 5) | blue \
65 #define COLOR_ROM_INFO color16(22, 36, 26)
66 #define COLOR_ACTIVE_ITEM color16(31, 63, 31)
67 #define COLOR_INACTIVE_ITEM color16(13, 40, 18)
68 #define COLOR_FRAMESKIP_BAR color16(15, 31, 31)
69 #define COLOR_HELP_TEXT color16(16, 40, 24)
72 static const char *clock_speed_options[] =
74 "33MHz", "66MHz", "100MHz", "133MHz", "166MHz", "200MHz", "233MHz",
75 "266MHz", "300MHz", "333MHz"
77 #define menu_get_clock_speed() \
78 clock_speed = (clock_speed_number + 1) * 33
79 #define get_clock_speed_number() \
80 clock_speed_number = (clock_speed / 33) - 1
81 #elif defined(WIZ_BUILD)
82 static const char *clock_speed_options[] =
84 "300MHz", "333MHz", "366MHz", "400MHz", "433MHz",
85 "466MHz", "500MHz", "533MHz", "566MHz", "600MHz",
86 "633MHz", "666MHz", "700MHz", "733MHz", "766MHz",
87 "800MHz", "833MHz", "866MHz", "900MHz"
89 #define menu_get_clock_speed() \
90 clock_speed = 300 + (clock_speed_number * 3333) / 100
91 #define get_clock_speed_number() \
92 clock_speed_number = (clock_speed - 300) / 33
93 #elif defined(GP2X_BUILD)
94 static const char *clock_speed_options[] =
96 "150MHz", "160MHz", "170MHz", "180MHz", "190MHz",
97 "200MHz", "210MHz", "220MHz", "230MHz", "240MHz",
98 "250MHz", "260MHz", "270MHz", "280MHz", "290MHz"
100 #define menu_get_clock_speed() \
101 clock_speed = 150 + clock_speed_number * 10
102 #define get_clock_speed_number() \
103 clock_speed_number = (clock_speed - 150) / 10
105 static const char *clock_speed_options[] =
109 #define menu_get_clock_speed()
110 #define get_clock_speed_number()
114 int sort_function(const void *dest_str_ptr, const void *src_str_ptr)
116 char *dest_str = *((char **)dest_str_ptr);
117 char *src_str = *((char **)src_str_ptr);
119 if(src_str[0] == '.')
122 if(dest_str[0] == '.')
125 return strcasecmp(dest_str, src_str);
128 s32 load_file(const char **wildcards, char *result)
131 struct dirent *current_file;
132 struct stat file_info;
133 char current_dir_name[MAX_PATH];
134 char current_dir_short[81];
135 u32 current_dir_length;
136 u32 total_filenames_allocated;
137 u32 total_dirnames_allocated;
143 u32 file_name_length;
145 u32 chosen_file, chosen_dir;
146 s32 return_value = 1;
147 s32 current_file_selection;
148 s32 current_file_scroll_value;
149 u32 current_dir_selection;
150 u32 current_dir_scroll_value;
151 s32 current_file_in_scroll;
152 u32 current_dir_in_scroll;
153 u32 current_file_number, current_dir_number;
154 u32 current_column = 0;
157 gui_action_type gui_action;
159 while(return_value == 1)
161 current_file_selection = 0;
162 current_file_scroll_value = 0;
163 current_dir_selection = 0;
164 current_dir_scroll_value = 0;
165 current_file_in_scroll = 0;
166 current_dir_in_scroll = 0;
168 total_filenames_allocated = 32;
169 total_dirnames_allocated = 32;
170 file_list = (char **)malloc(sizeof(char *) * 32);
171 dir_list = (char **)malloc(sizeof(char *) * 32);
172 memset(file_list, 0, sizeof(char *) * 32);
173 memset(dir_list, 0, sizeof(char *) * 32);
180 getcwd(current_dir_name, MAX_PATH);
182 current_dir = opendir(current_dir_name);
187 current_file = readdir(current_dir);
193 file_name = current_file->d_name;
194 file_name_length = strlen(file_name);
196 if((stat(file_name, &file_info) >= 0) &&
197 ((file_name[0] != '.') || (file_name[1] == '.')))
199 if(S_ISDIR(file_info.st_mode))
201 dir_list[num_dirs] = malloc(file_name_length + 1);
203 sprintf(dir_list[num_dirs], "%s", file_name);
209 // Must match one of the wildcards, also ignore the .
210 if(file_name_length >= 4)
212 if(file_name[file_name_length - 4] == '.')
213 ext_pos = file_name_length - 4;
216 if(file_name[file_name_length - 3] == '.')
217 ext_pos = file_name_length - 3;
222 for(i = 0; wildcards[i] != NULL; i++)
224 if(!strcasecmp((file_name + ext_pos),
227 file_list[num_files] =
228 malloc(file_name_length + 1);
230 sprintf(file_list[num_files], "%s", file_name);
240 if(num_files == total_filenames_allocated)
242 file_list = (char **)realloc(file_list, sizeof(char *) *
243 total_filenames_allocated * 2);
244 memset(file_list + total_filenames_allocated, 0,
245 sizeof(char *) * total_filenames_allocated);
246 total_filenames_allocated *= 2;
249 if(num_dirs == total_dirnames_allocated)
251 dir_list = (char **)realloc(dir_list, sizeof(char *) *
252 total_dirnames_allocated * 2);
253 memset(dir_list + total_dirnames_allocated, 0,
254 sizeof(char *) * total_dirnames_allocated);
255 total_dirnames_allocated *= 2;
258 } while(current_file);
260 qsort((void *)file_list, num_files, sizeof(char *), sort_function);
261 qsort((void *)dir_list, num_dirs, sizeof(char *), sort_function);
263 closedir(current_dir);
265 current_dir_length = strlen(current_dir_name);
267 if(current_dir_length > 80)
271 snprintf(current_dir_short, 80,
272 "...%s", current_dir_name + current_dir_length - 77);
274 memcpy(current_dir_short, "...", 3);
275 memcpy(current_dir_short + 3,
276 current_dir_name + current_dir_length - 77, 77);
277 current_dir_short[80] = 0;
283 snprintf(current_dir_short, 80, "%s", current_dir_name);
285 memcpy(current_dir_short, current_dir_name,
286 current_dir_length + 1);
295 clear_screen(COLOR_BG);
301 print_string(current_dir_short, COLOR_ACTIVE_ITEM, COLOR_BG, 0, 0);
303 print_string("Press X to return to the main menu.",
304 COLOR_HELP_TEXT, COLOR_BG, 20, 220);
306 print_string("Press X to return to the main menu.",
307 COLOR_HELP_TEXT, COLOR_BG, 20, 260);
310 for(i = 0, current_file_number = i + current_file_scroll_value;
311 i < FILE_LIST_ROWS; i++, current_file_number++)
313 if(current_file_number < num_files)
315 if((current_file_number == current_file_selection) &&
316 (current_column == 0))
318 print_string(file_list[current_file_number], COLOR_ACTIVE_ITEM,
319 COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10));
323 print_string(file_list[current_file_number], COLOR_INACTIVE_ITEM,
324 COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10));
329 for(i = 0, current_dir_number = i + current_dir_scroll_value;
330 i < FILE_LIST_ROWS; i++, current_dir_number++)
332 if(current_dir_number < num_dirs)
334 if((current_dir_number == current_dir_selection) &&
335 (current_column == 1))
337 print_string(dir_list[current_dir_number], COLOR_ACTIVE_ITEM,
338 COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10));
342 print_string(dir_list[current_dir_number], COLOR_INACTIVE_ITEM,
343 COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10));
348 gui_action = get_gui_input();
353 if(current_column == 0)
355 if(current_file_selection < (num_files - 1))
357 current_file_selection++;
358 if(current_file_in_scroll == (FILE_LIST_ROWS - 1))
360 clear_screen(COLOR_BG);
361 current_file_scroll_value++;
365 current_file_in_scroll++;
370 clear_screen(COLOR_BG);
371 current_file_selection = 0;
372 current_file_scroll_value = 0;
373 current_file_in_scroll = 0;
378 if(current_dir_selection < (num_dirs - 1))
380 current_dir_selection++;
381 if(current_dir_in_scroll == (FILE_LIST_ROWS - 1))
383 clear_screen(COLOR_BG);
384 current_dir_scroll_value++;
388 current_dir_in_scroll++;
396 if (current_column != 0)
398 clear_screen(COLOR_BG);
399 current_file_selection += FILE_LIST_ROWS;
400 if (current_file_selection > num_files - 1)
401 current_file_selection = num_files - 1;
402 current_file_scroll_value = current_file_selection - FILE_LIST_ROWS / 2;
403 if (current_file_scroll_value < 0)
405 current_file_scroll_value = 0;
406 current_file_in_scroll = current_file_selection;
410 current_file_in_scroll = FILE_LIST_ROWS / 2;
415 if(current_column == 0)
417 if(current_file_selection)
419 current_file_selection--;
420 if(current_file_in_scroll == 0)
422 clear_screen(COLOR_BG);
423 current_file_scroll_value--;
427 current_file_in_scroll--;
432 clear_screen(COLOR_BG);
433 current_file_selection = num_files - 1;
434 current_file_in_scroll = FILE_LIST_ROWS - 1;
435 if (current_file_in_scroll > num_files - 1)
436 current_file_in_scroll = num_files - 1;
437 current_file_scroll_value = num_files - FILE_LIST_ROWS;
438 if (current_file_scroll_value < 0)
439 current_file_scroll_value = 0;
444 if(current_dir_selection)
446 current_dir_selection--;
447 if(current_dir_in_scroll == 0)
449 clear_screen(COLOR_BG);
450 current_dir_scroll_value--;
454 current_dir_in_scroll--;
461 if (current_column != 0)
463 clear_screen(COLOR_BG);
464 current_file_selection -= FILE_LIST_ROWS;
465 if (current_file_selection < 0)
466 current_file_selection = 0;
467 current_file_scroll_value = current_file_selection - FILE_LIST_ROWS / 2;
468 if (current_file_scroll_value < 0)
470 current_file_scroll_value = 0;
471 current_file_in_scroll = current_file_selection;
475 current_file_in_scroll = FILE_LIST_ROWS / 2;
480 if(current_column == 0)
488 if(current_column == 1)
496 if(current_column == 1)
499 chdir(dir_list[current_dir_selection]);
507 strcpy(result, file_list[current_file_selection]);
514 if(!strcmp(current_dir_name, "ms0:/PSP"))
532 for(i = 0; i < num_files; i++)
538 for(i = 0; i < num_dirs; i++)
545 clear_screen(COLOR_BG);
552 NUMBER_SELECTION_OPTION = 0x01,
553 STRING_SELECTION_OPTION = 0x02,
554 SUBMENU_OPTION = 0x04,
556 } menu_option_type_enum;
560 void (* init_function)();
561 void (* passive_function)();
562 struct _menu_option_type *options;
566 struct _menu_option_type
568 void (* action_function)();
569 void (* passive_function)();
570 struct _menu_type *sub_menu;
571 const char *display_string;
575 const char *help_string;
577 menu_option_type_enum option_type;
580 typedef struct _menu_option_type menu_option_type;
581 typedef struct _menu_type menu_type;
583 #define make_menu(name, init_function, passive_function) \
584 menu_type name##_menu = \
589 sizeof(name##_options) / sizeof(menu_option_type) \
592 #define gamepad_config_option(display_string, number) \
595 menu_fix_gamepad_help, \
597 display_string ": %s", \
598 gamepad_config_buttons, \
599 gamepad_config_map + gamepad_config_line_to_button[number], \
600 sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \
601 gamepad_help[gamepad_config_map[ \
602 gamepad_config_line_to_button[number]]], \
604 STRING_SELECTION_OPTION \
607 #define analog_config_option(display_string, number) \
610 menu_fix_gamepad_help, \
612 display_string ": %s", \
613 gamepad_config_buttons, \
614 gamepad_config_map + number + 12, \
615 sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \
616 gamepad_help[gamepad_config_map[number + 12]], \
618 STRING_SELECTION_OPTION \
621 #define cheat_option(number) \
626 cheat_format_str[number], \
627 enable_disable_options, \
628 &(cheats[number].cheat_active), \
630 "Activate/deactivate this cheat code.", \
632 STRING_SELECTION_OPTION \
635 #define action_option(action_function, passive_function, display_string, \
636 help_string, line_number) \
650 #define submenu_option(sub_menu, display_string, help_string, line_number) \
658 sizeof(sub_menu) / sizeof(menu_option_type), \
664 #define selection_option(passive_function, display_string, options, \
665 option_ptr, num_options, help_string, line_number, type) \
679 #define action_selection_option(action_function, passive_function, \
680 display_string, options, option_ptr, num_options, help_string, line_number, \
692 type | ACTION_OPTION \
696 #define string_selection_option(passive_function, display_string, options, \
697 option_ptr, num_options, help_string, line_number) \
698 selection_option(passive_function, display_string ": %s", options, \
699 option_ptr, num_options, help_string, line_number, STRING_SELECTION_OPTION)\
701 #define numeric_selection_option(passive_function, display_string, \
702 option_ptr, num_options, help_string, line_number) \
703 selection_option(passive_function, display_string ": %d", NULL, option_ptr, \
704 num_options, help_string, line_number, NUMBER_SELECTION_OPTION) \
706 #define string_selection_action_option(action_function, passive_function, \
707 display_string, options, option_ptr, num_options, help_string, line_number) \
708 action_selection_option(action_function, passive_function, \
709 display_string ": %s", options, option_ptr, num_options, help_string, \
710 line_number, STRING_SELECTION_OPTION) \
712 #define numeric_selection_action_option(action_function, passive_function, \
713 display_string, option_ptr, num_options, help_string, line_number) \
714 action_selection_option(action_function, passive_function, \
715 display_string ": %d", NULL, option_ptr, num_options, help_string, \
716 line_number, NUMBER_SELECTION_OPTION) \
718 #define numeric_selection_action_hide_option(action_function, \
719 passive_function, display_string, option_ptr, num_options, help_string, \
721 action_selection_option(action_function, passive_function, \
722 display_string, NULL, option_ptr, num_options, help_string, \
723 line_number, NUMBER_SELECTION_OPTION) \
726 #define GAMEPAD_MENU_WIDTH 15
730 u32 gamepad_config_line_to_button[] =
731 { 8, 6, 7, 9, 1, 2, 3, 0, 4, 5, 11, 10 };
737 u32 gamepad_config_line_to_button[] =
738 { 0, 2, 1, 3, 8, 9, 10, 11, 6, 7, 4, 5, 14 };
744 u32 gamepad_config_line_to_button[] =
745 { 0, 2, 1, 3, 8, 9, 10, 11, 6, 7, 4, 5, 12, 13, 14, 15 };
749 static const char *scale_options[] =
752 "unscaled 3:2", "scaled 3:2", "fullscreen 16:9"
753 #elif defined(WIZ_BUILD)
754 "unscaled 3:2", "scaled 3:2 (slower)",
755 "unscaled 3:2 (anti-tear)", "scaled 3:2 (anti-tear)"
756 #elif defined(PND_BUILD)
757 "unscaled", "2x", "3x", "fullscreen"
758 #elif defined(GP2X_BUILD)
759 "unscaled 3:2", "scaled 3:2", "fullscreen", "scaled 3:2 (software)"
765 const char *filter2_options[] =
767 "none", "scale2x", "scale3x", "eagle2x"
770 s32 load_game_config_file()
772 char game_config_filename[512];
775 make_rpath(game_config_filename, sizeof(game_config_filename), ".cfg");
777 file_open(game_config_file, game_config_filename, read);
779 if(file_check_valid(game_config_file))
781 u32 file_size = file_length(game_config_filename, game_config_file);
783 // Sanity check: File size must be the right size
786 u32 file_options[file_size / 4];
788 file_read_array(game_config_file, file_options);
789 current_frameskip_type = file_options[0] % 3;
790 frameskip_value = file_options[1];
791 random_skip = file_options[2] % 2;
792 clock_speed = file_options[3];
795 if(clock_speed > 900)
797 #elif defined(GP2X_BUILD)
798 if(clock_speed >= 300)
801 if(clock_speed > 333)
808 if(frameskip_value < 0)
811 if(frameskip_value > 99)
812 frameskip_value = 99;
814 for(i = 0; i < 10; i++)
816 cheats[i].cheat_active = file_options[4 + i] % 2;
817 cheats[i].cheat_name[0] = 0;
820 file_close(game_config_file);
828 current_frameskip_type = auto_frameskip;
834 clock_speed = default_clock_speed;
836 for(i = 0; i < 10; i++)
838 cheats[i].cheat_active = 0;
839 cheats[i].cheat_name[0] = 0;
845 #define FILE_OPTION_COUNT 24
847 s32 load_config_file()
849 char config_path[512];
851 sprintf(config_path, "%s" PATH_SEPARATOR "%s", main_path, GPSP_CONFIG_FILENAME);
853 file_open(config_file, config_path, read);
855 if(file_check_valid(config_file))
857 u32 file_size = file_length(config_path, config_file);
859 // Sanity check: File size must be the right size
860 if(file_size == FILE_OPTION_COUNT * 4)
862 u32 file_options[file_size / 4];
863 file_read_array(config_file, file_options);
865 screen_scale = file_options[0] %
866 (sizeof(scale_options) / sizeof(scale_options[0]));
867 screen_filter = file_options[1] % 2;
868 global_enable_audio = file_options[2] % 2;
869 screen_filter2 = file_options[23] %
870 (sizeof(filter2_options) / sizeof(filter2_options[0]));
873 audio_buffer_size_number = file_options[3] % 10;
875 audio_buffer_size_number = file_options[3] % 11;
878 update_backup_flag = file_options[4] % 2;
879 global_enable_analog = file_options[5] % 2;
880 analog_sensitivity_level = file_options[6] % 8;
883 scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2);
886 // Sanity check: Make sure there's a MENU or FRAMESKIP
887 // key, if not assign to triangle
891 s32 menu_button = -1;
892 for(i = 0; i < 16; i++)
894 gamepad_config_map[i] = file_options[7 + i] %
895 (BUTTON_ID_NONE + 1);
897 if(gamepad_config_map[i] == BUTTON_ID_MENU)
903 if(menu_button == -1)
905 gamepad_config_map[0] = BUTTON_ID_MENU;
909 file_close(config_file);
918 s32 save_game_config_file()
920 char game_config_filename[512];
923 make_rpath(game_config_filename, sizeof(game_config_filename), ".cfg");
925 file_open(game_config_file, game_config_filename, write);
927 if(file_check_valid(game_config_file))
929 u32 file_options[14];
931 file_options[0] = current_frameskip_type;
932 file_options[1] = frameskip_value;
933 file_options[2] = random_skip;
934 file_options[3] = clock_speed;
936 for(i = 0; i < 10; i++)
938 file_options[4 + i] = cheats[i].cheat_active;
941 file_write_array(game_config_file, file_options);
943 file_close(game_config_file);
951 s32 save_config_file()
953 char config_path[512];
955 sprintf(config_path, "%s" PATH_SEPARATOR "%s", main_path, GPSP_CONFIG_FILENAME);
957 file_open(config_file, config_path, write);
959 save_game_config_file();
961 if(file_check_valid(config_file))
963 u32 file_options[FILE_OPTION_COUNT];
965 file_options[0] = screen_scale;
966 file_options[1] = screen_filter;
967 file_options[2] = global_enable_audio;
968 file_options[3] = audio_buffer_size_number;
969 file_options[4] = update_backup_flag;
970 file_options[5] = global_enable_analog;
971 file_options[6] = analog_sensitivity_level;
972 file_options[23] = screen_filter2;
976 for(i = 0; i < 16; i++)
978 file_options[7 + i] = gamepad_config_map[i];
982 file_write_array(config_file, file_options);
984 file_close(config_file);
1001 u32 savestate_slot = 0;
1003 void get_savestate_snapshot(char *savestate_filename)
1005 u16 snapshot_buffer[240 * 160];
1006 char savestate_timestamp_string[80];
1008 file_open(savestate_file, savestate_filename, read);
1010 if(file_check_valid(savestate_file))
1012 const char weekday_strings[7][11] =
1014 "Sunday", "Monday", "Tuesday", "Wednesday",
1015 "Thursday", "Friday", "Saturday"
1017 time_t savestate_time_flat;
1018 struct tm *current_time;
1019 file_read_array(savestate_file, snapshot_buffer);
1020 file_read_variable(savestate_file, savestate_time_flat);
1022 file_close(savestate_file);
1024 current_time = localtime(&savestate_time_flat);
1025 sprintf(savestate_timestamp_string,
1026 "%s %02d/%02d/%04d %02d:%02d:%02d ",
1027 weekday_strings[current_time->tm_wday], current_time->tm_mon + 1,
1028 current_time->tm_mday, current_time->tm_year + 1900,
1029 current_time->tm_hour, current_time->tm_min, current_time->tm_sec);
1031 savestate_timestamp_string[40] = 0;
1032 print_string(savestate_timestamp_string, COLOR_HELP_TEXT, COLOR_BG,
1037 memset(snapshot_buffer, 0, 240 * 160 * 2);
1038 print_string_ext("No savestate in this slot.",
1039 0xFFFF, 0x0000, 15, 75, snapshot_buffer, 240, 0, 0, FONT_HEIGHT);
1040 print_string("---------- --/--/---- --:--:-- ", COLOR_HELP_TEXT,
1045 blit_to_screen(snapshot_buffer, 240, 160, 230, 40);
1049 void get_savestate_filename_noshot(u32 slot, char *name_buffer)
1051 char savestate_ext[16];
1053 sprintf(savestate_ext, "%d.svs", slot);
1054 make_rpath(name_buffer, 512, savestate_ext);
1057 void get_savestate_filename(u32 slot, char *name_buffer)
1059 get_savestate_filename_noshot(slot, name_buffer);
1060 get_savestate_snapshot(name_buffer);
1066 invalidate_all_cache();
1070 u32 menu(u16 *original_screen)
1072 char print_buffer[81];
1073 u32 clock_speed_number;
1074 gui_action_type gui_action;
1077 u32 return_value = 0;
1079 char current_savestate_filename[512];
1080 char line_buffer[80];
1081 char cheat_format_str[10][41];
1083 menu_type *current_menu;
1084 menu_option_type *current_option;
1085 menu_option_type *display_option;
1086 u32 current_option_num;
1088 auto void choose_menu();
1089 auto void clear_help();
1092 static const char * const gamepad_help[] =
1094 "Up button on GBA d-pad.",
1095 "Down button on GBA d-pad.",
1096 "Left button on GBA d-pad.",
1097 "Right button on GBA d-pad.",
1100 "Left shoulder button on GBA.",
1101 "Right shoulder button on GBA.",
1102 "Start button on GBA.",
1103 "Select button on GBA.",
1104 "Brings up the options menu.",
1105 "Toggles fastforward on/off.",
1106 "Loads the game state from the current slot.",
1107 "Saves the game state to the current slot.",
1108 "Rapidly press/release the A button on GBA.",
1109 "Rapidly press/release the B button on GBA.",
1110 "Rapidly press/release the L shoulder on GBA.",
1111 "Rapidly press/release the R shoulder on GBA.",
1112 "Increases the volume.",
1113 "Decreases the volume.",
1114 "Displays virtual/drawn frames per second.",
1118 static const char *gamepad_config_buttons[] =
1145 void menu_update_clock()
1147 get_clock_speed_number();
1148 if (clock_speed_number < 0 || clock_speed_number >=
1149 sizeof(clock_speed_options) / sizeof(clock_speed_options[0]))
1151 clock_speed = default_clock_speed;
1152 get_clock_speed_number();
1164 menu_get_clock_speed();
1171 const char *file_ext[] = { ".gba", ".bin", ".zip", NULL };
1172 char load_filename[512];
1173 save_game_config_file();
1174 if(load_file(file_ext, load_filename) != -1)
1176 if(load_gamepak(load_filename) == -1)
1183 reg[CHANGED_PC_STATUS] = 1;
1184 menu_update_clock();
1188 choose_menu(current_menu);
1197 reg[CHANGED_PC_STATUS] = 1;
1203 void menu_change_state()
1205 get_savestate_filename(savestate_slot, current_savestate_filename);
1208 void menu_save_state()
1212 get_savestate_filename_noshot(savestate_slot,
1213 current_savestate_filename);
1214 save_state(current_savestate_filename, original_screen);
1216 menu_change_state();
1219 void menu_load_state()
1223 load_state(current_savestate_filename);
1229 void menu_load_state_file()
1231 const char *file_ext[] = { ".svs", NULL };
1232 char load_filename[512];
1233 if(load_file(file_ext, load_filename) != -1)
1235 load_state(load_filename);
1241 choose_menu(current_menu);
1245 void menu_fix_gamepad_help()
1249 current_option->help_string =
1250 gamepad_help[gamepad_config_map[
1251 gamepad_config_line_to_button[current_option_num]]];
1255 void submenu_graphics_sound()
1260 void submenu_cheats_misc()
1265 void submenu_gamepad()
1270 void submenu_analog()
1275 void submenu_savestate()
1277 print_string("Savestate options:", COLOR_ACTIVE_ITEM, COLOR_BG, 10, 70);
1278 menu_change_state();
1283 strncpy(print_buffer, gamepak_filename, 80);
1284 print_string(print_buffer, COLOR_ROM_INFO, COLOR_BG, 10, 10);
1285 sprintf(print_buffer, "%s %s %s", gamepak_title,
1286 gamepak_code, gamepak_maker);
1287 print_string(print_buffer, COLOR_ROM_INFO, COLOR_BG, 10, 20);
1289 get_savestate_filename_noshot(savestate_slot,
1290 current_savestate_filename);
1293 const char *yes_no_options[] = { "no", "yes" };
1294 const char *enable_disable_options[] = { "disabled", "enabled" };
1296 const char *frameskip_options[] = { "automatic", "manual", "off" };
1297 const char *frameskip_variation_options[] = { "uniform", "random" };
1300 static const char *audio_buffer_options[] =
1302 "16 bytes", "32 bytes", "64 bytes",
1303 "128 bytes", "256 bytes", "512 bytes", "1024 bytes", "2048 bytes",
1304 "4096 bytes", "8192 bytes", "16284 bytes"
1307 const char *audio_buffer_options[] =
1309 "3072 bytes", "4096 bytes", "5120 bytes", "6144 bytes", "7168 bytes",
1310 "8192 bytes", "9216 bytes", "10240 bytes", "11264 bytes", "12288 bytes"
1314 static const char *update_backup_options[] = { "Exit only", "Automatic" };
1316 // Marker for help information, don't go past this mark (except \n)------*
1317 menu_option_type graphics_sound_options[] =
1319 string_selection_option(NULL, "Display scaling", scale_options,
1320 (u32 *)(&screen_scale),
1321 sizeof(scale_options) / sizeof(scale_options[0]),
1323 "Determines how the GBA screen is resized in relation to the\n"
1326 " Select unscaled 3:2 for GBA resolution, scaled 3:2 for GBA\n"
1327 "aspect ratio scaled to fill the height of the PSP screen, and\n"
1328 "fullscreen to fill the entire PSP screen."
1333 string_selection_option(NULL, "Screen filtering", yes_no_options,
1334 (u32 *)(&screen_filter), 2,
1335 "Determines whether or not filtering should be used when\n"
1336 "scaling the screen. Selecting this will produce a more even and\n"
1337 "smooth image, at the cost of being blurry and having less vibrant\n"
1341 string_selection_option(NULL, "Scaling filter", filter2_options,
1342 (u32 *)(&screen_filter2),
1343 sizeof(filter2_options) / sizeof(filter2_options[0]),
1344 "Optional pixel art scaling filter", 4),
1346 string_selection_option(NULL, "Frameskip type", frameskip_options,
1347 (u32 *)(¤t_frameskip_type), 3,
1349 "Determines what kind of frameskipping to use.\n"
1350 "Frameskipping may improve emulation speed of many games.\n"
1352 "Off: Do not skip any frames.\n"
1353 "Auto: Skip up to N frames (see next opt) as needed.\n"
1354 "Manual: Always render only 1 out of N + 1 frames."
1356 numeric_selection_option(NULL, "Frameskip value", &frameskip_value, 100,
1358 "For auto frameskip, determines the maximum number of frames that\n"
1359 "are allowed to be skipped consecutively.\n"
1360 "For manual frameskip, determines the number of frames that will\n"
1361 "always be skipped."
1364 string_selection_option(NULL, "Framskip variation",
1365 frameskip_variation_options, &random_skip, 2,
1367 "If objects in the game flicker at a regular rate certain manual\n"
1368 "frameskip values may cause them to normally disappear. Change this\n"
1369 "value to 'random' to avoid this. Do not use otherwise, as it tends\n"
1370 "to make the image quality worse, especially in high motion games."
1373 string_selection_option(NULL, "Audio output", yes_no_options,
1374 &global_enable_audio, 2,
1375 "Select 'no' to turn off all audio output. This will\n"
1376 "not result in a significant change in performance.", 9),
1378 string_selection_option(NULL, "Audio buffer", audio_buffer_options,
1379 &audio_buffer_size_number, 11,
1381 string_selection_option(NULL, "Audio buffer", audio_buffer_options,
1382 &audio_buffer_size_number, 10,
1386 "Set the size (in bytes) of the audio buffer. Larger values may result\n"
1387 "in slightly better performance at the cost of latency; the lowest\n"
1388 "value will give the most responsive audio.\n"
1389 "This option requires gpSP to be restarted before it will take effect.",
1391 "Set the size (in bytes) of the audio buffer.\n"
1392 "This option requires gpSP restart to take effect.\n"
1393 "Settable values may be limited by SDL implementation.",
1396 submenu_option(NULL, "Back", "Return to the main menu.", 12)
1399 make_menu(graphics_sound, submenu_graphics_sound, NULL);
1401 menu_option_type cheats_misc_options[] =
1413 #if defined(PSP_BUILD) || defined(GP2X_BUILD)
1414 string_selection_option(NULL, "Clock speed",
1415 clock_speed_options, &clock_speed_number,
1416 sizeof(clock_speed_options) / sizeof(clock_speed_options[0]),
1417 "Change the clock speed of the device. Higher clock\n"
1418 "speed will yield better performance, but will drain\n"
1419 "battery life further.", 11),
1421 string_selection_option(NULL, "Update backup",
1422 update_backup_options, &update_backup_flag, 2,
1424 "Determines when in-game save files should be\n"
1425 "written back to SD card."
1427 "Determines when in-game save files should be written back to\n"
1428 "card. If set to 'automatic' writebacks will occur shortly after\n"
1429 "the game's backup is altered. On 'exit only' it will only be\n"
1430 "written back when you exit from this menu.\n"
1432 "(NOT from using the home button), use the latter with extreme care."
1436 submenu_option(NULL, "Back", "Return to the main menu.", 14)
1439 make_menu(cheats_misc, submenu_cheats_misc, NULL);
1441 menu_option_type savestate_options[] =
1443 numeric_selection_action_hide_option(menu_load_state, menu_change_state,
1444 "Load savestate from current slot", &savestate_slot, 10,
1445 "Select to load the game state from the current slot\n"
1447 "Press left + right to change the current slot.", 6),
1448 numeric_selection_action_hide_option(menu_save_state, menu_change_state,
1449 "Save savestate to current slot", &savestate_slot, 10,
1450 "Select to save the game state to the current slot\n"
1452 "Press left + right to change the current slot.", 7),
1453 numeric_selection_action_hide_option(menu_load_state_file,
1455 "Load savestate from file", &savestate_slot, 10,
1456 "Restore gameplay from a savestate file.\n"
1457 "Note: The same file used to save the state must be\n"
1459 numeric_selection_option(menu_change_state,
1460 "Current savestate slot", &savestate_slot, 10,
1461 "Change the current savestate slot.\n", 11),
1462 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1465 make_menu(savestate, submenu_savestate, NULL);
1469 menu_option_type gamepad_config_options[] =
1471 gamepad_config_option("D-pad up ", 0),
1472 gamepad_config_option("D-pad down ", 1),
1473 gamepad_config_option("D-pad left ", 2),
1474 gamepad_config_option("D-pad right ", 3),
1475 gamepad_config_option("Circle ", 4),
1476 gamepad_config_option("Cross ", 5),
1477 gamepad_config_option("Square ", 6),
1478 gamepad_config_option("Triangle ", 7),
1479 gamepad_config_option("Left Trigger ", 8),
1480 gamepad_config_option("Right Trigger", 9),
1481 gamepad_config_option("Start ", 10),
1482 gamepad_config_option("Select ", 11),
1483 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1487 menu_option_type analog_config_options[] =
1489 analog_config_option("Analog up ", 0),
1490 analog_config_option("Analog down ", 1),
1491 analog_config_option("Analog left ", 2),
1492 analog_config_option("Analog right", 3),
1493 string_selection_option(NULL, "Enable analog", yes_no_options,
1494 &global_enable_analog, 2,
1495 "Select 'no' to block analog input entirely.", 7),
1496 numeric_selection_option(NULL, "Analog sensitivity",
1497 &analog_sensitivity_level, 10,
1498 "Determine sensitivity/responsiveness of the analog input.\n"
1499 "Lower numbers are less sensitive.", 8),
1500 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1505 #if defined(GP2X_BUILD) || defined(PND_BUILD)
1507 menu_option_type gamepad_config_options[] =
1509 gamepad_config_option("D-pad up ", 0),
1510 gamepad_config_option("D-pad down ", 1),
1511 gamepad_config_option("D-pad left ", 2),
1512 gamepad_config_option("D-pad right ", 3),
1513 gamepad_config_option("A ", 4),
1514 gamepad_config_option("B ", 5),
1515 gamepad_config_option("X ", 6),
1516 gamepad_config_option("Y ", 7),
1517 gamepad_config_option("Left Trigger ", 8),
1518 gamepad_config_option("Right Trigger", 9),
1520 gamepad_config_option("Menu ", 10),
1522 gamepad_config_option("Start ", 10),
1524 gamepad_config_option("Select ", 11),
1525 #if !defined(WIZ_BUILD) && !defined(PND_BUILD)
1526 gamepad_config_option("Stick Push ", 12),
1529 gamepad_config_option("1 ", 12),
1530 gamepad_config_option("2 ", 13),
1531 gamepad_config_option("3 ", 14),
1532 gamepad_config_option("4 ", 15),
1533 submenu_option(NULL, "Back", "Return to the main menu.", 16)
1535 submenu_option(NULL, "Back", "Return to the main menu.", 14)
1540 menu_option_type analog_config_options[] =
1542 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1549 menu_option_type gamepad_config_options[] =
1551 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1554 menu_option_type analog_config_options[] =
1556 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1561 make_menu(gamepad_config, submenu_gamepad, NULL);
1562 make_menu(analog_config, submenu_analog, NULL);
1564 menu_option_type main_options[] =
1566 submenu_option(&graphics_sound_menu, "Graphics and Sound options",
1567 "Select to set display parameters and frameskip\n"
1568 "behavior, audio on/off, buffer size, and filtering.", 0),
1569 numeric_selection_action_option(menu_load_state, NULL,
1570 "Load state from slot", &savestate_slot, 10,
1571 "Select to load the game state from the current slot\n"
1572 "for this game, if it exists.\n"
1573 "Press left + right to change the current slot.", 2),
1574 numeric_selection_action_option(menu_save_state, NULL,
1575 "Save state to slot", &savestate_slot, 10,
1576 "Select to save the game state to the current slot\n"
1577 "for this game. See the extended menu for more info.\n"
1578 "Press left + right to change the current slot.", 3),
1579 submenu_option(&savestate_menu, "Savestate options",
1580 "Select to enter a menu for loading, saving, and\n"
1581 "viewing the currently active savestate for this game\n"
1582 "(or to load a savestate file from another game)", 4),
1583 submenu_option(&gamepad_config_menu, "Configure gamepad input",
1584 "Select to change the in-game behavior of buttons\n"
1587 submenu_option(&analog_config_menu, "Configure analog input",
1588 "Select to change the in-game behavior of the PSP analog nub.", 7),
1590 submenu_option(&cheats_misc_menu, "Cheats and Miscellaneous options",
1591 "Select to manage cheats, set backup behavior,\n"
1592 "and set device clock speed.", 9),
1593 action_option(menu_load, NULL, "Load new game",
1594 "Select to load a new game\n"
1595 "(will exit a game if currently playing).", 11),
1596 action_option(menu_restart, NULL, "Restart game",
1597 "Select to reset the GBA with the current game\n"
1599 action_option(menu_exit, NULL, "Return to game",
1600 "Select to exit this menu and resume gameplay.", 13),
1601 action_option(menu_quit, NULL, "Exit gpSP",
1602 "Select to exit gpSP and return to the menu.", 15)
1605 make_menu(main, submenu_main, NULL);
1607 void choose_menu(menu_type *new_menu)
1609 if(new_menu == NULL)
1610 new_menu = &main_menu;
1612 clear_screen(COLOR_BG);
1615 blit_to_screen(original_screen, 240, 160, 230, 40);
1618 current_menu = new_menu;
1619 current_option = new_menu->options;
1620 current_option_num = 0;
1621 if(current_menu->init_function)
1622 current_menu->init_function();
1627 for(i = 0; i < 6; i++)
1629 print_string_pad(" ", COLOR_BG, COLOR_BG, 8, 210 + (i * 10), 70);
1633 menu_update_clock();
1634 video_resolution_large();
1637 SDL_LockMutex(sound_mutex);
1642 SDL_UnlockMutex(sound_mutex);
1645 if(gamepak_filename[0] == 0)
1648 memset(original_screen, 0x00, 240 * 160 * 2);
1649 print_string_ext("No game loaded yet.", 0xFFFF, 0x0000,
1650 60, 75,original_screen, 240, 0, 0, FONT_HEIGHT);
1653 choose_menu(&main_menu);
1655 for(i = 0; i < 10; i++)
1659 sprintf(cheat_format_str[i], "cheat %d (none loaded)", i);
1663 sprintf(cheat_format_str[i], "cheat %d (%s): %%s", i,
1664 cheats[i].cheat_name);
1668 current_menu->init_function();
1672 display_option = current_menu->options;
1674 for(i = 0; i < current_menu->num_options; i++, display_option++)
1676 if(display_option->option_type & NUMBER_SELECTION_OPTION)
1678 sprintf(line_buffer, display_option->display_string,
1679 *(display_option->current_option));
1683 if(display_option->option_type & STRING_SELECTION_OPTION)
1685 sprintf(line_buffer, display_option->display_string,
1686 ((u32 *)display_option->options)[*(display_option->current_option)]);
1690 strcpy(line_buffer, display_option->display_string);
1693 if(display_option == current_option)
1695 print_string_pad(line_buffer, COLOR_ACTIVE_ITEM, COLOR_BG, 6,
1696 (display_option->line_number * 10) + 40, 36);
1700 print_string_pad(line_buffer, COLOR_INACTIVE_ITEM, COLOR_BG, 6,
1701 (display_option->line_number * 10) + 40, 36);
1705 print_string(current_option->help_string, COLOR_HELP_TEXT,
1710 gui_action = get_gui_input();
1715 current_option_num = (current_option_num + 1) %
1716 current_menu->num_options;
1718 current_option = current_menu->options + current_option_num;
1723 if(current_option_num)
1724 current_option_num--;
1726 current_option_num = current_menu->num_options - 1;
1728 current_option = current_menu->options + current_option_num;
1733 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1734 STRING_SELECTION_OPTION))
1736 *(current_option->current_option) =
1737 (*current_option->current_option + 1) %
1738 current_option->num_options;
1740 if(current_option->passive_function)
1741 current_option->passive_function();
1746 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1747 STRING_SELECTION_OPTION))
1749 u32 current_option_val = *(current_option->current_option);
1751 if(current_option_val)
1752 current_option_val--;
1754 current_option_val = current_option->num_options - 1;
1756 *(current_option->current_option) = current_option_val;
1758 if(current_option->passive_function)
1759 current_option->passive_function();
1764 if(current_menu == &main_menu)
1767 choose_menu(&main_menu);
1771 if(current_option->option_type & ACTION_OPTION)
1772 current_option->action_function();
1774 if(current_option->option_type & SUBMENU_OPTION)
1775 choose_menu(current_option->sub_menu);
1783 set_gba_resolution(screen_scale);
1784 video_resolution_small();
1785 menu_get_clock_speed();
1789 num_skipped_frames = 100;
1791 return return_value;