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)
81 int sort_function(const void *dest_str_ptr, const void *src_str_ptr)
83 char *dest_str = *((char **)dest_str_ptr);
84 char *src_str = *((char **)src_str_ptr);
89 if(dest_str[0] == '.')
92 return strcasecmp(dest_str, src_str);
95 s32 load_file(u8 **wildcards, u8 *result)
98 struct dirent *current_file;
99 struct stat file_info;
100 u8 current_dir_name[MAX_PATH];
101 u8 current_dir_short[81];
102 u32 current_dir_length;
103 u32 total_filenames_allocated;
104 u32 total_dirnames_allocated;
110 u32 file_name_length;
112 u32 chosen_file, chosen_dir;
113 u32 dialog_result = 1;
114 s32 return_value = 1;
115 u32 current_file_selection;
116 u32 current_file_scroll_value;
117 u32 current_dir_selection;
118 u32 current_dir_scroll_value;
119 u32 current_file_in_scroll;
120 u32 current_dir_in_scroll;
121 u32 current_file_number, current_dir_number;
122 u32 current_column = 0;
125 gui_action_type gui_action;
127 while(return_value == 1)
129 current_file_selection = 0;
130 current_file_scroll_value = 0;
131 current_dir_selection = 0;
132 current_dir_scroll_value = 0;
133 current_file_in_scroll = 0;
134 current_dir_in_scroll = 0;
136 total_filenames_allocated = 32;
137 total_dirnames_allocated = 32;
138 file_list = (u8 **)malloc(sizeof(u8 *) * 32);
139 dir_list = (u8 **)malloc(sizeof(u8 *) * 32);
140 memset(file_list, 0, sizeof(u8 *) * 32);
141 memset(dir_list, 0, sizeof(u8 *) * 32);
148 getcwd(current_dir_name, MAX_PATH);
150 current_dir = opendir(current_dir_name);
155 current_file = readdir(current_dir);
161 file_name = current_file->d_name;
162 file_name_length = strlen(file_name);
164 if((stat(file_name, &file_info) >= 0) &&
165 ((file_name[0] != '.') || (file_name[1] == '.')))
167 if(S_ISDIR(file_info.st_mode))
170 (u8 *)malloc(file_name_length + 1);
172 sprintf(dir_list[num_dirs], "%s", file_name);
178 // Must match one of the wildcards, also ignore the .
179 if(file_name_length >= 4)
181 if(file_name[file_name_length - 4] == '.')
182 ext_pos = file_name_length - 4;
185 if(file_name[file_name_length - 3] == '.')
186 ext_pos = file_name_length - 3;
191 for(i = 0; wildcards[i] != NULL; i++)
193 if(!strcasecmp((file_name + ext_pos),
196 file_list[num_files] =
197 (u8 *)malloc(file_name_length + 1);
199 sprintf(file_list[num_files], "%s", file_name);
209 if(num_files == total_filenames_allocated)
211 file_list = (u8 **)realloc(file_list, sizeof(u8 *) *
212 total_filenames_allocated * 2);
213 memset(file_list + total_filenames_allocated, 0,
214 sizeof(u8 *) * total_filenames_allocated);
215 total_filenames_allocated *= 2;
218 if(num_dirs == total_dirnames_allocated)
220 dir_list = (u8 **)realloc(dir_list, sizeof(u8 *) *
221 total_dirnames_allocated * 2);
222 memset(dir_list + total_dirnames_allocated, 0,
223 sizeof(u8 *) * total_dirnames_allocated);
224 total_dirnames_allocated *= 2;
227 } while(current_file);
229 qsort((void *)file_list, num_files, sizeof(u8 *), sort_function);
230 qsort((void *)dir_list, num_dirs, sizeof(u8 *), sort_function);
232 closedir(current_dir);
234 current_dir_length = strlen(current_dir_name);
236 if(current_dir_length > 80)
240 snprintf(current_dir_short, 80,
241 "...%s", current_dir_name + current_dir_length - 77);
243 memcpy(current_dir_short, "...", 3);
244 memcpy(current_dir_short + 3,
245 current_dir_name + current_dir_length - 77, 77);
246 current_dir_short[80] = 0;
252 snprintf(current_dir_short, 80, "%s", current_dir_name);
254 memcpy(current_dir_short, current_dir_name,
255 current_dir_length + 1);
264 clear_screen(COLOR_BG);
272 print_string(current_dir_short, COLOR_ACTIVE_ITEM, COLOR_BG, 0, 0);
274 print_string("Press X to return to the main menu.",
275 COLOR_HELP_TEXT, COLOR_BG, 20, 220);
277 print_string("Press X to return to the main menu.",
278 COLOR_HELP_TEXT, COLOR_BG, 20, 260);
281 for(i = 0, current_file_number = i + current_file_scroll_value;
282 i < FILE_LIST_ROWS; i++, current_file_number++)
284 if(current_file_number < num_files)
286 if((current_file_number == current_file_selection) &&
287 (current_column == 0))
289 print_string(file_list[current_file_number], COLOR_ACTIVE_ITEM,
290 COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10));
294 print_string(file_list[current_file_number], COLOR_INACTIVE_ITEM,
295 COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10));
300 for(i = 0, current_dir_number = i + current_dir_scroll_value;
301 i < FILE_LIST_ROWS; i++, current_dir_number++)
303 if(current_dir_number < num_dirs)
305 if((current_dir_number == current_dir_selection) &&
306 (current_column == 1))
308 print_string(dir_list[current_dir_number], COLOR_ACTIVE_ITEM,
309 COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10));
313 print_string(dir_list[current_dir_number], COLOR_INACTIVE_ITEM,
314 COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10));
319 gui_action = get_gui_input();
324 if(current_column == 0)
326 if(current_file_selection < (num_files - 1))
328 current_file_selection++;
329 if(current_file_in_scroll == (FILE_LIST_ROWS - 1))
331 clear_screen(COLOR_BG);
332 current_file_scroll_value++;
336 current_file_in_scroll++;
342 if(current_dir_selection < (num_dirs - 1))
344 current_dir_selection++;
345 if(current_dir_in_scroll == (FILE_LIST_ROWS - 1))
347 clear_screen(COLOR_BG);
348 current_dir_scroll_value++;
352 current_dir_in_scroll++;
360 if(current_column == 0)
362 if(current_file_selection)
364 current_file_selection--;
365 if(current_file_in_scroll == 0)
367 clear_screen(COLOR_BG);
368 current_file_scroll_value--;
372 current_file_in_scroll--;
378 if(current_dir_selection)
380 current_dir_selection--;
381 if(current_dir_in_scroll == 0)
383 clear_screen(COLOR_BG);
384 current_dir_scroll_value--;
388 current_dir_in_scroll--;
395 if(current_column == 0)
403 if(current_column == 1)
411 if(current_column == 1)
414 chdir(dir_list[current_dir_selection]);
422 strcpy(result, file_list[current_file_selection]);
429 if(!strcmp(current_dir_name, "ms0:/PSP"))
444 for(i = 0; i < num_files; i++)
450 for(i = 0; i < num_dirs; i++)
457 clear_screen(COLOR_BG);
464 NUMBER_SELECTION_OPTION = 0x01,
465 STRING_SELECTION_OPTION = 0x02,
466 SUBMENU_OPTION = 0x04,
468 } menu_option_type_enum;
472 void (* init_function)();
473 void (* passive_function)();
474 struct _menu_option_type *options;
478 struct _menu_option_type
480 void (* action_function)();
481 void (* passive_function)();
482 struct _menu_type *sub_menu;
483 char *display_string;
489 menu_option_type_enum option_type;
492 typedef struct _menu_option_type menu_option_type;
493 typedef struct _menu_type menu_type;
495 #define make_menu(name, init_function, passive_function) \
496 menu_type name##_menu = \
501 sizeof(name##_options) / sizeof(menu_option_type) \
504 #define gamepad_config_option(display_string, number) \
507 menu_fix_gamepad_help, \
509 display_string ": %s", \
510 gamepad_config_buttons, \
511 gamepad_config_map + gamepad_config_line_to_button[number], \
512 sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \
513 gamepad_help[gamepad_config_map[ \
514 gamepad_config_line_to_button[number]]], \
516 STRING_SELECTION_OPTION \
519 #define analog_config_option(display_string, number) \
522 menu_fix_gamepad_help, \
524 display_string ": %s", \
525 gamepad_config_buttons, \
526 gamepad_config_map + number + 12, \
527 sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \
528 gamepad_help[gamepad_config_map[number + 12]], \
530 STRING_SELECTION_OPTION \
533 #define cheat_option(number) \
538 cheat_format_str[number], \
539 enable_disable_options, \
540 &(cheats[number].cheat_active), \
542 "Activate/deactivate this cheat code.", \
544 STRING_SELECTION_OPTION \
547 #define action_option(action_function, passive_function, display_string, \
548 help_string, line_number) \
562 #define submenu_option(sub_menu, display_string, help_string, line_number) \
570 sizeof(sub_menu) / sizeof(menu_option_type), \
576 #define selection_option(passive_function, display_string, options, \
577 option_ptr, num_options, help_string, line_number, type) \
591 #define action_selection_option(action_function, passive_function, \
592 display_string, options, option_ptr, num_options, help_string, line_number, \
604 type | ACTION_OPTION \
608 #define string_selection_option(passive_function, display_string, options, \
609 option_ptr, num_options, help_string, line_number) \
610 selection_option(passive_function, display_string ": %s", options, \
611 option_ptr, num_options, help_string, line_number, STRING_SELECTION_OPTION)\
613 #define numeric_selection_option(passive_function, display_string, \
614 option_ptr, num_options, help_string, line_number) \
615 selection_option(passive_function, display_string ": %d", NULL, option_ptr, \
616 num_options, help_string, line_number, NUMBER_SELECTION_OPTION) \
618 #define string_selection_action_option(action_function, passive_function, \
619 display_string, options, option_ptr, num_options, help_string, line_number) \
620 action_selection_option(action_function, passive_function, \
621 display_string ": %s", options, option_ptr, num_options, help_string, \
622 line_number, STRING_SELECTION_OPTION) \
624 #define numeric_selection_action_option(action_function, passive_function, \
625 display_string, option_ptr, num_options, help_string, line_number) \
626 action_selection_option(action_function, passive_function, \
627 display_string ": %d", NULL, option_ptr, num_options, help_string, \
628 line_number, NUMBER_SELECTION_OPTION) \
630 #define numeric_selection_action_hide_option(action_function, \
631 passive_function, display_string, option_ptr, num_options, help_string, \
633 action_selection_option(action_function, passive_function, \
634 display_string, NULL, option_ptr, num_options, help_string, \
635 line_number, NUMBER_SELECTION_OPTION) \
638 #define GAMEPAD_MENU_WIDTH 15
642 u32 gamepad_config_line_to_button[] =
643 { 8, 6, 7, 9, 1, 2, 3, 0, 4, 5, 11, 10 };
649 u32 gamepad_config_line_to_button[] =
650 { 0, 2, 1, 3, 8, 9, 10, 11, 6, 7, 4, 5, 14 };
655 s32 load_game_config_file()
657 u8 game_config_filename[512];
660 change_ext(gamepak_filename, game_config_filename, ".cfg");
662 file_open(game_config_file, game_config_filename, read);
664 if(file_check_valid(game_config_file))
666 u32 file_size = file_length(game_config_filename, game_config_file);
668 // Sanity check: File size must be the right size
671 u32 file_options[file_size / 4];
673 file_read_array(game_config_file, file_options);
674 current_frameskip_type = file_options[0] % 3;
675 frameskip_value = file_options[1];
676 random_skip = file_options[2] % 2;
677 clock_speed = file_options[3];
680 if(clock_speed >= 300)
683 if(clock_speed > 333)
690 if(frameskip_value < 0)
693 if(frameskip_value > 99)
694 frameskip_value = 99;
696 for(i = 0; i < 10; i++)
698 cheats[i].cheat_active = file_options[3 + i] % 2;
699 cheats[i].cheat_name[0] = 0;
702 file_close(game_config_file);
710 current_frameskip_type = auto_frameskip;
719 for(i = 0; i < 10; i++)
721 cheats[i].cheat_active = 0;
722 cheats[i].cheat_name[0] = 0;
728 s32 load_config_file()
732 #if (defined(PSP_BUILD) || defined(ARM_ARCH)) && !defined(_WIN32_WCE)
733 sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
735 sprintf(config_path, "%s\\%s", main_path, GPSP_CONFIG_FILENAME);
738 file_open(config_file, config_path, read);
740 if(file_check_valid(config_file))
742 u32 file_size = file_length(config_path, config_file);
744 // Sanity check: File size must be the right size
747 u32 file_options[file_size / 4];
749 s32 menu_button = -1;
750 file_read_array(config_file, file_options);
752 screen_scale = file_options[0] % 3;
753 screen_filter = file_options[1] % 2;
754 global_enable_audio = file_options[2] % 2;
757 audio_buffer_size_number = file_options[3] % 10;
759 audio_buffer_size_number = file_options[3] % 11;
762 update_backup_flag = file_options[4] % 2;
763 global_enable_analog = file_options[5] % 2;
764 analog_sensitivity_level = file_options[6] % 8;
767 scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2);
770 // Sanity check: Make sure there's a MENU or FRAMESKIP
771 // key, if not assign to triangle
774 for(i = 0; i < 16; i++)
776 gamepad_config_map[i] = file_options[7 + i] %
777 (BUTTON_ID_NONE + 1);
779 if(gamepad_config_map[i] == BUTTON_ID_MENU)
785 if(menu_button == -1)
787 gamepad_config_map[0] = BUTTON_ID_MENU;
791 file_close(config_file);
800 s32 save_game_config_file()
802 u8 game_config_filename[512];
805 change_ext(gamepak_filename, game_config_filename, ".cfg");
807 file_open(game_config_file, game_config_filename, write);
809 if(file_check_valid(game_config_file))
811 u32 file_options[14];
813 file_options[0] = current_frameskip_type;
814 file_options[1] = frameskip_value;
815 file_options[2] = random_skip;
816 file_options[3] = clock_speed;
818 for(i = 0; i < 10; i++)
820 file_options[4 + i] = cheats[i].cheat_active;
823 file_write_array(game_config_file, file_options);
825 file_close(game_config_file);
833 s32 save_config_file()
837 #if (defined(PSP_BUILD) || defined(ARM_ARCH)) && !defined(_WIN32_WCE)
838 sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
840 sprintf(config_path, "%s\\%s", main_path, GPSP_CONFIG_FILENAME);
843 file_open(config_file, config_path, write);
845 save_game_config_file();
847 if(file_check_valid(config_file))
849 u32 file_options[23];
852 file_options[0] = screen_scale;
853 file_options[1] = screen_filter;
854 file_options[2] = global_enable_audio;
855 file_options[3] = audio_buffer_size_number;
856 file_options[4] = update_backup_flag;
857 file_options[5] = global_enable_analog;
858 file_options[6] = analog_sensitivity_level;
861 for(i = 0; i < 16; i++)
863 file_options[7 + i] = gamepad_config_map[i];
867 file_write_array(config_file, file_options);
869 file_close(config_file);
886 u32 savestate_slot = 0;
888 void get_savestate_snapshot(u8 *savestate_filename)
890 u16 snapshot_buffer[240 * 160];
891 u8 savestate_timestamp_string[80];
893 file_open(savestate_file, savestate_filename, read);
895 if(file_check_valid(savestate_file))
897 u8 weekday_strings[7][11] =
899 "Sunday", "Monday", "Tuesday", "Wednesday",
900 "Thursday", "Friday", "Saturday"
902 time_t savestate_time_flat;
903 struct tm *current_time;
904 file_read_array(savestate_file, snapshot_buffer);
905 file_read_variable(savestate_file, savestate_time_flat);
907 file_close(savestate_file);
909 current_time = localtime(&savestate_time_flat);
910 sprintf(savestate_timestamp_string,
911 "%s %02d/%02d/%04d %02d:%02d:%02d ",
912 weekday_strings[current_time->tm_wday], current_time->tm_mon + 1,
913 current_time->tm_mday, current_time->tm_year + 1900,
914 current_time->tm_hour, current_time->tm_min, current_time->tm_sec);
916 savestate_timestamp_string[40] = 0;
917 print_string(savestate_timestamp_string, COLOR_HELP_TEXT, COLOR_BG,
922 memset(snapshot_buffer, 0, 240 * 160 * 2);
923 print_string_ext("No savestate exists for this slot.",
924 0xFFFF, 0x0000, 15, 75, snapshot_buffer, 240, 0);
925 print_string("---------- --/--/---- --:--:-- ", COLOR_HELP_TEXT,
930 blit_to_screen(snapshot_buffer, 240, 160, 230, 40);
934 void get_savestate_filename(u32 slot, u8 *name_buffer)
936 u8 savestate_ext[16];
938 sprintf(savestate_ext, "%d.svs", slot);
939 change_ext(gamepak_filename, name_buffer, savestate_ext);
941 get_savestate_snapshot(name_buffer);
944 void get_savestate_filename_noshot(u32 slot, u8 *name_buffer)
946 u8 savestate_ext[16];
948 sprintf(savestate_ext, "%d.svs", slot);
949 change_ext(gamepak_filename, name_buffer, savestate_ext);
955 invalidate_all_cache();
959 u32 menu(u16 *original_screen)
961 u32 clock_speed_number;
963 static u32 clock_speed_old = 200;
966 u32 _current_option = 0;
967 gui_action_type gui_action;
968 menu_enum _current_menu = MAIN_MENU;
971 u32 return_value = 0;
973 u8 savestate_ext[16];
974 u8 current_savestate_filename[512];
976 u8 cheat_format_str[10][41];
978 menu_type *current_menu;
979 menu_option_type *current_option;
980 menu_option_type *display_option;
981 u32 current_option_num;
983 auto void choose_menu();
984 auto void clear_help();
988 "Up button on GBA d-pad.",
989 "Down button on GBA d-pad.",
990 "Left button on GBA d-pad.",
991 "Right button on GBA d-pad.",
994 "Left shoulder button on GBA.",
995 "Right shoulder button on GBA.",
996 "Start button on GBA.",
997 "Select button on GBA.",
998 "Brings up the options menu.",
999 "Toggles fastforward on/off.",
1000 "Loads the game state from the current slot.",
1001 "Saves the game state to the current slot.",
1002 "Rapidly press/release the A button on GBA.",
1003 "Rapidly press/release the B button on GBA.",
1004 "Rapidly press/release the L shoulder on GBA.",
1005 "Rapidly press/release the R shoulder on GBA.",
1006 "Increases the volume.",
1007 "Decreases the volume.",
1008 "Displays virtual/drawn frames per second.",
1021 clock_speed = (clock_speed_number + 1) * 33;
1022 #elif defined(GP2X_BUILD)
1023 clock_speed = 150 + clock_speed_number * 10;
1031 u8 *file_ext[] = { ".gba", ".bin", ".zip", NULL };
1032 u8 load_filename[512];
1033 save_game_config_file();
1034 if(load_file(file_ext, load_filename) != -1)
1036 if(load_gamepak(load_filename) == -1)
1043 reg[CHANGED_PC_STATUS] = 1;
1047 choose_menu(current_menu);
1056 reg[CHANGED_PC_STATUS] = 1;
1062 void menu_change_state()
1064 get_savestate_filename(savestate_slot, current_savestate_filename);
1067 void menu_save_state()
1071 get_savestate_filename_noshot(savestate_slot,
1072 current_savestate_filename);
1073 save_state(current_savestate_filename, original_screen);
1075 menu_change_state();
1078 void menu_load_state()
1082 load_state(current_savestate_filename);
1088 void menu_load_state_file()
1090 u8 *file_ext[] = { ".svs", NULL };
1091 u8 load_filename[512];
1092 if(load_file(file_ext, load_filename) != -1)
1094 load_state(load_filename);
1100 choose_menu(current_menu);
1104 void menu_fix_gamepad_help()
1108 current_option->help_string =
1109 gamepad_help[gamepad_config_map[
1110 gamepad_config_line_to_button[current_option_num]]];
1114 void submenu_graphics_sound()
1119 void submenu_cheats_misc()
1124 void submenu_gamepad()
1129 void submenu_analog()
1134 void submenu_savestate()
1136 print_string("Savestate options:", COLOR_ACTIVE_ITEM, COLOR_BG, 10, 70);
1137 menu_change_state();
1142 strncpy(print_buffer, gamepak_filename, 80);
1143 print_string(print_buffer, COLOR_ROM_INFO, COLOR_BG, 10, 10);
1144 sprintf(print_buffer, "%s %s %s", gamepak_title,
1145 gamepak_code, gamepak_maker);
1146 print_string(print_buffer, COLOR_ROM_INFO, COLOR_BG, 10, 20);
1148 get_savestate_filename_noshot(savestate_slot,
1149 current_savestate_filename);
1152 u8 *yes_no_options[] = { "no", "yes" };
1153 u8 *enable_disable_options[] = { "disabled", "enabled" };
1155 u8 *scale_options[] =
1157 "unscaled 3:2", "scaled 3:2", "fullscreen"
1163 u8 *frameskip_options[] = { "automatic", "manual", "off" };
1164 u8 *frameskip_variation_options[] = { "uniform", "random" };
1167 u8 *audio_buffer_options[] =
1169 "16 bytes", "32 bytes", "64 bytes",
1170 "128 bytes", "256 bytes", "512 bytes", "1024 bytes", "2048 bytes",
1171 "4096 bytes", "8192 bytes", "16284 bytes"
1174 u8 *audio_buffer_options[] =
1176 "3072 bytes", "4096 bytes", "5120 bytes", "6144 bytes", "7168 bytes",
1177 "8192 bytes", "9216 bytes", "10240 bytes", "11264 bytes", "12288 bytes"
1182 u8 *update_backup_options[] = { "Exit only", "Automatic" };
1185 u8 *clock_speed_options[] =
1187 "150MHz", "160MHz", "170MHz", "180MHz", "190MHz",
1188 "200MHz", "210MHz", "220MHz", "230MHz", "240MHz",
1189 "250MHz", "260MHz", "270MHz", "280MHz", "290MHz"
1192 u8 *clock_speed_options[] =
1194 "33MHz", "66MHz", "100MHz", "133MHz", "166MHz", "200MHz", "233MHz",
1195 "266MHz", "300MHz", "333MHz"
1199 u8 *gamepad_config_buttons[] =
1225 // Marker for help information, don't go past this mark (except \n)------*
1226 menu_option_type graphics_sound_options[] =
1228 string_selection_option(NULL, "Display scaling", scale_options,
1229 (u32 *)(&screen_scale), 3,
1231 "Determines how the GBA screen is resized in relation to the entire\n"
1232 "screen. Select unscaled 3:2 for GBA resolution, scaled 3:2 for GBA\n"
1233 "aspect ratio scaled to fill the height of the PSP screen, and\n"
1234 "fullscreen to fill the entire PSP screen."
1238 string_selection_option(NULL, "Screen filtering", yes_no_options,
1239 (u32 *)(&screen_filter), 2,
1240 "Determines whether or not bilinear filtering should be used when\n"
1241 "scaling the screen. Selecting this will produce a more even and\n"
1242 "smooth image, at the cost of being blurry and having less vibrant\n"
1245 string_selection_option(NULL, "Frameskip type", frameskip_options,
1246 (u32 *)(¤t_frameskip_type), 3,
1247 "Determines what kind of frameskipping to use.\n"
1249 "Frameskipping may improve emulation speed of many games.\n"
1250 "Off: Do not skip any frames.\n"
1251 "Auto: Skip up to N frames (see next option) as needed.\n"
1252 "Manual: Always render only 1 out of N + 1 frames."
1255 numeric_selection_option(NULL, "Frameskip value", &frameskip_value, 100,
1257 "For auto frameskip, determines the maximum number of frames that\n"
1258 "are allowed to be skipped consecutively.\n"
1259 "For manual frameskip, determines the number of frames that will\n"
1260 "always be skipped."
1263 string_selection_option(NULL, "Framskip variation",
1264 frameskip_variation_options, &random_skip, 2,
1266 "If objects in the game flicker at a regular rate certain manual\n"
1267 "frameskip values may cause them to normally disappear. Change this\n"
1268 "value to 'random' to avoid this. Do not use otherwise, as it tends to\n"
1269 "make the image quality worse, especially in high motion games."
1272 string_selection_option(NULL, "Audio output", yes_no_options,
1273 &global_enable_audio, 2,
1274 "Select 'no' to turn off all audio output. This will\n"
1275 "not result in a significant change in performance.", 9),
1277 string_selection_option(NULL, "Audio buffer", audio_buffer_options,
1278 &audio_buffer_size_number, 11,
1280 string_selection_option(NULL, "Audio buffer", audio_buffer_options,
1281 &audio_buffer_size_number, 10,
1285 "Set the size (in bytes) of the audio buffer. Larger values may result\n"
1286 "in slightly better performance at the cost of latency; the lowest\n"
1287 "value will give the most responsive audio.\n"
1288 "This option requires gpSP to be restarted before it will take effect.",
1290 "Set the size (in bytes) of the audio buffer.\n"
1291 "This option requires gpSP restart to take effect.",
1294 submenu_option(NULL, "Back", "Return to the main menu.", 12)
1297 make_menu(graphics_sound, submenu_graphics_sound, NULL);
1299 menu_option_type cheats_misc_options[] =
1311 string_selection_option(NULL, "Clock speed",
1312 clock_speed_options, &clock_speed_number,
1318 "Change the clock speed of the device. Higher clock\n"
1319 "speed will yield better performance, but will drain\n"
1320 "battery life further.", 11),
1321 string_selection_option(NULL, "Update backup",
1322 update_backup_options, &update_backup_flag, 2,
1324 "Determines when in-game save files should be\n"
1325 "written back to SD card.",
1327 "Determines when in-game save files should be written back to\n"
1328 "memstick. If set to 'automatic' writebacks will occur shortly after\n"
1329 "the game's backup is altered. On 'exit only' it will only be written\n"
1330 "back when you exit from this menu (NOT from using the home button).\n"
1331 "Use the latter with extreme care.",
1334 submenu_option(NULL, "Back", "Return to the main menu.", 14)
1337 make_menu(cheats_misc, submenu_cheats_misc, NULL);
1339 menu_option_type savestate_options[] =
1341 numeric_selection_action_hide_option(menu_load_state, menu_change_state,
1342 "Load savestate from current slot", &savestate_slot, 10,
1343 "Select to load the game state from the current slot\n"
1345 "Press left + right to change the current slot.", 6),
1346 numeric_selection_action_hide_option(menu_save_state, menu_change_state,
1347 "Save savestate to current slot", &savestate_slot, 10,
1348 "Select to save the game state to the current slot\n"
1350 "Press left + right to change the current slot.", 7),
1351 numeric_selection_action_hide_option(menu_load_state_file,
1353 "Load savestate from file", &savestate_slot, 10,
1354 "Restore gameplay from a savestate file.\n"
1355 "Note: The same file used to save the state must be\n"
1357 numeric_selection_option(menu_change_state,
1358 "Current savestate slot", &savestate_slot, 10,
1359 "Change the current savestate slot.\n", 11),
1360 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1363 make_menu(savestate, submenu_savestate, NULL);
1367 menu_option_type gamepad_config_options[] =
1369 gamepad_config_option("D-pad up ", 0),
1370 gamepad_config_option("D-pad down ", 1),
1371 gamepad_config_option("D-pad left ", 2),
1372 gamepad_config_option("D-pad right ", 3),
1373 gamepad_config_option("Circle ", 4),
1374 gamepad_config_option("Cross ", 5),
1375 gamepad_config_option("Square ", 6),
1376 gamepad_config_option("Triangle ", 7),
1377 gamepad_config_option("Left Trigger ", 8),
1378 gamepad_config_option("Right Trigger", 9),
1379 gamepad_config_option("Start ", 10),
1380 gamepad_config_option("Select ", 11),
1381 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1385 menu_option_type analog_config_options[] =
1387 analog_config_option("Analog up ", 0),
1388 analog_config_option("Analog down ", 1),
1389 analog_config_option("Analog left ", 2),
1390 analog_config_option("Analog right", 3),
1391 string_selection_option(NULL, "Enable analog", yes_no_options,
1392 &global_enable_analog, 2,
1393 "Select 'no' to block analog input entirely.", 7),
1394 numeric_selection_option(NULL, "Analog sensitivity",
1395 &analog_sensitivity_level, 10,
1396 "Determine sensitivity/responsiveness of the analog input.\n"
1397 "Lower numbers are less sensitive.", 8),
1398 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1405 menu_option_type gamepad_config_options[] =
1407 gamepad_config_option("D-pad up ", 0),
1408 gamepad_config_option("D-pad down ", 1),
1409 gamepad_config_option("D-pad left ", 2),
1410 gamepad_config_option("D-pad right ", 3),
1411 gamepad_config_option("A ", 4),
1412 gamepad_config_option("B ", 5),
1413 gamepad_config_option("X ", 6),
1414 gamepad_config_option("Y ", 7),
1415 gamepad_config_option("Left Trigger ", 8),
1416 gamepad_config_option("Right Trigger", 9),
1417 gamepad_config_option("Start ", 10),
1418 gamepad_config_option("Select ", 11),
1419 gamepad_config_option("Stick Push ", 12),
1420 submenu_option(NULL, "Back", "Return to the main menu.", 14)
1424 menu_option_type analog_config_options[] =
1426 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1433 menu_option_type gamepad_config_options[] =
1435 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1438 menu_option_type analog_config_options[] =
1440 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1445 make_menu(gamepad_config, submenu_gamepad, NULL);
1446 make_menu(analog_config, submenu_analog, NULL);
1448 menu_option_type main_options[] =
1450 submenu_option(&graphics_sound_menu, "Graphics and Sound options",
1451 "Select to set display parameters and frameskip\n"
1452 "behavior, audio on/off, buffer size, and filtering.", 0),
1453 numeric_selection_action_option(menu_load_state, NULL,
1454 "Load state from slot", &savestate_slot, 10,
1455 "Select to load the game state from the current slot\n"
1456 "for this game, if it exists.\n"
1457 "Press left + right to change the current slot.", 2),
1458 numeric_selection_action_option(menu_save_state, NULL,
1459 "Save state to slot", &savestate_slot, 10,
1460 "Select to save the game state to the current slot\n"
1461 "for this game. See the extended menu for more info.\n"
1462 "Press left + right to change the current slot.", 3),
1463 submenu_option(&savestate_menu, "Savestate options",
1464 "Select to enter a menu for loading, saving, and\n"
1465 "viewing the currently active savestate for this game\n"
1466 "(or to load a savestate file from another game)", 4),
1467 submenu_option(&gamepad_config_menu, "Configure gamepad input",
1468 "Select to change the in-game behavior of buttons\n"
1471 submenu_option(&analog_config_menu, "Configure analog input",
1472 "Select to change the in-game behavior of the PSP analog nub.", 7),
1474 submenu_option(&cheats_misc_menu, "Cheats and Miscellaneous options",
1475 "Select to manage cheats, set backup behavior,\n"
1476 "and set device clock speed.", 9),
1477 action_option(menu_load, NULL, "Load new game",
1478 "Select to load a new game\n"
1479 "(will exit a game if currently playing).", 11),
1480 action_option(menu_restart, NULL, "Restart game",
1481 "Select to reset the GBA with the current game\n"
1483 action_option(menu_exit, NULL, "Return to game",
1484 "Select to exit this menu and resume gameplay.", 13),
1485 action_option(menu_quit, NULL, "Exit gpSP",
1486 "Select to exit gpSP and return to the menu.", 15)
1489 make_menu(main, submenu_main, NULL);
1491 void choose_menu(menu_type *new_menu)
1493 if(new_menu == NULL)
1494 new_menu = &main_menu;
1496 clear_screen(COLOR_BG);
1499 blit_to_screen(original_screen, 240, 160, 230, 40);
1502 current_menu = new_menu;
1503 current_option = new_menu->options;
1504 current_option_num = 0;
1505 if(current_menu->init_function)
1506 current_menu->init_function();
1511 for(i = 0; i < 6; i++)
1513 print_string_pad(" ", COLOR_BG, COLOR_BG, 8, 210 + (i * 10), 70);
1518 clock_speed_number = (clock_speed / 33) - 1;
1519 #elif defined(GP2X_BUILD)
1520 clock_speed_number = (clock_speed - 150) / 10;
1523 video_resolution_large();
1526 SDL_LockMutex(sound_mutex);
1531 SDL_UnlockMutex(sound_mutex);
1534 if(gamepak_filename[0] == 0)
1537 memset(original_screen, 0x00, 240 * 160 * 2);
1538 print_string_ext("No game loaded yet.", 0xFFFF, 0x0000,
1539 60, 75,original_screen, 240, 0);
1542 choose_menu(&main_menu);
1544 for(i = 0; i < 10; i++)
1548 sprintf(cheat_format_str[i], "cheat %d (none loaded)", i);
1552 sprintf(cheat_format_str[i], "cheat %d (%s): %%s", i,
1553 cheats[i].cheat_name);
1557 current_menu->init_function();
1561 display_option = current_menu->options;
1563 for(i = 0; i < current_menu->num_options; i++, display_option++)
1565 if(display_option->option_type & NUMBER_SELECTION_OPTION)
1567 sprintf(line_buffer, display_option->display_string,
1568 *(display_option->current_option));
1572 if(display_option->option_type & STRING_SELECTION_OPTION)
1574 sprintf(line_buffer, display_option->display_string,
1575 ((u32 *)display_option->options)[*(display_option->current_option)]);
1579 strcpy(line_buffer, display_option->display_string);
1582 if(display_option == current_option)
1584 print_string_pad(line_buffer, COLOR_ACTIVE_ITEM, COLOR_BG, 10,
1585 (display_option->line_number * 10) + 40, 36);
1589 print_string_pad(line_buffer, COLOR_INACTIVE_ITEM, COLOR_BG, 10,
1590 (display_option->line_number * 10) + 40, 36);
1594 print_string(current_option->help_string, COLOR_HELP_TEXT,
1599 gui_action = get_gui_input();
1604 current_option_num = (current_option_num + 1) %
1605 current_menu->num_options;
1607 current_option = current_menu->options + current_option_num;
1612 if(current_option_num)
1613 current_option_num--;
1615 current_option_num = current_menu->num_options - 1;
1617 current_option = current_menu->options + current_option_num;
1622 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1623 STRING_SELECTION_OPTION))
1625 *(current_option->current_option) =
1626 (*current_option->current_option + 1) %
1627 current_option->num_options;
1629 if(current_option->passive_function)
1630 current_option->passive_function();
1635 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1636 STRING_SELECTION_OPTION))
1638 u32 current_option_val = *(current_option->current_option);
1640 if(current_option_val)
1641 current_option_val--;
1643 current_option_val = current_option->num_options - 1;
1645 *(current_option->current_option) = current_option_val;
1647 if(current_option->passive_function)
1648 current_option->passive_function();
1653 if(current_menu == &main_menu)
1656 choose_menu(&main_menu);
1660 if(current_option->option_type & ACTION_OPTION)
1661 current_option->action_function();
1663 if(current_option->option_type & SUBMENU_OPTION)
1664 choose_menu(current_option->sub_menu);
1669 set_gba_resolution(screen_scale);
1670 video_resolution_small();
1673 clock_speed = (clock_speed_number + 1) * 33;
1674 scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2);
1675 #elif defined(GP2X_BUILD)
1676 clock_speed = 150 + clock_speed_number * 10;
1677 if (clock_speed != clock_speed_old)
1679 printf("about to set CPU clock to %iMHz\n", clock_speed);
1680 set_FCLK(clock_speed);
1681 clock_speed_old = clock_speed;
1687 return return_value;