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
29 #include "gp2x/cpuctrl.h"
37 // Blatantly stolen and trimmed from MZX (megazeux.sourceforge.net)
41 #define FILE_LIST_ROWS ((int)((SDL_SCREEN_HEIGHT - 40) / FONT_HEIGHT))
42 #define FILE_LIST_POSITION 5
43 #define DIR_LIST_POSITION 260
47 #define FILE_LIST_ROWS 25
48 #define FILE_LIST_POSITION 5
49 #define DIR_LIST_POSITION 360
55 #define color16(red, green, blue) \
56 (blue << 11) | (green << 5) | red \
60 #define color16(red, green, blue) \
61 (red << 11) | (green << 5) | blue \
67 #define COLOR_BG color16(0, 0, 0)
71 #define COLOR_BG color16(2, 8, 10)
75 #define COLOR_ROM_INFO color16(22, 36, 26)
76 #define COLOR_ACTIVE_ITEM color16(31, 63, 31)
77 #define COLOR_INACTIVE_ITEM color16(13, 40, 18)
78 #define COLOR_FRAMESKIP_BAR color16(15, 31, 31)
79 #define COLOR_HELP_TEXT color16(16, 40, 24)
82 u8 *clock_speed_options[] =
84 "33MHz", "66MHz", "100MHz", "133MHz", "166MHz", "200MHz", "233MHz",
85 "266MHz", "300MHz", "333MHz"
87 #define menu_get_clock_speed() \
88 clock_speed = (clock_speed_number + 1) * 33
89 #define get_clock_speed_number() \
90 clock_speed_number = (clock_speed / 33) - 1
91 #elif defined(WIZ_BUILD)
92 u8 *clock_speed_options[] =
94 "300MHz", "333MHz", "366MHz", "400MHz", "433MHz",
95 "466MHz", "500MHz", "533MHz", "566MHz", "600MHz",
96 "633MHz", "666MHz", "700MHz", "733MHz", "766MHz",
97 "800MHz", "833MHz", "866MHz", "900MHz"
99 #define menu_get_clock_speed() \
100 clock_speed = 300 + (clock_speed_number * 3333) / 100
101 #define get_clock_speed_number() \
102 clock_speed_number = (clock_speed - 300) / 33
103 #elif defined(GP2X_BUILD)
104 u8 *clock_speed_options[] =
106 "150MHz", "160MHz", "170MHz", "180MHz", "190MHz",
107 "200MHz", "210MHz", "220MHz", "230MHz", "240MHz",
108 "250MHz", "260MHz", "270MHz", "280MHz", "290MHz"
110 #define menu_get_clock_speed() \
111 clock_speed = 150 + clock_speed_number * 10
112 #define get_clock_speed_number() \
113 clock_speed_number = (clock_speed - 150) / 10
115 u8 *clock_speed_options[] =
119 #define menu_get_clock_speed() 0
120 #define get_clock_speed_number() 0
124 int sort_function(const void *dest_str_ptr, const void *src_str_ptr)
126 char *dest_str = *((char **)dest_str_ptr);
127 char *src_str = *((char **)src_str_ptr);
129 if(src_str[0] == '.')
132 if(dest_str[0] == '.')
135 return strcasecmp(dest_str, src_str);
138 s32 load_file(u8 **wildcards, u8 *result)
141 struct dirent *current_file;
142 struct stat file_info;
143 u8 current_dir_name[MAX_PATH];
144 u8 current_dir_short[81];
145 u32 current_dir_length;
146 u32 total_filenames_allocated;
147 u32 total_dirnames_allocated;
153 u32 file_name_length;
155 u32 chosen_file, chosen_dir;
156 u32 dialog_result = 1;
157 s32 return_value = 1;
158 s32 current_file_selection;
159 s32 current_file_scroll_value;
160 u32 current_dir_selection;
161 u32 current_dir_scroll_value;
162 s32 current_file_in_scroll;
163 u32 current_dir_in_scroll;
164 u32 current_file_number, current_dir_number;
165 u32 current_column = 0;
168 gui_action_type gui_action;
170 while(return_value == 1)
172 current_file_selection = 0;
173 current_file_scroll_value = 0;
174 current_dir_selection = 0;
175 current_dir_scroll_value = 0;
176 current_file_in_scroll = 0;
177 current_dir_in_scroll = 0;
179 total_filenames_allocated = 32;
180 total_dirnames_allocated = 32;
181 file_list = (u8 **)malloc(sizeof(u8 *) * 32);
182 dir_list = (u8 **)malloc(sizeof(u8 *) * 32);
183 memset(file_list, 0, sizeof(u8 *) * 32);
184 memset(dir_list, 0, sizeof(u8 *) * 32);
191 getcwd(current_dir_name, MAX_PATH);
193 current_dir = opendir(current_dir_name);
198 current_file = readdir(current_dir);
204 file_name = current_file->d_name;
205 file_name_length = strlen(file_name);
207 if((stat(file_name, &file_info) >= 0) &&
208 ((file_name[0] != '.') || (file_name[1] == '.')))
210 if(S_ISDIR(file_info.st_mode))
213 (u8 *)malloc(file_name_length + 1);
215 sprintf(dir_list[num_dirs], "%s", file_name);
221 // Must match one of the wildcards, also ignore the .
222 if(file_name_length >= 4)
224 if(file_name[file_name_length - 4] == '.')
225 ext_pos = file_name_length - 4;
228 if(file_name[file_name_length - 3] == '.')
229 ext_pos = file_name_length - 3;
234 for(i = 0; wildcards[i] != NULL; i++)
236 if(!strcasecmp((file_name + ext_pos),
239 file_list[num_files] =
240 (u8 *)malloc(file_name_length + 1);
242 sprintf(file_list[num_files], "%s", file_name);
252 if(num_files == total_filenames_allocated)
254 file_list = (u8 **)realloc(file_list, sizeof(u8 *) *
255 total_filenames_allocated * 2);
256 memset(file_list + total_filenames_allocated, 0,
257 sizeof(u8 *) * total_filenames_allocated);
258 total_filenames_allocated *= 2;
261 if(num_dirs == total_dirnames_allocated)
263 dir_list = (u8 **)realloc(dir_list, sizeof(u8 *) *
264 total_dirnames_allocated * 2);
265 memset(dir_list + total_dirnames_allocated, 0,
266 sizeof(u8 *) * total_dirnames_allocated);
267 total_dirnames_allocated *= 2;
270 } while(current_file);
272 qsort((void *)file_list, num_files, sizeof(u8 *), sort_function);
273 qsort((void *)dir_list, num_dirs, sizeof(u8 *), sort_function);
275 closedir(current_dir);
277 current_dir_length = strlen(current_dir_name);
279 if(current_dir_length > 80)
283 snprintf(current_dir_short, 80,
284 "...%s", current_dir_name + current_dir_length - 77);
286 memcpy(current_dir_short, "...", 3);
287 memcpy(current_dir_short + 3,
288 current_dir_name + current_dir_length - 77, 77);
289 current_dir_short[80] = 0;
295 snprintf(current_dir_short, 80, "%s", current_dir_name);
297 memcpy(current_dir_short, current_dir_name,
298 current_dir_length + 1);
307 clear_screen(COLOR_BG);
315 print_string(current_dir_short, COLOR_ACTIVE_ITEM, COLOR_BG, 0, 0);
317 print_string("Press X to return to the main menu.",
318 COLOR_HELP_TEXT, COLOR_BG, 20, 220);
320 print_string("Press X to return to the main menu.",
321 COLOR_HELP_TEXT, COLOR_BG, 20, 260);
324 for(i = 0, current_file_number = i + current_file_scroll_value;
325 i < FILE_LIST_ROWS; i++, current_file_number++)
327 if(current_file_number < num_files)
329 if((current_file_number == current_file_selection) &&
330 (current_column == 0))
332 print_string(file_list[current_file_number], COLOR_ACTIVE_ITEM,
333 COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10));
337 print_string(file_list[current_file_number], COLOR_INACTIVE_ITEM,
338 COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10));
343 for(i = 0, current_dir_number = i + current_dir_scroll_value;
344 i < FILE_LIST_ROWS; i++, current_dir_number++)
346 if(current_dir_number < num_dirs)
348 if((current_dir_number == current_dir_selection) &&
349 (current_column == 1))
351 print_string(dir_list[current_dir_number], COLOR_ACTIVE_ITEM,
352 COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10));
356 print_string(dir_list[current_dir_number], COLOR_INACTIVE_ITEM,
357 COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10));
362 gui_action = get_gui_input();
367 if(current_column == 0)
369 if(current_file_selection < (num_files - 1))
371 current_file_selection++;
372 if(current_file_in_scroll == (FILE_LIST_ROWS - 1))
374 clear_screen(COLOR_BG);
375 current_file_scroll_value++;
379 current_file_in_scroll++;
384 clear_screen(COLOR_BG);
385 current_file_selection = 0;
386 current_file_scroll_value = 0;
387 current_file_in_scroll = 0;
392 if(current_dir_selection < (num_dirs - 1))
394 current_dir_selection++;
395 if(current_dir_in_scroll == (FILE_LIST_ROWS - 1))
397 clear_screen(COLOR_BG);
398 current_dir_scroll_value++;
402 current_dir_in_scroll++;
410 if (current_column != 0)
412 clear_screen(COLOR_BG);
413 current_file_selection += FILE_LIST_ROWS;
414 if (current_file_selection > num_files - 1)
415 current_file_selection = num_files - 1;
416 current_file_scroll_value = current_file_selection - FILE_LIST_ROWS / 2;
417 if (current_file_scroll_value < 0)
419 current_file_scroll_value = 0;
420 current_file_in_scroll = current_file_selection;
424 current_file_in_scroll = FILE_LIST_ROWS / 2;
429 if(current_column == 0)
431 if(current_file_selection)
433 current_file_selection--;
434 if(current_file_in_scroll == 0)
436 clear_screen(COLOR_BG);
437 current_file_scroll_value--;
441 current_file_in_scroll--;
446 clear_screen(COLOR_BG);
447 current_file_selection = num_files - 1;
448 current_file_in_scroll = FILE_LIST_ROWS - 1;
449 if (current_file_in_scroll > num_files - 1)
450 current_file_in_scroll = num_files - 1;
451 current_file_scroll_value = num_files - FILE_LIST_ROWS;
452 if (current_file_scroll_value < 0)
453 current_file_scroll_value = 0;
458 if(current_dir_selection)
460 current_dir_selection--;
461 if(current_dir_in_scroll == 0)
463 clear_screen(COLOR_BG);
464 current_dir_scroll_value--;
468 current_dir_in_scroll--;
475 if (current_column != 0)
477 clear_screen(COLOR_BG);
478 current_file_selection -= FILE_LIST_ROWS;
479 if (current_file_selection < 0)
480 current_file_selection = 0;
481 current_file_scroll_value = current_file_selection - FILE_LIST_ROWS / 2;
482 if (current_file_scroll_value < 0)
484 current_file_scroll_value = 0;
485 current_file_in_scroll = current_file_selection;
489 current_file_in_scroll = FILE_LIST_ROWS / 2;
494 if(current_column == 0)
502 if(current_column == 1)
510 if(current_column == 1)
513 chdir(dir_list[current_dir_selection]);
521 strcpy(result, file_list[current_file_selection]);
528 if(!strcmp(current_dir_name, "ms0:/PSP"))
543 for(i = 0; i < num_files; i++)
549 for(i = 0; i < num_dirs; i++)
556 clear_screen(COLOR_BG);
563 NUMBER_SELECTION_OPTION = 0x01,
564 STRING_SELECTION_OPTION = 0x02,
565 SUBMENU_OPTION = 0x04,
567 } menu_option_type_enum;
571 void (* init_function)();
572 void (* passive_function)();
573 struct _menu_option_type *options;
577 struct _menu_option_type
579 void (* action_function)();
580 void (* passive_function)();
581 struct _menu_type *sub_menu;
582 char *display_string;
588 menu_option_type_enum option_type;
591 typedef struct _menu_option_type menu_option_type;
592 typedef struct _menu_type menu_type;
594 #define make_menu(name, init_function, passive_function) \
595 menu_type name##_menu = \
600 sizeof(name##_options) / sizeof(menu_option_type) \
603 #define gamepad_config_option(display_string, number) \
606 menu_fix_gamepad_help, \
608 display_string ": %s", \
609 gamepad_config_buttons, \
610 gamepad_config_map + gamepad_config_line_to_button[number], \
611 sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \
612 gamepad_help[gamepad_config_map[ \
613 gamepad_config_line_to_button[number]]], \
615 STRING_SELECTION_OPTION \
618 #define analog_config_option(display_string, number) \
621 menu_fix_gamepad_help, \
623 display_string ": %s", \
624 gamepad_config_buttons, \
625 gamepad_config_map + number + 12, \
626 sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \
627 gamepad_help[gamepad_config_map[number + 12]], \
629 STRING_SELECTION_OPTION \
632 #define cheat_option(number) \
637 cheat_format_str[number], \
638 enable_disable_options, \
639 &(cheats[number].cheat_active), \
641 "Activate/deactivate this cheat code.", \
643 STRING_SELECTION_OPTION \
646 #define action_option(action_function, passive_function, display_string, \
647 help_string, line_number) \
661 #define submenu_option(sub_menu, display_string, help_string, line_number) \
669 sizeof(sub_menu) / sizeof(menu_option_type), \
675 #define selection_option(passive_function, display_string, options, \
676 option_ptr, num_options, help_string, line_number, type) \
690 #define action_selection_option(action_function, passive_function, \
691 display_string, options, option_ptr, num_options, help_string, line_number, \
703 type | ACTION_OPTION \
707 #define string_selection_option(passive_function, display_string, options, \
708 option_ptr, num_options, help_string, line_number) \
709 selection_option(passive_function, display_string ": %s", options, \
710 option_ptr, num_options, help_string, line_number, STRING_SELECTION_OPTION)\
712 #define numeric_selection_option(passive_function, display_string, \
713 option_ptr, num_options, help_string, line_number) \
714 selection_option(passive_function, display_string ": %d", NULL, option_ptr, \
715 num_options, help_string, line_number, NUMBER_SELECTION_OPTION) \
717 #define string_selection_action_option(action_function, passive_function, \
718 display_string, options, option_ptr, num_options, help_string, line_number) \
719 action_selection_option(action_function, passive_function, \
720 display_string ": %s", options, option_ptr, num_options, help_string, \
721 line_number, STRING_SELECTION_OPTION) \
723 #define numeric_selection_action_option(action_function, passive_function, \
724 display_string, option_ptr, num_options, help_string, line_number) \
725 action_selection_option(action_function, passive_function, \
726 display_string ": %d", NULL, option_ptr, num_options, help_string, \
727 line_number, NUMBER_SELECTION_OPTION) \
729 #define numeric_selection_action_hide_option(action_function, \
730 passive_function, display_string, option_ptr, num_options, help_string, \
732 action_selection_option(action_function, passive_function, \
733 display_string, NULL, option_ptr, num_options, help_string, \
734 line_number, NUMBER_SELECTION_OPTION) \
737 #define GAMEPAD_MENU_WIDTH 15
741 u32 gamepad_config_line_to_button[] =
742 { 8, 6, 7, 9, 1, 2, 3, 0, 4, 5, 11, 10 };
748 u32 gamepad_config_line_to_button[] =
749 { 0, 2, 1, 3, 8, 9, 10, 11, 6, 7, 4, 5, 14 };
753 u8 *scale_options[] =
756 "unscaled 3:2", "scaled 3:2 (slower)",
757 "unscaled 3:2 (anti-tear)", "scaled 3:2 (anti-tear)"
759 "unscaled 3:2", "scaled 3:2", "fullscreen", "scaled 3:2 (software)"
766 s32 load_game_config_file()
768 u8 game_config_filename[512];
771 change_ext(gamepak_filename, game_config_filename, ".cfg");
773 file_open(game_config_file, game_config_filename, read);
775 if(file_check_valid(game_config_file))
777 u32 file_size = file_length(game_config_filename, game_config_file);
779 // Sanity check: File size must be the right size
782 u32 file_options[file_size / 4];
784 file_read_array(game_config_file, file_options);
785 current_frameskip_type = file_options[0] % 3;
786 frameskip_value = file_options[1];
787 random_skip = file_options[2] % 2;
788 clock_speed = file_options[3];
791 if(clock_speed > 900)
793 #elif defined(GP2X_BUILD)
794 if(clock_speed >= 300)
797 if(clock_speed > 333)
804 if(frameskip_value < 0)
807 if(frameskip_value > 99)
808 frameskip_value = 99;
810 for(i = 0; i < 10; i++)
812 cheats[i].cheat_active = file_options[3 + i] % 2;
813 cheats[i].cheat_name[0] = 0;
816 file_close(game_config_file);
824 current_frameskip_type = auto_frameskip;
830 clock_speed = default_clock_speed;
832 for(i = 0; i < 10; i++)
834 cheats[i].cheat_active = 0;
835 cheats[i].cheat_name[0] = 0;
841 s32 load_config_file()
845 #if (defined(PSP_BUILD) || defined(ARM_ARCH)) && !defined(_WIN32_WCE)
846 sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
848 sprintf(config_path, "%s\\%s", main_path, GPSP_CONFIG_FILENAME);
851 file_open(config_file, config_path, read);
853 if(file_check_valid(config_file))
855 u32 file_size = file_length(config_path, config_file);
857 // Sanity check: File size must be the right size
860 u32 file_options[file_size / 4];
862 s32 menu_button = -1;
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;
871 audio_buffer_size_number = file_options[3] % 10;
873 audio_buffer_size_number = file_options[3] % 11;
876 update_backup_flag = file_options[4] % 2;
877 global_enable_analog = file_options[5] % 2;
878 analog_sensitivity_level = file_options[6] % 8;
881 scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2);
884 // Sanity check: Make sure there's a MENU or FRAMESKIP
885 // key, if not assign to triangle
888 for(i = 0; i < 16; i++)
890 gamepad_config_map[i] = file_options[7 + i] %
891 (BUTTON_ID_NONE + 1);
893 if(gamepad_config_map[i] == BUTTON_ID_MENU)
899 if(menu_button == -1)
901 gamepad_config_map[0] = BUTTON_ID_MENU;
905 file_close(config_file);
914 s32 save_game_config_file()
916 u8 game_config_filename[512];
919 change_ext(gamepak_filename, game_config_filename, ".cfg");
921 file_open(game_config_file, game_config_filename, write);
923 if(file_check_valid(game_config_file))
925 u32 file_options[14];
927 file_options[0] = current_frameskip_type;
928 file_options[1] = frameskip_value;
929 file_options[2] = random_skip;
930 file_options[3] = clock_speed;
932 for(i = 0; i < 10; i++)
934 file_options[4 + i] = cheats[i].cheat_active;
937 file_write_array(game_config_file, file_options);
939 file_close(game_config_file);
947 s32 save_config_file()
951 #if (defined(PSP_BUILD) || defined(ARM_ARCH)) && !defined(_WIN32_WCE)
952 sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
954 sprintf(config_path, "%s\\%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[23];
966 file_options[0] = screen_scale;
967 file_options[1] = screen_filter;
968 file_options[2] = global_enable_audio;
969 file_options[3] = audio_buffer_size_number;
970 file_options[4] = update_backup_flag;
971 file_options[5] = global_enable_analog;
972 file_options[6] = analog_sensitivity_level;
975 for(i = 0; i < 16; i++)
977 file_options[7 + i] = gamepad_config_map[i];
981 file_write_array(config_file, file_options);
983 file_close(config_file);
1000 u32 savestate_slot = 0;
1002 void get_savestate_snapshot(u8 *savestate_filename)
1004 u16 snapshot_buffer[240 * 160];
1005 u8 savestate_timestamp_string[80];
1007 file_open(savestate_file, savestate_filename, read);
1009 if(file_check_valid(savestate_file))
1011 u8 weekday_strings[7][11] =
1013 "Sunday", "Monday", "Tuesday", "Wednesday",
1014 "Thursday", "Friday", "Saturday"
1016 time_t savestate_time_flat;
1017 struct tm *current_time;
1018 file_read_array(savestate_file, snapshot_buffer);
1019 file_read_variable(savestate_file, savestate_time_flat);
1021 file_close(savestate_file);
1023 current_time = localtime(&savestate_time_flat);
1024 sprintf(savestate_timestamp_string,
1025 "%s %02d/%02d/%04d %02d:%02d:%02d ",
1026 weekday_strings[current_time->tm_wday], current_time->tm_mon + 1,
1027 current_time->tm_mday, current_time->tm_year + 1900,
1028 current_time->tm_hour, current_time->tm_min, current_time->tm_sec);
1030 savestate_timestamp_string[40] = 0;
1031 print_string(savestate_timestamp_string, COLOR_HELP_TEXT, COLOR_BG,
1036 memset(snapshot_buffer, 0, 240 * 160 * 2);
1037 print_string_ext("No savestate exists for this slot.",
1038 0xFFFF, 0x0000, 15, 75, snapshot_buffer, 240, 0, 0, FONT_HEIGHT);
1039 print_string("---------- --/--/---- --:--:-- ", COLOR_HELP_TEXT,
1044 blit_to_screen(snapshot_buffer, 240, 160, 230, 40);
1048 void get_savestate_filename(u32 slot, u8 *name_buffer)
1050 u8 savestate_ext[16];
1052 sprintf(savestate_ext, "%d.svs", slot);
1053 change_ext(gamepak_filename, name_buffer, savestate_ext);
1055 get_savestate_snapshot(name_buffer);
1058 void get_savestate_filename_noshot(u32 slot, u8 *name_buffer)
1060 u8 savestate_ext[16];
1062 sprintf(savestate_ext, "%d.svs", slot);
1063 change_ext(gamepak_filename, name_buffer, savestate_ext);
1069 invalidate_all_cache();
1073 u32 menu(u16 *original_screen)
1075 u8 print_buffer[81];
1076 u32 clock_speed_number;
1077 u32 _current_option = 0;
1078 gui_action_type gui_action;
1079 menu_enum _current_menu = MAIN_MENU;
1082 u32 return_value = 0;
1084 u8 savestate_ext[16];
1085 u8 current_savestate_filename[512];
1087 u8 cheat_format_str[10][41];
1089 menu_type *current_menu;
1090 menu_option_type *current_option;
1091 menu_option_type *display_option;
1092 u32 current_option_num;
1094 auto void choose_menu();
1095 auto void clear_help();
1097 u8 *gamepad_help[] =
1099 "Up button on GBA d-pad.",
1100 "Down button on GBA d-pad.",
1101 "Left button on GBA d-pad.",
1102 "Right button on GBA d-pad.",
1105 "Left shoulder button on GBA.",
1106 "Right shoulder button on GBA.",
1107 "Start button on GBA.",
1108 "Select button on GBA.",
1109 "Brings up the options menu.",
1110 "Toggles fastforward on/off.",
1111 "Loads the game state from the current slot.",
1112 "Saves the game state to the current slot.",
1113 "Rapidly press/release the A button on GBA.",
1114 "Rapidly press/release the B button on GBA.",
1115 "Rapidly press/release the L shoulder on GBA.",
1116 "Rapidly press/release the R shoulder on GBA.",
1117 "Increases the volume.",
1118 "Decreases the volume.",
1119 "Displays virtual/drawn frames per second.",
1123 void menu_update_clock()
1125 get_clock_speed_number();
1126 if (clock_speed_number < 0 || clock_speed_number >=
1127 sizeof(clock_speed_options) / sizeof(clock_speed_options[0]))
1129 clock_speed = default_clock_speed;
1130 get_clock_speed_number();
1142 menu_get_clock_speed();
1149 u8 *file_ext[] = { ".gba", ".bin", ".zip", NULL };
1150 u8 load_filename[512];
1151 save_game_config_file();
1152 if(load_file(file_ext, load_filename) != -1)
1154 if(load_gamepak(load_filename) == -1)
1161 reg[CHANGED_PC_STATUS] = 1;
1162 menu_update_clock();
1166 choose_menu(current_menu);
1175 reg[CHANGED_PC_STATUS] = 1;
1181 void menu_change_state()
1183 get_savestate_filename(savestate_slot, current_savestate_filename);
1186 void menu_save_state()
1190 get_savestate_filename_noshot(savestate_slot,
1191 current_savestate_filename);
1192 save_state(current_savestate_filename, original_screen);
1194 menu_change_state();
1197 void menu_load_state()
1201 load_state(current_savestate_filename);
1207 void menu_load_state_file()
1209 u8 *file_ext[] = { ".svs", NULL };
1210 u8 load_filename[512];
1211 if(load_file(file_ext, load_filename) != -1)
1213 load_state(load_filename);
1219 choose_menu(current_menu);
1223 void menu_fix_gamepad_help()
1227 current_option->help_string =
1228 gamepad_help[gamepad_config_map[
1229 gamepad_config_line_to_button[current_option_num]]];
1233 void submenu_graphics_sound()
1238 void submenu_cheats_misc()
1243 void submenu_gamepad()
1248 void submenu_analog()
1253 void submenu_savestate()
1255 print_string("Savestate options:", COLOR_ACTIVE_ITEM, COLOR_BG, 10, 70);
1256 menu_change_state();
1261 strncpy(print_buffer, gamepak_filename, 80);
1262 print_string(print_buffer, COLOR_ROM_INFO, COLOR_BG, 10, 10);
1263 sprintf(print_buffer, "%s %s %s", gamepak_title,
1264 gamepak_code, gamepak_maker);
1265 print_string(print_buffer, COLOR_ROM_INFO, COLOR_BG, 10, 20);
1267 get_savestate_filename_noshot(savestate_slot,
1268 current_savestate_filename);
1271 u8 *yes_no_options[] = { "no", "yes" };
1272 u8 *enable_disable_options[] = { "disabled", "enabled" };
1274 u8 *frameskip_options[] = { "automatic", "manual", "off" };
1275 u8 *frameskip_variation_options[] = { "uniform", "random" };
1278 u8 *audio_buffer_options[] =
1280 "16 bytes", "32 bytes", "64 bytes",
1281 "128 bytes", "256 bytes", "512 bytes", "1024 bytes", "2048 bytes",
1282 "4096 bytes", "8192 bytes", "16284 bytes"
1285 u8 *audio_buffer_options[] =
1287 "3072 bytes", "4096 bytes", "5120 bytes", "6144 bytes", "7168 bytes",
1288 "8192 bytes", "9216 bytes", "10240 bytes", "11264 bytes", "12288 bytes"
1293 u8 *update_backup_options[] = { "Exit only", "Automatic" };
1295 u8 *gamepad_config_buttons[] =
1321 // Marker for help information, don't go past this mark (except \n)------*
1322 menu_option_type graphics_sound_options[] =
1324 string_selection_option(NULL, "Display scaling", scale_options,
1325 (u32 *)(&screen_scale),
1326 sizeof(scale_options) / sizeof(scale_options[0]),
1328 "Determines how the GBA screen is resized in relation to the entire\n"
1329 "screen. Select unscaled 3:2 for GBA resolution, scaled 3:2 for GBA\n"
1330 "aspect ratio scaled to fill the height of the PSP screen, and\n"
1331 "fullscreen to fill the entire PSP screen."
1335 string_selection_option(NULL, "Screen filtering", yes_no_options,
1336 (u32 *)(&screen_filter), 2,
1337 "Determines whether or not bilinear filtering should be used when\n"
1338 "scaling the screen. Selecting this will produce a more even and\n"
1339 "smooth image, at the cost of being blurry and having less vibrant\n"
1342 string_selection_option(NULL, "Frameskip type", frameskip_options,
1343 (u32 *)(¤t_frameskip_type), 3,
1345 "Determines what kind of frameskipping to use.\n"
1346 "Frameskipping may improve emulation speed of many games.\n"
1348 "Off: Do not skip any frames.\n"
1349 "Auto: Skip up to N frames (see next opt) as needed.\n"
1350 "Manual: Always render only 1 out of N + 1 frames."
1352 numeric_selection_option(NULL, "Frameskip value", &frameskip_value, 100,
1354 "For auto frameskip, determines the maximum number of frames that\n"
1355 "are allowed to be skipped consecutively.\n"
1356 "For manual frameskip, determines the number of frames that will\n"
1357 "always be skipped."
1360 string_selection_option(NULL, "Framskip variation",
1361 frameskip_variation_options, &random_skip, 2,
1363 "If objects in the game flicker at a regular rate certain manual\n"
1364 "frameskip values may cause them to normally disappear. Change this\n"
1365 "value to 'random' to avoid this. Do not use otherwise, as it tends to\n"
1366 "make the image quality worse, especially in high motion games."
1369 string_selection_option(NULL, "Audio output", yes_no_options,
1370 &global_enable_audio, 2,
1371 "Select 'no' to turn off all audio output. This will\n"
1372 "not result in a significant change in performance.", 9),
1374 string_selection_option(NULL, "Audio buffer", audio_buffer_options,
1375 &audio_buffer_size_number, 11,
1377 string_selection_option(NULL, "Audio buffer", audio_buffer_options,
1378 &audio_buffer_size_number, 10,
1382 "Set the size (in bytes) of the audio buffer. Larger values may result\n"
1383 "in slightly better performance at the cost of latency; the lowest\n"
1384 "value will give the most responsive audio.\n"
1385 "This option requires gpSP to be restarted before it will take effect.",
1387 "Set the size (in bytes) of the audio buffer.\n"
1388 "This option requires gpSP restart to take effect.",
1391 submenu_option(NULL, "Back", "Return to the main menu.", 12)
1394 make_menu(graphics_sound, submenu_graphics_sound, NULL);
1396 menu_option_type cheats_misc_options[] =
1408 string_selection_option(NULL, "Clock speed",
1409 clock_speed_options, &clock_speed_number,
1410 sizeof(clock_speed_options) / sizeof(clock_speed_options[0]),
1411 "Change the clock speed of the device. Higher clock\n"
1412 "speed will yield better performance, but will drain\n"
1413 "battery life further.", 11),
1414 string_selection_option(NULL, "Update backup",
1415 update_backup_options, &update_backup_flag, 2,
1417 "Determines when in-game save files should be\n"
1418 "written back to SD card.",
1420 "Determines when in-game save files should be written back to\n"
1421 "memstick. If set to 'automatic' writebacks will occur shortly after\n"
1422 "the game's backup is altered. On 'exit only' it will only be written\n"
1423 "back when you exit from this menu (NOT from using the home button).\n"
1424 "Use the latter with extreme care.",
1427 submenu_option(NULL, "Back", "Return to the main menu.", 14)
1430 make_menu(cheats_misc, submenu_cheats_misc, NULL);
1432 menu_option_type savestate_options[] =
1434 numeric_selection_action_hide_option(menu_load_state, menu_change_state,
1435 "Load savestate from current slot", &savestate_slot, 10,
1436 "Select to load the game state from the current slot\n"
1438 "Press left + right to change the current slot.", 6),
1439 numeric_selection_action_hide_option(menu_save_state, menu_change_state,
1440 "Save savestate to current slot", &savestate_slot, 10,
1441 "Select to save the game state to the current slot\n"
1443 "Press left + right to change the current slot.", 7),
1444 numeric_selection_action_hide_option(menu_load_state_file,
1446 "Load savestate from file", &savestate_slot, 10,
1447 "Restore gameplay from a savestate file.\n"
1448 "Note: The same file used to save the state must be\n"
1450 numeric_selection_option(menu_change_state,
1451 "Current savestate slot", &savestate_slot, 10,
1452 "Change the current savestate slot.\n", 11),
1453 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1456 make_menu(savestate, submenu_savestate, NULL);
1460 menu_option_type gamepad_config_options[] =
1462 gamepad_config_option("D-pad up ", 0),
1463 gamepad_config_option("D-pad down ", 1),
1464 gamepad_config_option("D-pad left ", 2),
1465 gamepad_config_option("D-pad right ", 3),
1466 gamepad_config_option("Circle ", 4),
1467 gamepad_config_option("Cross ", 5),
1468 gamepad_config_option("Square ", 6),
1469 gamepad_config_option("Triangle ", 7),
1470 gamepad_config_option("Left Trigger ", 8),
1471 gamepad_config_option("Right Trigger", 9),
1472 gamepad_config_option("Start ", 10),
1473 gamepad_config_option("Select ", 11),
1474 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1478 menu_option_type analog_config_options[] =
1480 analog_config_option("Analog up ", 0),
1481 analog_config_option("Analog down ", 1),
1482 analog_config_option("Analog left ", 2),
1483 analog_config_option("Analog right", 3),
1484 string_selection_option(NULL, "Enable analog", yes_no_options,
1485 &global_enable_analog, 2,
1486 "Select 'no' to block analog input entirely.", 7),
1487 numeric_selection_option(NULL, "Analog sensitivity",
1488 &analog_sensitivity_level, 10,
1489 "Determine sensitivity/responsiveness of the analog input.\n"
1490 "Lower numbers are less sensitive.", 8),
1491 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1498 menu_option_type gamepad_config_options[] =
1500 gamepad_config_option("D-pad up ", 0),
1501 gamepad_config_option("D-pad down ", 1),
1502 gamepad_config_option("D-pad left ", 2),
1503 gamepad_config_option("D-pad right ", 3),
1504 gamepad_config_option("A ", 4),
1505 gamepad_config_option("B ", 5),
1506 gamepad_config_option("X ", 6),
1507 gamepad_config_option("Y ", 7),
1508 gamepad_config_option("Left Trigger ", 8),
1509 gamepad_config_option("Right Trigger", 9),
1511 gamepad_config_option("Menu ", 10),
1513 gamepad_config_option("Start ", 10),
1515 gamepad_config_option("Select ", 11),
1517 gamepad_config_option("Stick Push ", 12),
1519 submenu_option(NULL, "Back", "Return to the main menu.", 14)
1523 menu_option_type analog_config_options[] =
1525 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1532 menu_option_type gamepad_config_options[] =
1534 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1537 menu_option_type analog_config_options[] =
1539 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1544 make_menu(gamepad_config, submenu_gamepad, NULL);
1545 make_menu(analog_config, submenu_analog, NULL);
1547 menu_option_type main_options[] =
1549 submenu_option(&graphics_sound_menu, "Graphics and Sound options",
1550 "Select to set display parameters and frameskip\n"
1551 "behavior, audio on/off, buffer size, and filtering.", 0),
1552 numeric_selection_action_option(menu_load_state, NULL,
1553 "Load state from slot", &savestate_slot, 10,
1554 "Select to load the game state from the current slot\n"
1555 "for this game, if it exists.\n"
1556 "Press left + right to change the current slot.", 2),
1557 numeric_selection_action_option(menu_save_state, NULL,
1558 "Save state to slot", &savestate_slot, 10,
1559 "Select to save the game state to the current slot\n"
1560 "for this game. See the extended menu for more info.\n"
1561 "Press left + right to change the current slot.", 3),
1562 submenu_option(&savestate_menu, "Savestate options",
1563 "Select to enter a menu for loading, saving, and\n"
1564 "viewing the currently active savestate for this game\n"
1565 "(or to load a savestate file from another game)", 4),
1566 submenu_option(&gamepad_config_menu, "Configure gamepad input",
1567 "Select to change the in-game behavior of buttons\n"
1570 submenu_option(&analog_config_menu, "Configure analog input",
1571 "Select to change the in-game behavior of the PSP analog nub.", 7),
1573 submenu_option(&cheats_misc_menu, "Cheats and Miscellaneous options",
1574 "Select to manage cheats, set backup behavior,\n"
1575 "and set device clock speed.", 9),
1576 action_option(menu_load, NULL, "Load new game",
1577 "Select to load a new game\n"
1578 "(will exit a game if currently playing).", 11),
1579 action_option(menu_restart, NULL, "Restart game",
1580 "Select to reset the GBA with the current game\n"
1582 action_option(menu_exit, NULL, "Return to game",
1583 "Select to exit this menu and resume gameplay.", 13),
1584 action_option(menu_quit, NULL, "Exit gpSP",
1585 "Select to exit gpSP and return to the menu.", 15)
1588 make_menu(main, submenu_main, NULL);
1590 void choose_menu(menu_type *new_menu)
1592 if(new_menu == NULL)
1593 new_menu = &main_menu;
1595 clear_screen(COLOR_BG);
1598 blit_to_screen(original_screen, 240, 160, 230, 40);
1601 current_menu = new_menu;
1602 current_option = new_menu->options;
1603 current_option_num = 0;
1604 if(current_menu->init_function)
1605 current_menu->init_function();
1610 for(i = 0; i < 6; i++)
1612 print_string_pad(" ", COLOR_BG, COLOR_BG, 8, 210 + (i * 10), 70);
1616 menu_update_clock();
1617 video_resolution_large();
1620 SDL_LockMutex(sound_mutex);
1625 SDL_UnlockMutex(sound_mutex);
1628 if(gamepak_filename[0] == 0)
1631 memset(original_screen, 0x00, 240 * 160 * 2);
1632 print_string_ext("No game loaded yet.", 0xFFFF, 0x0000,
1633 60, 75,original_screen, 240, 0, 0, FONT_HEIGHT);
1636 choose_menu(&main_menu);
1638 for(i = 0; i < 10; i++)
1642 sprintf(cheat_format_str[i], "cheat %d (none loaded)", i);
1646 sprintf(cheat_format_str[i], "cheat %d (%s): %%s", i,
1647 cheats[i].cheat_name);
1651 current_menu->init_function();
1655 display_option = current_menu->options;
1657 for(i = 0; i < current_menu->num_options; i++, display_option++)
1659 if(display_option->option_type & NUMBER_SELECTION_OPTION)
1661 sprintf(line_buffer, display_option->display_string,
1662 *(display_option->current_option));
1666 if(display_option->option_type & STRING_SELECTION_OPTION)
1668 sprintf(line_buffer, display_option->display_string,
1669 ((u32 *)display_option->options)[*(display_option->current_option)]);
1673 strcpy(line_buffer, display_option->display_string);
1676 if(display_option == current_option)
1678 print_string_pad(line_buffer, COLOR_ACTIVE_ITEM, COLOR_BG, 10,
1679 (display_option->line_number * 10) + 40, 41);
1683 print_string_pad(line_buffer, COLOR_INACTIVE_ITEM, COLOR_BG, 10,
1684 (display_option->line_number * 10) + 40, 41);
1688 print_string(current_option->help_string, COLOR_HELP_TEXT,
1693 gui_action = get_gui_input();
1698 current_option_num = (current_option_num + 1) %
1699 current_menu->num_options;
1701 current_option = current_menu->options + current_option_num;
1706 if(current_option_num)
1707 current_option_num--;
1709 current_option_num = current_menu->num_options - 1;
1711 current_option = current_menu->options + current_option_num;
1716 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1717 STRING_SELECTION_OPTION))
1719 *(current_option->current_option) =
1720 (*current_option->current_option + 1) %
1721 current_option->num_options;
1723 if(current_option->passive_function)
1724 current_option->passive_function();
1729 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1730 STRING_SELECTION_OPTION))
1732 u32 current_option_val = *(current_option->current_option);
1734 if(current_option_val)
1735 current_option_val--;
1737 current_option_val = current_option->num_options - 1;
1739 *(current_option->current_option) = current_option_val;
1741 if(current_option->passive_function)
1742 current_option->passive_function();
1747 if(current_menu == &main_menu)
1750 choose_menu(&main_menu);
1754 if(current_option->option_type & ACTION_OPTION)
1755 current_option->action_function();
1757 if(current_option->option_type & SUBMENU_OPTION)
1758 choose_menu(current_option->sub_menu);
1763 set_gba_resolution(screen_scale);
1764 video_resolution_small();
1765 menu_get_clock_speed();
1770 return return_value;