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 u32 current_file_selection;
144 u32 current_file_scroll_value;
145 u32 current_dir_selection;
146 u32 current_dir_scroll_value;
147 u32 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++;
370 if(current_dir_selection < (num_dirs - 1))
372 current_dir_selection++;
373 if(current_dir_in_scroll == (FILE_LIST_ROWS - 1))
375 clear_screen(COLOR_BG);
376 current_dir_scroll_value++;
380 current_dir_in_scroll++;
388 if(current_column == 0)
390 if(current_file_selection)
392 current_file_selection--;
393 if(current_file_in_scroll == 0)
395 clear_screen(COLOR_BG);
396 current_file_scroll_value--;
400 current_file_in_scroll--;
406 if(current_dir_selection)
408 current_dir_selection--;
409 if(current_dir_in_scroll == 0)
411 clear_screen(COLOR_BG);
412 current_dir_scroll_value--;
416 current_dir_in_scroll--;
423 if(current_column == 0)
431 if(current_column == 1)
439 if(current_column == 1)
442 chdir(dir_list[current_dir_selection]);
450 strcpy(result, file_list[current_file_selection]);
457 if(!strcmp(current_dir_name, "ms0:/PSP"))
472 for(i = 0; i < num_files; i++)
478 for(i = 0; i < num_dirs; i++)
485 clear_screen(COLOR_BG);
492 NUMBER_SELECTION_OPTION = 0x01,
493 STRING_SELECTION_OPTION = 0x02,
494 SUBMENU_OPTION = 0x04,
496 } menu_option_type_enum;
500 void (* init_function)();
501 void (* passive_function)();
502 struct _menu_option_type *options;
506 struct _menu_option_type
508 void (* action_function)();
509 void (* passive_function)();
510 struct _menu_type *sub_menu;
511 char *display_string;
517 menu_option_type_enum option_type;
520 typedef struct _menu_option_type menu_option_type;
521 typedef struct _menu_type menu_type;
523 #define make_menu(name, init_function, passive_function) \
524 menu_type name##_menu = \
529 sizeof(name##_options) / sizeof(menu_option_type) \
532 #define gamepad_config_option(display_string, number) \
535 menu_fix_gamepad_help, \
537 display_string ": %s", \
538 gamepad_config_buttons, \
539 gamepad_config_map + gamepad_config_line_to_button[number], \
540 sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \
541 gamepad_help[gamepad_config_map[ \
542 gamepad_config_line_to_button[number]]], \
544 STRING_SELECTION_OPTION \
547 #define analog_config_option(display_string, number) \
550 menu_fix_gamepad_help, \
552 display_string ": %s", \
553 gamepad_config_buttons, \
554 gamepad_config_map + number + 12, \
555 sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \
556 gamepad_help[gamepad_config_map[number + 12]], \
558 STRING_SELECTION_OPTION \
561 #define cheat_option(number) \
566 cheat_format_str[number], \
567 enable_disable_options, \
568 &(cheats[number].cheat_active), \
570 "Activate/deactivate this cheat code.", \
572 STRING_SELECTION_OPTION \
575 #define action_option(action_function, passive_function, display_string, \
576 help_string, line_number) \
590 #define submenu_option(sub_menu, display_string, help_string, line_number) \
598 sizeof(sub_menu) / sizeof(menu_option_type), \
604 #define selection_option(passive_function, display_string, options, \
605 option_ptr, num_options, help_string, line_number, type) \
619 #define action_selection_option(action_function, passive_function, \
620 display_string, options, option_ptr, num_options, help_string, line_number, \
632 type | ACTION_OPTION \
636 #define string_selection_option(passive_function, display_string, options, \
637 option_ptr, num_options, help_string, line_number) \
638 selection_option(passive_function, display_string ": %s", options, \
639 option_ptr, num_options, help_string, line_number, STRING_SELECTION_OPTION)\
641 #define numeric_selection_option(passive_function, display_string, \
642 option_ptr, num_options, help_string, line_number) \
643 selection_option(passive_function, display_string ": %d", NULL, option_ptr, \
644 num_options, help_string, line_number, NUMBER_SELECTION_OPTION) \
646 #define string_selection_action_option(action_function, passive_function, \
647 display_string, options, option_ptr, num_options, help_string, line_number) \
648 action_selection_option(action_function, passive_function, \
649 display_string ": %s", options, option_ptr, num_options, help_string, \
650 line_number, STRING_SELECTION_OPTION) \
652 #define numeric_selection_action_option(action_function, passive_function, \
653 display_string, option_ptr, num_options, help_string, line_number) \
654 action_selection_option(action_function, passive_function, \
655 display_string ": %d", NULL, option_ptr, num_options, help_string, \
656 line_number, NUMBER_SELECTION_OPTION) \
658 #define numeric_selection_action_hide_option(action_function, \
659 passive_function, display_string, option_ptr, num_options, help_string, \
661 action_selection_option(action_function, passive_function, \
662 display_string, NULL, option_ptr, num_options, help_string, \
663 line_number, NUMBER_SELECTION_OPTION) \
666 #define GAMEPAD_MENU_WIDTH 15
670 u32 gamepad_config_line_to_button[] =
671 { 8, 6, 7, 9, 1, 2, 3, 0, 4, 5, 11, 10 };
677 u32 gamepad_config_line_to_button[] =
678 { 0, 2, 1, 3, 8, 9, 10, 11, 6, 7, 4, 5, 14 };
683 s32 load_game_config_file()
685 u8 game_config_filename[512];
688 change_ext(gamepak_filename, game_config_filename, ".cfg");
690 file_open(game_config_file, game_config_filename, read);
692 if(file_check_valid(game_config_file))
694 u32 file_size = file_length(game_config_filename, game_config_file);
696 // Sanity check: File size must be the right size
699 u32 file_options[file_size / 4];
701 file_read_array(game_config_file, file_options);
702 current_frameskip_type = file_options[0] % 3;
703 frameskip_value = file_options[1];
704 random_skip = file_options[2] % 2;
705 clock_speed = file_options[3];
708 if(clock_speed > 900)
710 #elif defined(GP2X_BUILD)
711 if(clock_speed >= 300)
714 if(clock_speed > 333)
721 if(frameskip_value < 0)
724 if(frameskip_value > 99)
725 frameskip_value = 99;
727 for(i = 0; i < 10; i++)
729 cheats[i].cheat_active = file_options[3 + i] % 2;
730 cheats[i].cheat_name[0] = 0;
733 file_close(game_config_file);
741 current_frameskip_type = auto_frameskip;
744 clock_speed = default_clock_speed;
746 for(i = 0; i < 10; i++)
748 cheats[i].cheat_active = 0;
749 cheats[i].cheat_name[0] = 0;
755 s32 load_config_file()
759 #if (defined(PSP_BUILD) || defined(ARM_ARCH)) && !defined(_WIN32_WCE)
760 sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
762 sprintf(config_path, "%s\\%s", main_path, GPSP_CONFIG_FILENAME);
765 file_open(config_file, config_path, read);
767 if(file_check_valid(config_file))
769 u32 file_size = file_length(config_path, config_file);
771 // Sanity check: File size must be the right size
774 u32 file_options[file_size / 4];
776 s32 menu_button = -1;
777 file_read_array(config_file, file_options);
779 screen_scale = file_options[0] % 3;
780 screen_filter = file_options[1] % 2;
781 global_enable_audio = file_options[2] % 2;
784 audio_buffer_size_number = file_options[3] % 10;
786 audio_buffer_size_number = file_options[3] % 11;
789 update_backup_flag = file_options[4] % 2;
790 global_enable_analog = file_options[5] % 2;
791 analog_sensitivity_level = file_options[6] % 8;
794 scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2);
797 // Sanity check: Make sure there's a MENU or FRAMESKIP
798 // key, if not assign to triangle
801 for(i = 0; i < 16; i++)
803 gamepad_config_map[i] = file_options[7 + i] %
804 (BUTTON_ID_NONE + 1);
806 if(gamepad_config_map[i] == BUTTON_ID_MENU)
812 if(menu_button == -1)
814 gamepad_config_map[0] = BUTTON_ID_MENU;
818 file_close(config_file);
827 s32 save_game_config_file()
829 u8 game_config_filename[512];
832 change_ext(gamepak_filename, game_config_filename, ".cfg");
834 file_open(game_config_file, game_config_filename, write);
836 if(file_check_valid(game_config_file))
838 u32 file_options[14];
840 file_options[0] = current_frameskip_type;
841 file_options[1] = frameskip_value;
842 file_options[2] = random_skip;
843 file_options[3] = clock_speed;
845 for(i = 0; i < 10; i++)
847 file_options[4 + i] = cheats[i].cheat_active;
850 file_write_array(game_config_file, file_options);
852 file_close(game_config_file);
860 s32 save_config_file()
864 #if (defined(PSP_BUILD) || defined(ARM_ARCH)) && !defined(_WIN32_WCE)
865 sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
867 sprintf(config_path, "%s\\%s", main_path, GPSP_CONFIG_FILENAME);
870 file_open(config_file, config_path, write);
872 save_game_config_file();
874 if(file_check_valid(config_file))
876 u32 file_options[23];
879 file_options[0] = screen_scale;
880 file_options[1] = screen_filter;
881 file_options[2] = global_enable_audio;
882 file_options[3] = audio_buffer_size_number;
883 file_options[4] = update_backup_flag;
884 file_options[5] = global_enable_analog;
885 file_options[6] = analog_sensitivity_level;
888 for(i = 0; i < 16; i++)
890 file_options[7 + i] = gamepad_config_map[i];
894 file_write_array(config_file, file_options);
896 file_close(config_file);
913 u32 savestate_slot = 0;
915 void get_savestate_snapshot(u8 *savestate_filename)
917 u16 snapshot_buffer[240 * 160];
918 u8 savestate_timestamp_string[80];
920 file_open(savestate_file, savestate_filename, read);
922 if(file_check_valid(savestate_file))
924 u8 weekday_strings[7][11] =
926 "Sunday", "Monday", "Tuesday", "Wednesday",
927 "Thursday", "Friday", "Saturday"
929 time_t savestate_time_flat;
930 struct tm *current_time;
931 file_read_array(savestate_file, snapshot_buffer);
932 file_read_variable(savestate_file, savestate_time_flat);
934 file_close(savestate_file);
936 current_time = localtime(&savestate_time_flat);
937 sprintf(savestate_timestamp_string,
938 "%s %02d/%02d/%04d %02d:%02d:%02d ",
939 weekday_strings[current_time->tm_wday], current_time->tm_mon + 1,
940 current_time->tm_mday, current_time->tm_year + 1900,
941 current_time->tm_hour, current_time->tm_min, current_time->tm_sec);
943 savestate_timestamp_string[40] = 0;
944 print_string(savestate_timestamp_string, COLOR_HELP_TEXT, COLOR_BG,
949 memset(snapshot_buffer, 0, 240 * 160 * 2);
950 print_string_ext("No savestate exists for this slot.",
951 0xFFFF, 0x0000, 15, 75, snapshot_buffer, 240, 0);
952 print_string("---------- --/--/---- --:--:-- ", COLOR_HELP_TEXT,
957 blit_to_screen(snapshot_buffer, 240, 160, 230, 40);
961 void get_savestate_filename(u32 slot, u8 *name_buffer)
963 u8 savestate_ext[16];
965 sprintf(savestate_ext, "%d.svs", slot);
966 change_ext(gamepak_filename, name_buffer, savestate_ext);
968 get_savestate_snapshot(name_buffer);
971 void get_savestate_filename_noshot(u32 slot, u8 *name_buffer)
973 u8 savestate_ext[16];
975 sprintf(savestate_ext, "%d.svs", slot);
976 change_ext(gamepak_filename, name_buffer, savestate_ext);
982 invalidate_all_cache();
986 u32 menu(u16 *original_screen)
988 u32 clock_speed_number;
989 static u32 clock_speed_old = default_clock_speed;
991 u32 _current_option = 0;
992 gui_action_type gui_action;
993 menu_enum _current_menu = MAIN_MENU;
996 u32 return_value = 0;
998 u8 savestate_ext[16];
999 u8 current_savestate_filename[512];
1001 u8 cheat_format_str[10][41];
1003 menu_type *current_menu;
1004 menu_option_type *current_option;
1005 menu_option_type *display_option;
1006 u32 current_option_num;
1008 auto void choose_menu();
1009 auto void clear_help();
1011 u8 *gamepad_help[] =
1013 "Up button on GBA d-pad.",
1014 "Down button on GBA d-pad.",
1015 "Left button on GBA d-pad.",
1016 "Right button on GBA d-pad.",
1019 "Left shoulder button on GBA.",
1020 "Right shoulder button on GBA.",
1021 "Start button on GBA.",
1022 "Select button on GBA.",
1023 "Brings up the options menu.",
1024 "Toggles fastforward on/off.",
1025 "Loads the game state from the current slot.",
1026 "Saves the game state to the current slot.",
1027 "Rapidly press/release the A button on GBA.",
1028 "Rapidly press/release the B button on GBA.",
1029 "Rapidly press/release the L shoulder on GBA.",
1030 "Rapidly press/release the R shoulder on GBA.",
1031 "Increases the volume.",
1032 "Decreases the volume.",
1033 "Displays virtual/drawn frames per second.",
1052 u8 *file_ext[] = { ".gba", ".bin", ".zip", NULL };
1053 u8 load_filename[512];
1054 save_game_config_file();
1055 if(load_file(file_ext, load_filename) != -1)
1057 if(load_gamepak(load_filename) == -1)
1064 reg[CHANGED_PC_STATUS] = 1;
1068 choose_menu(current_menu);
1077 reg[CHANGED_PC_STATUS] = 1;
1083 void menu_change_state()
1085 get_savestate_filename(savestate_slot, current_savestate_filename);
1088 void menu_save_state()
1092 get_savestate_filename_noshot(savestate_slot,
1093 current_savestate_filename);
1094 save_state(current_savestate_filename, original_screen);
1096 menu_change_state();
1099 void menu_load_state()
1103 load_state(current_savestate_filename);
1109 void menu_load_state_file()
1111 u8 *file_ext[] = { ".svs", NULL };
1112 u8 load_filename[512];
1113 if(load_file(file_ext, load_filename) != -1)
1115 load_state(load_filename);
1121 choose_menu(current_menu);
1125 void menu_fix_gamepad_help()
1129 current_option->help_string =
1130 gamepad_help[gamepad_config_map[
1131 gamepad_config_line_to_button[current_option_num]]];
1135 void submenu_graphics_sound()
1140 void submenu_cheats_misc()
1145 void submenu_gamepad()
1150 void submenu_analog()
1155 void submenu_savestate()
1157 print_string("Savestate options:", COLOR_ACTIVE_ITEM, COLOR_BG, 10, 70);
1158 menu_change_state();
1163 strncpy(print_buffer, gamepak_filename, 80);
1164 print_string(print_buffer, COLOR_ROM_INFO, COLOR_BG, 10, 10);
1165 sprintf(print_buffer, "%s %s %s", gamepak_title,
1166 gamepak_code, gamepak_maker);
1167 print_string(print_buffer, COLOR_ROM_INFO, COLOR_BG, 10, 20);
1169 get_savestate_filename_noshot(savestate_slot,
1170 current_savestate_filename);
1173 u8 *yes_no_options[] = { "no", "yes" };
1174 u8 *enable_disable_options[] = { "disabled", "enabled" };
1176 u8 *scale_options[] =
1179 "unscaled 3:2", "scaled 3:2 (slower)"
1181 "unscaled 3:2", "scaled 3:2", "fullscreen"
1188 u8 *frameskip_options[] = { "automatic", "manual", "off" };
1189 u8 *frameskip_variation_options[] = { "uniform", "random" };
1192 u8 *audio_buffer_options[] =
1194 "16 bytes", "32 bytes", "64 bytes",
1195 "128 bytes", "256 bytes", "512 bytes", "1024 bytes", "2048 bytes",
1196 "4096 bytes", "8192 bytes", "16284 bytes"
1199 u8 *audio_buffer_options[] =
1201 "3072 bytes", "4096 bytes", "5120 bytes", "6144 bytes", "7168 bytes",
1202 "8192 bytes", "9216 bytes", "10240 bytes", "11264 bytes", "12288 bytes"
1207 u8 *update_backup_options[] = { "Exit only", "Automatic" };
1210 u8 *clock_speed_options[] =
1212 "300MHz", "333MHz", "366MHz", "400MHz", "433MHz",
1213 "466MHz", "500MHz", "533MHz", "566MHz", "600MHz",
1214 "633MHz", "666MHz", "700MHz", "733MHz", "766MHz",
1215 "800MHz", "833MHz", "866MHz", "900MHz"
1217 #elif defined(GP2X_BUILD)
1218 u8 *clock_speed_options[] =
1220 "150MHz", "160MHz", "170MHz", "180MHz", "190MHz",
1221 "200MHz", "210MHz", "220MHz", "230MHz", "240MHz",
1222 "250MHz", "260MHz", "270MHz", "280MHz", "290MHz"
1225 u8 *clock_speed_options[] =
1227 "33MHz", "66MHz", "100MHz", "133MHz", "166MHz", "200MHz", "233MHz",
1228 "266MHz", "300MHz", "333MHz"
1232 u8 *gamepad_config_buttons[] =
1258 // Marker for help information, don't go past this mark (except \n)------*
1259 menu_option_type graphics_sound_options[] =
1261 string_selection_option(NULL, "Display scaling", scale_options,
1262 (u32 *)(&screen_scale),
1269 "Determines how the GBA screen is resized in relation to the entire\n"
1270 "screen. Select unscaled 3:2 for GBA resolution, scaled 3:2 for GBA\n"
1271 "aspect ratio scaled to fill the height of the PSP screen, and\n"
1272 "fullscreen to fill the entire PSP screen."
1276 string_selection_option(NULL, "Screen filtering", yes_no_options,
1277 (u32 *)(&screen_filter), 2,
1278 "Determines whether or not bilinear filtering should be used when\n"
1279 "scaling the screen. Selecting this will produce a more even and\n"
1280 "smooth image, at the cost of being blurry and having less vibrant\n"
1283 string_selection_option(NULL, "Frameskip type", frameskip_options,
1284 (u32 *)(¤t_frameskip_type), 3,
1286 "Determines what kind of frameskipping to use.\n"
1287 "Frameskipping may improve emulation speed of many games.\n"
1289 "Off: Do not skip any frames.\n"
1290 "Auto: Skip up to N frames (see next opt) as needed.\n"
1291 "Manual: Always render only 1 out of N + 1 frames."
1293 numeric_selection_option(NULL, "Frameskip value", &frameskip_value, 100,
1295 "For auto frameskip, determines the maximum number of frames that\n"
1296 "are allowed to be skipped consecutively.\n"
1297 "For manual frameskip, determines the number of frames that will\n"
1298 "always be skipped."
1301 string_selection_option(NULL, "Framskip variation",
1302 frameskip_variation_options, &random_skip, 2,
1304 "If objects in the game flicker at a regular rate certain manual\n"
1305 "frameskip values may cause them to normally disappear. Change this\n"
1306 "value to 'random' to avoid this. Do not use otherwise, as it tends to\n"
1307 "make the image quality worse, especially in high motion games."
1310 string_selection_option(NULL, "Audio output", yes_no_options,
1311 &global_enable_audio, 2,
1312 "Select 'no' to turn off all audio output. This will\n"
1313 "not result in a significant change in performance.", 9),
1315 string_selection_option(NULL, "Audio buffer", audio_buffer_options,
1316 &audio_buffer_size_number, 11,
1318 string_selection_option(NULL, "Audio buffer", audio_buffer_options,
1319 &audio_buffer_size_number, 10,
1323 "Set the size (in bytes) of the audio buffer. Larger values may result\n"
1324 "in slightly better performance at the cost of latency; the lowest\n"
1325 "value will give the most responsive audio.\n"
1326 "This option requires gpSP to be restarted before it will take effect.",
1328 "Set the size (in bytes) of the audio buffer.\n"
1329 "This option requires gpSP restart to take effect.",
1332 submenu_option(NULL, "Back", "Return to the main menu.", 12)
1335 make_menu(graphics_sound, submenu_graphics_sound, NULL);
1337 menu_option_type cheats_misc_options[] =
1349 string_selection_option(NULL, "Clock speed",
1350 clock_speed_options, &clock_speed_number,
1351 sizeof(clock_speed_options) / sizeof(clock_speed_options[0]),
1352 "Change the clock speed of the device. Higher clock\n"
1353 "speed will yield better performance, but will drain\n"
1354 "battery life further.", 11),
1355 string_selection_option(NULL, "Update backup",
1356 update_backup_options, &update_backup_flag, 2,
1358 "Determines when in-game save files should be\n"
1359 "written back to SD card.",
1361 "Determines when in-game save files should be written back to\n"
1362 "memstick. If set to 'automatic' writebacks will occur shortly after\n"
1363 "the game's backup is altered. On 'exit only' it will only be written\n"
1364 "back when you exit from this menu (NOT from using the home button).\n"
1365 "Use the latter with extreme care.",
1368 submenu_option(NULL, "Back", "Return to the main menu.", 14)
1371 make_menu(cheats_misc, submenu_cheats_misc, NULL);
1373 menu_option_type savestate_options[] =
1375 numeric_selection_action_hide_option(menu_load_state, menu_change_state,
1376 "Load savestate from current slot", &savestate_slot, 10,
1377 "Select to load the game state from the current slot\n"
1379 "Press left + right to change the current slot.", 6),
1380 numeric_selection_action_hide_option(menu_save_state, menu_change_state,
1381 "Save savestate to current slot", &savestate_slot, 10,
1382 "Select to save the game state to the current slot\n"
1384 "Press left + right to change the current slot.", 7),
1385 numeric_selection_action_hide_option(menu_load_state_file,
1387 "Load savestate from file", &savestate_slot, 10,
1388 "Restore gameplay from a savestate file.\n"
1389 "Note: The same file used to save the state must be\n"
1391 numeric_selection_option(menu_change_state,
1392 "Current savestate slot", &savestate_slot, 10,
1393 "Change the current savestate slot.\n", 11),
1394 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1397 make_menu(savestate, submenu_savestate, NULL);
1401 menu_option_type gamepad_config_options[] =
1403 gamepad_config_option("D-pad up ", 0),
1404 gamepad_config_option("D-pad down ", 1),
1405 gamepad_config_option("D-pad left ", 2),
1406 gamepad_config_option("D-pad right ", 3),
1407 gamepad_config_option("Circle ", 4),
1408 gamepad_config_option("Cross ", 5),
1409 gamepad_config_option("Square ", 6),
1410 gamepad_config_option("Triangle ", 7),
1411 gamepad_config_option("Left Trigger ", 8),
1412 gamepad_config_option("Right Trigger", 9),
1413 gamepad_config_option("Start ", 10),
1414 gamepad_config_option("Select ", 11),
1415 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1419 menu_option_type analog_config_options[] =
1421 analog_config_option("Analog up ", 0),
1422 analog_config_option("Analog down ", 1),
1423 analog_config_option("Analog left ", 2),
1424 analog_config_option("Analog right", 3),
1425 string_selection_option(NULL, "Enable analog", yes_no_options,
1426 &global_enable_analog, 2,
1427 "Select 'no' to block analog input entirely.", 7),
1428 numeric_selection_option(NULL, "Analog sensitivity",
1429 &analog_sensitivity_level, 10,
1430 "Determine sensitivity/responsiveness of the analog input.\n"
1431 "Lower numbers are less sensitive.", 8),
1432 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1439 menu_option_type gamepad_config_options[] =
1441 gamepad_config_option("D-pad up ", 0),
1442 gamepad_config_option("D-pad down ", 1),
1443 gamepad_config_option("D-pad left ", 2),
1444 gamepad_config_option("D-pad right ", 3),
1445 gamepad_config_option("A ", 4),
1446 gamepad_config_option("B ", 5),
1447 gamepad_config_option("X ", 6),
1448 gamepad_config_option("Y ", 7),
1449 gamepad_config_option("Left Trigger ", 8),
1450 gamepad_config_option("Right Trigger", 9),
1452 gamepad_config_option("Menu ", 10),
1454 gamepad_config_option("Start ", 10),
1456 gamepad_config_option("Select ", 11),
1458 gamepad_config_option("Stick Push ", 12),
1460 submenu_option(NULL, "Back", "Return to the main menu.", 14)
1464 menu_option_type analog_config_options[] =
1466 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1473 menu_option_type gamepad_config_options[] =
1475 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1478 menu_option_type analog_config_options[] =
1480 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1485 make_menu(gamepad_config, submenu_gamepad, NULL);
1486 make_menu(analog_config, submenu_analog, NULL);
1488 menu_option_type main_options[] =
1490 submenu_option(&graphics_sound_menu, "Graphics and Sound options",
1491 "Select to set display parameters and frameskip\n"
1492 "behavior, audio on/off, buffer size, and filtering.", 0),
1493 numeric_selection_action_option(menu_load_state, NULL,
1494 "Load state from slot", &savestate_slot, 10,
1495 "Select to load the game state from the current slot\n"
1496 "for this game, if it exists.\n"
1497 "Press left + right to change the current slot.", 2),
1498 numeric_selection_action_option(menu_save_state, NULL,
1499 "Save state to slot", &savestate_slot, 10,
1500 "Select to save the game state to the current slot\n"
1501 "for this game. See the extended menu for more info.\n"
1502 "Press left + right to change the current slot.", 3),
1503 submenu_option(&savestate_menu, "Savestate options",
1504 "Select to enter a menu for loading, saving, and\n"
1505 "viewing the currently active savestate for this game\n"
1506 "(or to load a savestate file from another game)", 4),
1507 submenu_option(&gamepad_config_menu, "Configure gamepad input",
1508 "Select to change the in-game behavior of buttons\n"
1511 submenu_option(&analog_config_menu, "Configure analog input",
1512 "Select to change the in-game behavior of the PSP analog nub.", 7),
1514 submenu_option(&cheats_misc_menu, "Cheats and Miscellaneous options",
1515 "Select to manage cheats, set backup behavior,\n"
1516 "and set device clock speed.", 9),
1517 action_option(menu_load, NULL, "Load new game",
1518 "Select to load a new game\n"
1519 "(will exit a game if currently playing).", 11),
1520 action_option(menu_restart, NULL, "Restart game",
1521 "Select to reset the GBA with the current game\n"
1523 action_option(menu_exit, NULL, "Return to game",
1524 "Select to exit this menu and resume gameplay.", 13),
1525 action_option(menu_quit, NULL, "Exit gpSP",
1526 "Select to exit gpSP and return to the menu.", 15)
1529 make_menu(main, submenu_main, NULL);
1531 void choose_menu(menu_type *new_menu)
1533 if(new_menu == NULL)
1534 new_menu = &main_menu;
1536 clear_screen(COLOR_BG);
1539 blit_to_screen(original_screen, 240, 160, 230, 40);
1542 current_menu = new_menu;
1543 current_option = new_menu->options;
1544 current_option_num = 0;
1545 if(current_menu->init_function)
1546 current_menu->init_function();
1551 for(i = 0; i < 6; i++)
1553 print_string_pad(" ", COLOR_BG, COLOR_BG, 8, 210 + (i * 10), 70);
1557 get_clock_speed_number();
1558 if (clock_speed_number < 0 || clock_speed_number >=
1559 sizeof(clock_speed_options) / sizeof(clock_speed_options[0]))
1561 clock_speed = default_clock_speed;
1562 get_clock_speed_number();
1565 video_resolution_large();
1568 SDL_LockMutex(sound_mutex);
1573 SDL_UnlockMutex(sound_mutex);
1576 if(gamepak_filename[0] == 0)
1579 memset(original_screen, 0x00, 240 * 160 * 2);
1580 print_string_ext("No game loaded yet.", 0xFFFF, 0x0000,
1581 60, 75,original_screen, 240, 0);
1584 choose_menu(&main_menu);
1586 for(i = 0; i < 10; i++)
1590 sprintf(cheat_format_str[i], "cheat %d (none loaded)", i);
1594 sprintf(cheat_format_str[i], "cheat %d (%s): %%s", i,
1595 cheats[i].cheat_name);
1599 current_menu->init_function();
1603 display_option = current_menu->options;
1605 for(i = 0; i < current_menu->num_options; i++, display_option++)
1607 if(display_option->option_type & NUMBER_SELECTION_OPTION)
1609 sprintf(line_buffer, display_option->display_string,
1610 *(display_option->current_option));
1614 if(display_option->option_type & STRING_SELECTION_OPTION)
1616 sprintf(line_buffer, display_option->display_string,
1617 ((u32 *)display_option->options)[*(display_option->current_option)]);
1621 strcpy(line_buffer, display_option->display_string);
1624 if(display_option == current_option)
1626 print_string_pad(line_buffer, COLOR_ACTIVE_ITEM, COLOR_BG, 10,
1627 (display_option->line_number * 10) + 40, 36);
1631 print_string_pad(line_buffer, COLOR_INACTIVE_ITEM, COLOR_BG, 10,
1632 (display_option->line_number * 10) + 40, 36);
1636 print_string(current_option->help_string, COLOR_HELP_TEXT,
1641 gui_action = get_gui_input();
1646 current_option_num = (current_option_num + 1) %
1647 current_menu->num_options;
1649 current_option = current_menu->options + current_option_num;
1654 if(current_option_num)
1655 current_option_num--;
1657 current_option_num = current_menu->num_options - 1;
1659 current_option = current_menu->options + current_option_num;
1664 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1665 STRING_SELECTION_OPTION))
1667 *(current_option->current_option) =
1668 (*current_option->current_option + 1) %
1669 current_option->num_options;
1671 if(current_option->passive_function)
1672 current_option->passive_function();
1677 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1678 STRING_SELECTION_OPTION))
1680 u32 current_option_val = *(current_option->current_option);
1682 if(current_option_val)
1683 current_option_val--;
1685 current_option_val = current_option->num_options - 1;
1687 *(current_option->current_option) = current_option_val;
1689 if(current_option->passive_function)
1690 current_option->passive_function();
1695 if(current_menu == &main_menu)
1698 choose_menu(&main_menu);
1702 if(current_option->option_type & ACTION_OPTION)
1703 current_option->action_function();
1705 if(current_option->option_type & SUBMENU_OPTION)
1706 choose_menu(current_option->sub_menu);
1711 set_gba_resolution(screen_scale);
1712 video_resolution_small();
1715 if (clock_speed != clock_speed_old)
1717 printf("about to set CPU clock to %iMHz\n", clock_speed);
1719 scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2);
1720 #elif defined(GP2X_BUILD)
1721 set_FCLK(clock_speed);
1723 clock_speed_old = clock_speed;
1728 return return_value;