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 #define get_clock_speed() \
83 clock_speed = (clock_speed_number + 1) * 33
84 #define get_clock_speed_number() \
85 clock_speed_number = (clock_speed / 33) - 1
86 #elif defined(WIZ_BUILD)
87 #define get_clock_speed() \
88 clock_speed = 300 + (clock_speed_number * 3333) / 100
89 #define get_clock_speed_number() \
90 clock_speed_number = (clock_speed - 300) / 33
91 #elif defined(GP2X_BUILD)
92 #define get_clock_speed() \
93 clock_speed = 150 + clock_speed_number * 10
94 #define get_clock_speed_number() \
95 clock_speed_number = (clock_speed - 150) / 10
97 #define get_clock_speed() 0
98 #define get_clock_speed_number() 0
103 default_clock_speed = 533;
104 #elif defined(GP2X_BUILD)
105 default_clock_speed = 200;
107 default_clock_speed = 333;
109 int sort_function(const void *dest_str_ptr, const void *src_str_ptr)
111 char *dest_str = *((char **)dest_str_ptr);
112 char *src_str = *((char **)src_str_ptr);
114 if(src_str[0] == '.')
117 if(dest_str[0] == '.')
120 return strcasecmp(dest_str, src_str);
123 s32 load_file(u8 **wildcards, u8 *result)
126 struct dirent *current_file;
127 struct stat file_info;
128 u8 current_dir_name[MAX_PATH];
129 u8 current_dir_short[81];
130 u32 current_dir_length;
131 u32 total_filenames_allocated;
132 u32 total_dirnames_allocated;
138 u32 file_name_length;
140 u32 chosen_file, chosen_dir;
141 u32 dialog_result = 1;
142 s32 return_value = 1;
143 s32 current_file_selection;
144 s32 current_file_scroll_value;
145 u32 current_dir_selection;
146 u32 current_dir_scroll_value;
147 s32 current_file_in_scroll;
148 u32 current_dir_in_scroll;
149 u32 current_file_number, current_dir_number;
150 u32 current_column = 0;
153 gui_action_type gui_action;
155 while(return_value == 1)
157 current_file_selection = 0;
158 current_file_scroll_value = 0;
159 current_dir_selection = 0;
160 current_dir_scroll_value = 0;
161 current_file_in_scroll = 0;
162 current_dir_in_scroll = 0;
164 total_filenames_allocated = 32;
165 total_dirnames_allocated = 32;
166 file_list = (u8 **)malloc(sizeof(u8 *) * 32);
167 dir_list = (u8 **)malloc(sizeof(u8 *) * 32);
168 memset(file_list, 0, sizeof(u8 *) * 32);
169 memset(dir_list, 0, sizeof(u8 *) * 32);
176 getcwd(current_dir_name, MAX_PATH);
178 current_dir = opendir(current_dir_name);
183 current_file = readdir(current_dir);
189 file_name = current_file->d_name;
190 file_name_length = strlen(file_name);
192 if((stat(file_name, &file_info) >= 0) &&
193 ((file_name[0] != '.') || (file_name[1] == '.')))
195 if(S_ISDIR(file_info.st_mode))
198 (u8 *)malloc(file_name_length + 1);
200 sprintf(dir_list[num_dirs], "%s", file_name);
206 // Must match one of the wildcards, also ignore the .
207 if(file_name_length >= 4)
209 if(file_name[file_name_length - 4] == '.')
210 ext_pos = file_name_length - 4;
213 if(file_name[file_name_length - 3] == '.')
214 ext_pos = file_name_length - 3;
219 for(i = 0; wildcards[i] != NULL; i++)
221 if(!strcasecmp((file_name + ext_pos),
224 file_list[num_files] =
225 (u8 *)malloc(file_name_length + 1);
227 sprintf(file_list[num_files], "%s", file_name);
237 if(num_files == total_filenames_allocated)
239 file_list = (u8 **)realloc(file_list, sizeof(u8 *) *
240 total_filenames_allocated * 2);
241 memset(file_list + total_filenames_allocated, 0,
242 sizeof(u8 *) * total_filenames_allocated);
243 total_filenames_allocated *= 2;
246 if(num_dirs == total_dirnames_allocated)
248 dir_list = (u8 **)realloc(dir_list, sizeof(u8 *) *
249 total_dirnames_allocated * 2);
250 memset(dir_list + total_dirnames_allocated, 0,
251 sizeof(u8 *) * total_dirnames_allocated);
252 total_dirnames_allocated *= 2;
255 } while(current_file);
257 qsort((void *)file_list, num_files, sizeof(u8 *), sort_function);
258 qsort((void *)dir_list, num_dirs, sizeof(u8 *), sort_function);
260 closedir(current_dir);
262 current_dir_length = strlen(current_dir_name);
264 if(current_dir_length > 80)
268 snprintf(current_dir_short, 80,
269 "...%s", current_dir_name + current_dir_length - 77);
271 memcpy(current_dir_short, "...", 3);
272 memcpy(current_dir_short + 3,
273 current_dir_name + current_dir_length - 77, 77);
274 current_dir_short[80] = 0;
280 snprintf(current_dir_short, 80, "%s", current_dir_name);
282 memcpy(current_dir_short, current_dir_name,
283 current_dir_length + 1);
292 clear_screen(COLOR_BG);
300 print_string(current_dir_short, COLOR_ACTIVE_ITEM, COLOR_BG, 0, 0);
302 print_string("Press X to return to the main menu.",
303 COLOR_HELP_TEXT, COLOR_BG, 20, 220);
305 print_string("Press X to return to the main menu.",
306 COLOR_HELP_TEXT, COLOR_BG, 20, 260);
309 for(i = 0, current_file_number = i + current_file_scroll_value;
310 i < FILE_LIST_ROWS; i++, current_file_number++)
312 if(current_file_number < num_files)
314 if((current_file_number == current_file_selection) &&
315 (current_column == 0))
317 print_string(file_list[current_file_number], COLOR_ACTIVE_ITEM,
318 COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10));
322 print_string(file_list[current_file_number], COLOR_INACTIVE_ITEM,
323 COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10));
328 for(i = 0, current_dir_number = i + current_dir_scroll_value;
329 i < FILE_LIST_ROWS; i++, current_dir_number++)
331 if(current_dir_number < num_dirs)
333 if((current_dir_number == current_dir_selection) &&
334 (current_column == 1))
336 print_string(dir_list[current_dir_number], COLOR_ACTIVE_ITEM,
337 COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10));
341 print_string(dir_list[current_dir_number], COLOR_INACTIVE_ITEM,
342 COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10));
347 gui_action = get_gui_input();
352 if(current_column == 0)
354 if(current_file_selection < (num_files - 1))
356 current_file_selection++;
357 if(current_file_in_scroll == (FILE_LIST_ROWS - 1))
359 clear_screen(COLOR_BG);
360 current_file_scroll_value++;
364 current_file_in_scroll++;
369 clear_screen(COLOR_BG);
370 current_file_selection = 0;
371 current_file_scroll_value = 0;
372 current_file_in_scroll = 0;
377 if(current_dir_selection < (num_dirs - 1))
379 current_dir_selection++;
380 if(current_dir_in_scroll == (FILE_LIST_ROWS - 1))
382 clear_screen(COLOR_BG);
383 current_dir_scroll_value++;
387 current_dir_in_scroll++;
395 if (current_column != 0)
397 clear_screen(COLOR_BG);
398 current_file_selection += FILE_LIST_ROWS;
399 if (current_file_selection > num_files - 1)
400 current_file_selection = num_files - 1;
401 current_file_scroll_value = current_file_selection - FILE_LIST_ROWS / 2;
402 if (current_file_scroll_value < 0)
404 current_file_scroll_value = 0;
405 current_file_in_scroll = current_file_selection;
409 current_file_in_scroll = FILE_LIST_ROWS / 2;
414 if(current_column == 0)
416 if(current_file_selection)
418 current_file_selection--;
419 if(current_file_in_scroll == 0)
421 clear_screen(COLOR_BG);
422 current_file_scroll_value--;
426 current_file_in_scroll--;
431 clear_screen(COLOR_BG);
432 current_file_selection = num_files - 1;
433 current_file_in_scroll = FILE_LIST_ROWS - 1;
434 if (current_file_in_scroll > num_files - 1)
435 current_file_in_scroll = num_files - 1;
436 current_file_scroll_value = num_files - FILE_LIST_ROWS;
437 if (current_file_scroll_value < 0)
438 current_file_scroll_value = 0;
443 if(current_dir_selection)
445 current_dir_selection--;
446 if(current_dir_in_scroll == 0)
448 clear_screen(COLOR_BG);
449 current_dir_scroll_value--;
453 current_dir_in_scroll--;
460 if (current_column != 0)
462 clear_screen(COLOR_BG);
463 current_file_selection -= FILE_LIST_ROWS;
464 if (current_file_selection < 0)
465 current_file_selection = 0;
466 current_file_scroll_value = current_file_selection - FILE_LIST_ROWS / 2;
467 if (current_file_scroll_value < 0)
469 current_file_scroll_value = 0;
470 current_file_in_scroll = current_file_selection;
474 current_file_in_scroll = FILE_LIST_ROWS / 2;
479 if(current_column == 0)
487 if(current_column == 1)
495 if(current_column == 1)
498 chdir(dir_list[current_dir_selection]);
506 strcpy(result, file_list[current_file_selection]);
513 if(!strcmp(current_dir_name, "ms0:/PSP"))
528 for(i = 0; i < num_files; i++)
534 for(i = 0; i < num_dirs; i++)
541 clear_screen(COLOR_BG);
548 NUMBER_SELECTION_OPTION = 0x01,
549 STRING_SELECTION_OPTION = 0x02,
550 SUBMENU_OPTION = 0x04,
552 } menu_option_type_enum;
556 void (* init_function)();
557 void (* passive_function)();
558 struct _menu_option_type *options;
562 struct _menu_option_type
564 void (* action_function)();
565 void (* passive_function)();
566 struct _menu_type *sub_menu;
567 char *display_string;
573 menu_option_type_enum option_type;
576 typedef struct _menu_option_type menu_option_type;
577 typedef struct _menu_type menu_type;
579 #define make_menu(name, init_function, passive_function) \
580 menu_type name##_menu = \
585 sizeof(name##_options) / sizeof(menu_option_type) \
588 #define gamepad_config_option(display_string, number) \
591 menu_fix_gamepad_help, \
593 display_string ": %s", \
594 gamepad_config_buttons, \
595 gamepad_config_map + gamepad_config_line_to_button[number], \
596 sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \
597 gamepad_help[gamepad_config_map[ \
598 gamepad_config_line_to_button[number]]], \
600 STRING_SELECTION_OPTION \
603 #define analog_config_option(display_string, number) \
606 menu_fix_gamepad_help, \
608 display_string ": %s", \
609 gamepad_config_buttons, \
610 gamepad_config_map + number + 12, \
611 sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \
612 gamepad_help[gamepad_config_map[number + 12]], \
614 STRING_SELECTION_OPTION \
617 #define cheat_option(number) \
622 cheat_format_str[number], \
623 enable_disable_options, \
624 &(cheats[number].cheat_active), \
626 "Activate/deactivate this cheat code.", \
628 STRING_SELECTION_OPTION \
631 #define action_option(action_function, passive_function, display_string, \
632 help_string, line_number) \
646 #define submenu_option(sub_menu, display_string, help_string, line_number) \
654 sizeof(sub_menu) / sizeof(menu_option_type), \
660 #define selection_option(passive_function, display_string, options, \
661 option_ptr, num_options, help_string, line_number, type) \
675 #define action_selection_option(action_function, passive_function, \
676 display_string, options, option_ptr, num_options, help_string, line_number, \
688 type | ACTION_OPTION \
692 #define string_selection_option(passive_function, display_string, options, \
693 option_ptr, num_options, help_string, line_number) \
694 selection_option(passive_function, display_string ": %s", options, \
695 option_ptr, num_options, help_string, line_number, STRING_SELECTION_OPTION)\
697 #define numeric_selection_option(passive_function, display_string, \
698 option_ptr, num_options, help_string, line_number) \
699 selection_option(passive_function, display_string ": %d", NULL, option_ptr, \
700 num_options, help_string, line_number, NUMBER_SELECTION_OPTION) \
702 #define string_selection_action_option(action_function, passive_function, \
703 display_string, options, option_ptr, num_options, help_string, line_number) \
704 action_selection_option(action_function, passive_function, \
705 display_string ": %s", options, option_ptr, num_options, help_string, \
706 line_number, STRING_SELECTION_OPTION) \
708 #define numeric_selection_action_option(action_function, passive_function, \
709 display_string, option_ptr, num_options, help_string, line_number) \
710 action_selection_option(action_function, passive_function, \
711 display_string ": %d", NULL, option_ptr, num_options, help_string, \
712 line_number, NUMBER_SELECTION_OPTION) \
714 #define numeric_selection_action_hide_option(action_function, \
715 passive_function, display_string, option_ptr, num_options, help_string, \
717 action_selection_option(action_function, passive_function, \
718 display_string, NULL, option_ptr, num_options, help_string, \
719 line_number, NUMBER_SELECTION_OPTION) \
722 #define GAMEPAD_MENU_WIDTH 15
726 u32 gamepad_config_line_to_button[] =
727 { 8, 6, 7, 9, 1, 2, 3, 0, 4, 5, 11, 10 };
733 u32 gamepad_config_line_to_button[] =
734 { 0, 2, 1, 3, 8, 9, 10, 11, 6, 7, 4, 5, 14 };
739 s32 load_game_config_file()
741 u8 game_config_filename[512];
744 change_ext(gamepak_filename, game_config_filename, ".cfg");
746 file_open(game_config_file, game_config_filename, read);
748 if(file_check_valid(game_config_file))
750 u32 file_size = file_length(game_config_filename, game_config_file);
752 // Sanity check: File size must be the right size
755 u32 file_options[file_size / 4];
757 file_read_array(game_config_file, file_options);
758 current_frameskip_type = file_options[0] % 3;
759 frameskip_value = file_options[1];
760 random_skip = file_options[2] % 2;
761 clock_speed = file_options[3];
764 if(clock_speed > 900)
766 #elif defined(GP2X_BUILD)
767 if(clock_speed >= 300)
770 if(clock_speed > 333)
777 if(frameskip_value < 0)
780 if(frameskip_value > 99)
781 frameskip_value = 99;
783 for(i = 0; i < 10; i++)
785 cheats[i].cheat_active = file_options[3 + i] % 2;
786 cheats[i].cheat_name[0] = 0;
789 file_close(game_config_file);
797 current_frameskip_type = auto_frameskip;
803 clock_speed = default_clock_speed;
805 for(i = 0; i < 10; i++)
807 cheats[i].cheat_active = 0;
808 cheats[i].cheat_name[0] = 0;
814 s32 load_config_file()
818 #if (defined(PSP_BUILD) || defined(ARM_ARCH)) && !defined(_WIN32_WCE)
819 sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
821 sprintf(config_path, "%s\\%s", main_path, GPSP_CONFIG_FILENAME);
824 file_open(config_file, config_path, read);
826 if(file_check_valid(config_file))
828 u32 file_size = file_length(config_path, config_file);
830 // Sanity check: File size must be the right size
833 u32 file_options[file_size / 4];
835 s32 menu_button = -1;
836 file_read_array(config_file, file_options);
838 screen_scale = file_options[0] % 3;
839 screen_filter = file_options[1] % 2;
840 global_enable_audio = file_options[2] % 2;
843 audio_buffer_size_number = file_options[3] % 10;
845 audio_buffer_size_number = file_options[3] % 11;
848 update_backup_flag = file_options[4] % 2;
849 global_enable_analog = file_options[5] % 2;
850 analog_sensitivity_level = file_options[6] % 8;
853 scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2);
856 // Sanity check: Make sure there's a MENU or FRAMESKIP
857 // key, if not assign to triangle
860 for(i = 0; i < 16; i++)
862 gamepad_config_map[i] = file_options[7 + i] %
863 (BUTTON_ID_NONE + 1);
865 if(gamepad_config_map[i] == BUTTON_ID_MENU)
871 if(menu_button == -1)
873 gamepad_config_map[0] = BUTTON_ID_MENU;
877 file_close(config_file);
886 s32 save_game_config_file()
888 u8 game_config_filename[512];
891 change_ext(gamepak_filename, game_config_filename, ".cfg");
893 file_open(game_config_file, game_config_filename, write);
895 if(file_check_valid(game_config_file))
897 u32 file_options[14];
899 file_options[0] = current_frameskip_type;
900 file_options[1] = frameskip_value;
901 file_options[2] = random_skip;
902 file_options[3] = clock_speed;
904 for(i = 0; i < 10; i++)
906 file_options[4 + i] = cheats[i].cheat_active;
909 file_write_array(game_config_file, file_options);
911 file_close(game_config_file);
919 s32 save_config_file()
923 #if (defined(PSP_BUILD) || defined(ARM_ARCH)) && !defined(_WIN32_WCE)
924 sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
926 sprintf(config_path, "%s\\%s", main_path, GPSP_CONFIG_FILENAME);
929 file_open(config_file, config_path, write);
931 save_game_config_file();
933 if(file_check_valid(config_file))
935 u32 file_options[23];
938 file_options[0] = screen_scale;
939 file_options[1] = screen_filter;
940 file_options[2] = global_enable_audio;
941 file_options[3] = audio_buffer_size_number;
942 file_options[4] = update_backup_flag;
943 file_options[5] = global_enable_analog;
944 file_options[6] = analog_sensitivity_level;
947 for(i = 0; i < 16; i++)
949 file_options[7 + i] = gamepad_config_map[i];
953 file_write_array(config_file, file_options);
955 file_close(config_file);
972 u32 savestate_slot = 0;
974 void get_savestate_snapshot(u8 *savestate_filename)
976 u16 snapshot_buffer[240 * 160];
977 u8 savestate_timestamp_string[80];
979 file_open(savestate_file, savestate_filename, read);
981 if(file_check_valid(savestate_file))
983 u8 weekday_strings[7][11] =
985 "Sunday", "Monday", "Tuesday", "Wednesday",
986 "Thursday", "Friday", "Saturday"
988 time_t savestate_time_flat;
989 struct tm *current_time;
990 file_read_array(savestate_file, snapshot_buffer);
991 file_read_variable(savestate_file, savestate_time_flat);
993 file_close(savestate_file);
995 current_time = localtime(&savestate_time_flat);
996 sprintf(savestate_timestamp_string,
997 "%s %02d/%02d/%04d %02d:%02d:%02d ",
998 weekday_strings[current_time->tm_wday], current_time->tm_mon + 1,
999 current_time->tm_mday, current_time->tm_year + 1900,
1000 current_time->tm_hour, current_time->tm_min, current_time->tm_sec);
1002 savestate_timestamp_string[40] = 0;
1003 print_string(savestate_timestamp_string, COLOR_HELP_TEXT, COLOR_BG,
1008 memset(snapshot_buffer, 0, 240 * 160 * 2);
1009 print_string_ext("No savestate exists for this slot.",
1010 0xFFFF, 0x0000, 15, 75, snapshot_buffer, 240, 0, 0, FONT_HEIGHT);
1011 print_string("---------- --/--/---- --:--:-- ", COLOR_HELP_TEXT,
1016 blit_to_screen(snapshot_buffer, 240, 160, 230, 40);
1020 void get_savestate_filename(u32 slot, u8 *name_buffer)
1022 u8 savestate_ext[16];
1024 sprintf(savestate_ext, "%d.svs", slot);
1025 change_ext(gamepak_filename, name_buffer, savestate_ext);
1027 get_savestate_snapshot(name_buffer);
1030 void get_savestate_filename_noshot(u32 slot, u8 *name_buffer)
1032 u8 savestate_ext[16];
1034 sprintf(savestate_ext, "%d.svs", slot);
1035 change_ext(gamepak_filename, name_buffer, savestate_ext);
1041 invalidate_all_cache();
1045 u32 menu(u16 *original_screen)
1047 u32 clock_speed_number;
1048 static u32 clock_speed_old = default_clock_speed;
1049 u8 print_buffer[81];
1050 u32 _current_option = 0;
1051 gui_action_type gui_action;
1052 menu_enum _current_menu = MAIN_MENU;
1055 u32 return_value = 0;
1057 u8 savestate_ext[16];
1058 u8 current_savestate_filename[512];
1060 u8 cheat_format_str[10][41];
1062 menu_type *current_menu;
1063 menu_option_type *current_option;
1064 menu_option_type *display_option;
1065 u32 current_option_num;
1067 auto void choose_menu();
1068 auto void clear_help();
1070 u8 *gamepad_help[] =
1072 "Up button on GBA d-pad.",
1073 "Down button on GBA d-pad.",
1074 "Left button on GBA d-pad.",
1075 "Right button on GBA d-pad.",
1078 "Left shoulder button on GBA.",
1079 "Right shoulder button on GBA.",
1080 "Start button on GBA.",
1081 "Select button on GBA.",
1082 "Brings up the options menu.",
1083 "Toggles fastforward on/off.",
1084 "Loads the game state from the current slot.",
1085 "Saves the game state to the current slot.",
1086 "Rapidly press/release the A button on GBA.",
1087 "Rapidly press/release the B button on GBA.",
1088 "Rapidly press/release the L shoulder on GBA.",
1089 "Rapidly press/release the R shoulder on GBA.",
1090 "Increases the volume.",
1091 "Decreases the volume.",
1092 "Displays virtual/drawn frames per second.",
1111 u8 *file_ext[] = { ".gba", ".bin", ".zip", NULL };
1112 u8 load_filename[512];
1113 save_game_config_file();
1114 if(load_file(file_ext, load_filename) != -1)
1116 if(load_gamepak(load_filename) == -1)
1123 reg[CHANGED_PC_STATUS] = 1;
1127 choose_menu(current_menu);
1136 reg[CHANGED_PC_STATUS] = 1;
1142 void menu_change_state()
1144 get_savestate_filename(savestate_slot, current_savestate_filename);
1147 void menu_save_state()
1151 get_savestate_filename_noshot(savestate_slot,
1152 current_savestate_filename);
1153 save_state(current_savestate_filename, original_screen);
1155 menu_change_state();
1158 void menu_load_state()
1162 load_state(current_savestate_filename);
1168 void menu_load_state_file()
1170 u8 *file_ext[] = { ".svs", NULL };
1171 u8 load_filename[512];
1172 if(load_file(file_ext, load_filename) != -1)
1174 load_state(load_filename);
1180 choose_menu(current_menu);
1184 void menu_fix_gamepad_help()
1188 current_option->help_string =
1189 gamepad_help[gamepad_config_map[
1190 gamepad_config_line_to_button[current_option_num]]];
1194 void submenu_graphics_sound()
1199 void submenu_cheats_misc()
1204 void submenu_gamepad()
1209 void submenu_analog()
1214 void submenu_savestate()
1216 print_string("Savestate options:", COLOR_ACTIVE_ITEM, COLOR_BG, 10, 70);
1217 menu_change_state();
1222 strncpy(print_buffer, gamepak_filename, 80);
1223 print_string(print_buffer, COLOR_ROM_INFO, COLOR_BG, 10, 10);
1224 sprintf(print_buffer, "%s %s %s", gamepak_title,
1225 gamepak_code, gamepak_maker);
1226 print_string(print_buffer, COLOR_ROM_INFO, COLOR_BG, 10, 20);
1228 get_savestate_filename_noshot(savestate_slot,
1229 current_savestate_filename);
1232 u8 *yes_no_options[] = { "no", "yes" };
1233 u8 *enable_disable_options[] = { "disabled", "enabled" };
1235 u8 *scale_options[] =
1238 "unscaled 3:2", "scaled 3:2 (slower)",
1239 "unscaled 3:2 (anti-tear)", "scaled 3:2 (anti-tear)"
1241 "unscaled 3:2", "scaled 3:2", "fullscreen"
1248 u8 *frameskip_options[] = { "automatic", "manual", "off" };
1249 u8 *frameskip_variation_options[] = { "uniform", "random" };
1252 u8 *audio_buffer_options[] =
1254 "16 bytes", "32 bytes", "64 bytes",
1255 "128 bytes", "256 bytes", "512 bytes", "1024 bytes", "2048 bytes",
1256 "4096 bytes", "8192 bytes", "16284 bytes"
1259 u8 *audio_buffer_options[] =
1261 "3072 bytes", "4096 bytes", "5120 bytes", "6144 bytes", "7168 bytes",
1262 "8192 bytes", "9216 bytes", "10240 bytes", "11264 bytes", "12288 bytes"
1267 u8 *update_backup_options[] = { "Exit only", "Automatic" };
1270 u8 *clock_speed_options[] =
1272 "300MHz", "333MHz", "366MHz", "400MHz", "433MHz",
1273 "466MHz", "500MHz", "533MHz", "566MHz", "600MHz",
1274 "633MHz", "666MHz", "700MHz", "733MHz", "766MHz",
1275 "800MHz", "833MHz", "866MHz", "900MHz"
1277 #elif defined(GP2X_BUILD)
1278 u8 *clock_speed_options[] =
1280 "150MHz", "160MHz", "170MHz", "180MHz", "190MHz",
1281 "200MHz", "210MHz", "220MHz", "230MHz", "240MHz",
1282 "250MHz", "260MHz", "270MHz", "280MHz", "290MHz"
1285 u8 *clock_speed_options[] =
1287 "33MHz", "66MHz", "100MHz", "133MHz", "166MHz", "200MHz", "233MHz",
1288 "266MHz", "300MHz", "333MHz"
1292 u8 *gamepad_config_buttons[] =
1318 // Marker for help information, don't go past this mark (except \n)------*
1319 menu_option_type graphics_sound_options[] =
1321 string_selection_option(NULL, "Display scaling", scale_options,
1322 (u32 *)(&screen_scale),
1323 sizeof(scale_options) / sizeof(scale_options[0]),
1325 "Determines how the GBA screen is resized in relation to the entire\n"
1326 "screen. 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."
1332 string_selection_option(NULL, "Screen filtering", yes_no_options,
1333 (u32 *)(&screen_filter), 2,
1334 "Determines whether or not bilinear filtering should be used when\n"
1335 "scaling the screen. Selecting this will produce a more even and\n"
1336 "smooth image, at the cost of being blurry and having less vibrant\n"
1339 string_selection_option(NULL, "Frameskip type", frameskip_options,
1340 (u32 *)(¤t_frameskip_type), 3,
1342 "Determines what kind of frameskipping to use.\n"
1343 "Frameskipping may improve emulation speed of many games.\n"
1345 "Off: Do not skip any frames.\n"
1346 "Auto: Skip up to N frames (see next opt) as needed.\n"
1347 "Manual: Always render only 1 out of N + 1 frames."
1349 numeric_selection_option(NULL, "Frameskip value", &frameskip_value, 100,
1351 "For auto frameskip, determines the maximum number of frames that\n"
1352 "are allowed to be skipped consecutively.\n"
1353 "For manual frameskip, determines the number of frames that will\n"
1354 "always be skipped."
1357 string_selection_option(NULL, "Framskip variation",
1358 frameskip_variation_options, &random_skip, 2,
1360 "If objects in the game flicker at a regular rate certain manual\n"
1361 "frameskip values may cause them to normally disappear. Change this\n"
1362 "value to 'random' to avoid this. Do not use otherwise, as it tends to\n"
1363 "make the image quality worse, especially in high motion games."
1366 string_selection_option(NULL, "Audio output", yes_no_options,
1367 &global_enable_audio, 2,
1368 "Select 'no' to turn off all audio output. This will\n"
1369 "not result in a significant change in performance.", 9),
1371 string_selection_option(NULL, "Audio buffer", audio_buffer_options,
1372 &audio_buffer_size_number, 11,
1374 string_selection_option(NULL, "Audio buffer", audio_buffer_options,
1375 &audio_buffer_size_number, 10,
1379 "Set the size (in bytes) of the audio buffer. Larger values may result\n"
1380 "in slightly better performance at the cost of latency; the lowest\n"
1381 "value will give the most responsive audio.\n"
1382 "This option requires gpSP to be restarted before it will take effect.",
1384 "Set the size (in bytes) of the audio buffer.\n"
1385 "This option requires gpSP restart to take effect.",
1388 submenu_option(NULL, "Back", "Return to the main menu.", 12)
1391 make_menu(graphics_sound, submenu_graphics_sound, NULL);
1393 menu_option_type cheats_misc_options[] =
1405 string_selection_option(NULL, "Clock speed",
1406 clock_speed_options, &clock_speed_number,
1407 sizeof(clock_speed_options) / sizeof(clock_speed_options[0]),
1408 "Change the clock speed of the device. Higher clock\n"
1409 "speed will yield better performance, but will drain\n"
1410 "battery life further.", 11),
1411 string_selection_option(NULL, "Update backup",
1412 update_backup_options, &update_backup_flag, 2,
1414 "Determines when in-game save files should be\n"
1415 "written back to SD card.",
1417 "Determines when in-game save files should be written back to\n"
1418 "memstick. If set to 'automatic' writebacks will occur shortly after\n"
1419 "the game's backup is altered. On 'exit only' it will only be written\n"
1420 "back when you exit from this menu (NOT from using the home button).\n"
1421 "Use the latter with extreme care.",
1424 submenu_option(NULL, "Back", "Return to the main menu.", 14)
1427 make_menu(cheats_misc, submenu_cheats_misc, NULL);
1429 menu_option_type savestate_options[] =
1431 numeric_selection_action_hide_option(menu_load_state, menu_change_state,
1432 "Load savestate from current slot", &savestate_slot, 10,
1433 "Select to load the game state from the current slot\n"
1435 "Press left + right to change the current slot.", 6),
1436 numeric_selection_action_hide_option(menu_save_state, menu_change_state,
1437 "Save savestate to current slot", &savestate_slot, 10,
1438 "Select to save the game state to the current slot\n"
1440 "Press left + right to change the current slot.", 7),
1441 numeric_selection_action_hide_option(menu_load_state_file,
1443 "Load savestate from file", &savestate_slot, 10,
1444 "Restore gameplay from a savestate file.\n"
1445 "Note: The same file used to save the state must be\n"
1447 numeric_selection_option(menu_change_state,
1448 "Current savestate slot", &savestate_slot, 10,
1449 "Change the current savestate slot.\n", 11),
1450 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1453 make_menu(savestate, submenu_savestate, NULL);
1457 menu_option_type gamepad_config_options[] =
1459 gamepad_config_option("D-pad up ", 0),
1460 gamepad_config_option("D-pad down ", 1),
1461 gamepad_config_option("D-pad left ", 2),
1462 gamepad_config_option("D-pad right ", 3),
1463 gamepad_config_option("Circle ", 4),
1464 gamepad_config_option("Cross ", 5),
1465 gamepad_config_option("Square ", 6),
1466 gamepad_config_option("Triangle ", 7),
1467 gamepad_config_option("Left Trigger ", 8),
1468 gamepad_config_option("Right Trigger", 9),
1469 gamepad_config_option("Start ", 10),
1470 gamepad_config_option("Select ", 11),
1471 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1475 menu_option_type analog_config_options[] =
1477 analog_config_option("Analog up ", 0),
1478 analog_config_option("Analog down ", 1),
1479 analog_config_option("Analog left ", 2),
1480 analog_config_option("Analog right", 3),
1481 string_selection_option(NULL, "Enable analog", yes_no_options,
1482 &global_enable_analog, 2,
1483 "Select 'no' to block analog input entirely.", 7),
1484 numeric_selection_option(NULL, "Analog sensitivity",
1485 &analog_sensitivity_level, 10,
1486 "Determine sensitivity/responsiveness of the analog input.\n"
1487 "Lower numbers are less sensitive.", 8),
1488 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1495 menu_option_type gamepad_config_options[] =
1497 gamepad_config_option("D-pad up ", 0),
1498 gamepad_config_option("D-pad down ", 1),
1499 gamepad_config_option("D-pad left ", 2),
1500 gamepad_config_option("D-pad right ", 3),
1501 gamepad_config_option("A ", 4),
1502 gamepad_config_option("B ", 5),
1503 gamepad_config_option("X ", 6),
1504 gamepad_config_option("Y ", 7),
1505 gamepad_config_option("Left Trigger ", 8),
1506 gamepad_config_option("Right Trigger", 9),
1508 gamepad_config_option("Menu ", 10),
1510 gamepad_config_option("Start ", 10),
1512 gamepad_config_option("Select ", 11),
1514 gamepad_config_option("Stick Push ", 12),
1516 submenu_option(NULL, "Back", "Return to the main menu.", 14)
1520 menu_option_type analog_config_options[] =
1522 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1529 menu_option_type gamepad_config_options[] =
1531 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1534 menu_option_type analog_config_options[] =
1536 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1541 make_menu(gamepad_config, submenu_gamepad, NULL);
1542 make_menu(analog_config, submenu_analog, NULL);
1544 menu_option_type main_options[] =
1546 submenu_option(&graphics_sound_menu, "Graphics and Sound options",
1547 "Select to set display parameters and frameskip\n"
1548 "behavior, audio on/off, buffer size, and filtering.", 0),
1549 numeric_selection_action_option(menu_load_state, NULL,
1550 "Load state from slot", &savestate_slot, 10,
1551 "Select to load the game state from the current slot\n"
1552 "for this game, if it exists.\n"
1553 "Press left + right to change the current slot.", 2),
1554 numeric_selection_action_option(menu_save_state, NULL,
1555 "Save state to slot", &savestate_slot, 10,
1556 "Select to save the game state to the current slot\n"
1557 "for this game. See the extended menu for more info.\n"
1558 "Press left + right to change the current slot.", 3),
1559 submenu_option(&savestate_menu, "Savestate options",
1560 "Select to enter a menu for loading, saving, and\n"
1561 "viewing the currently active savestate for this game\n"
1562 "(or to load a savestate file from another game)", 4),
1563 submenu_option(&gamepad_config_menu, "Configure gamepad input",
1564 "Select to change the in-game behavior of buttons\n"
1567 submenu_option(&analog_config_menu, "Configure analog input",
1568 "Select to change the in-game behavior of the PSP analog nub.", 7),
1570 submenu_option(&cheats_misc_menu, "Cheats and Miscellaneous options",
1571 "Select to manage cheats, set backup behavior,\n"
1572 "and set device clock speed.", 9),
1573 action_option(menu_load, NULL, "Load new game",
1574 "Select to load a new game\n"
1575 "(will exit a game if currently playing).", 11),
1576 action_option(menu_restart, NULL, "Restart game",
1577 "Select to reset the GBA with the current game\n"
1579 action_option(menu_exit, NULL, "Return to game",
1580 "Select to exit this menu and resume gameplay.", 13),
1581 action_option(menu_quit, NULL, "Exit gpSP",
1582 "Select to exit gpSP and return to the menu.", 15)
1585 make_menu(main, submenu_main, NULL);
1587 void choose_menu(menu_type *new_menu)
1589 if(new_menu == NULL)
1590 new_menu = &main_menu;
1592 clear_screen(COLOR_BG);
1595 blit_to_screen(original_screen, 240, 160, 230, 40);
1598 current_menu = new_menu;
1599 current_option = new_menu->options;
1600 current_option_num = 0;
1601 if(current_menu->init_function)
1602 current_menu->init_function();
1607 for(i = 0; i < 6; i++)
1609 print_string_pad(" ", COLOR_BG, COLOR_BG, 8, 210 + (i * 10), 70);
1613 get_clock_speed_number();
1614 if (clock_speed_number < 0 || clock_speed_number >=
1615 sizeof(clock_speed_options) / sizeof(clock_speed_options[0]))
1617 clock_speed = default_clock_speed;
1618 get_clock_speed_number();
1621 video_resolution_large();
1624 SDL_LockMutex(sound_mutex);
1629 SDL_UnlockMutex(sound_mutex);
1632 if(gamepak_filename[0] == 0)
1635 memset(original_screen, 0x00, 240 * 160 * 2);
1636 print_string_ext("No game loaded yet.", 0xFFFF, 0x0000,
1637 60, 75,original_screen, 240, 0, 0, FONT_HEIGHT);
1640 choose_menu(&main_menu);
1642 for(i = 0; i < 10; i++)
1646 sprintf(cheat_format_str[i], "cheat %d (none loaded)", i);
1650 sprintf(cheat_format_str[i], "cheat %d (%s): %%s", i,
1651 cheats[i].cheat_name);
1655 current_menu->init_function();
1659 display_option = current_menu->options;
1661 for(i = 0; i < current_menu->num_options; i++, display_option++)
1663 if(display_option->option_type & NUMBER_SELECTION_OPTION)
1665 sprintf(line_buffer, display_option->display_string,
1666 *(display_option->current_option));
1670 if(display_option->option_type & STRING_SELECTION_OPTION)
1672 sprintf(line_buffer, display_option->display_string,
1673 ((u32 *)display_option->options)[*(display_option->current_option)]);
1677 strcpy(line_buffer, display_option->display_string);
1680 if(display_option == current_option)
1682 print_string_pad(line_buffer, COLOR_ACTIVE_ITEM, COLOR_BG, 10,
1683 (display_option->line_number * 10) + 40, 41);
1687 print_string_pad(line_buffer, COLOR_INACTIVE_ITEM, COLOR_BG, 10,
1688 (display_option->line_number * 10) + 40, 41);
1692 print_string(current_option->help_string, COLOR_HELP_TEXT,
1697 gui_action = get_gui_input();
1702 current_option_num = (current_option_num + 1) %
1703 current_menu->num_options;
1705 current_option = current_menu->options + current_option_num;
1710 if(current_option_num)
1711 current_option_num--;
1713 current_option_num = current_menu->num_options - 1;
1715 current_option = current_menu->options + current_option_num;
1720 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1721 STRING_SELECTION_OPTION))
1723 *(current_option->current_option) =
1724 (*current_option->current_option + 1) %
1725 current_option->num_options;
1727 if(current_option->passive_function)
1728 current_option->passive_function();
1733 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1734 STRING_SELECTION_OPTION))
1736 u32 current_option_val = *(current_option->current_option);
1738 if(current_option_val)
1739 current_option_val--;
1741 current_option_val = current_option->num_options - 1;
1743 *(current_option->current_option) = current_option_val;
1745 if(current_option->passive_function)
1746 current_option->passive_function();
1751 if(current_menu == &main_menu)
1754 choose_menu(&main_menu);
1758 if(current_option->option_type & ACTION_OPTION)
1759 current_option->action_function();
1761 if(current_option->option_type & SUBMENU_OPTION)
1762 choose_menu(current_option->sub_menu);
1767 set_gba_resolution(screen_scale);
1768 video_resolution_small();
1771 if (clock_speed != clock_speed_old)
1773 printf("about to set CPU clock to %iMHz\n", clock_speed);
1775 scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2);
1776 #elif defined(GP2X_BUILD)
1777 set_FCLK(clock_speed);
1779 clock_speed_old = clock_speed;
1784 return return_value;