added upscaler
[gpsp.git] / gui.c
CommitLineData
2823a4c8 1/* gameplaySP
2 *
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.
8 *
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.
13 *
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
17 */
18
19#ifndef _WIN32_WCE
20
21#include <sys/stat.h>
22#include <unistd.h>
23#include <ctype.h>
24#include <dirent.h>
25
26#endif
27
90206450 28#ifndef GP2X_BUILD
29#include "gp2x/cpuctrl.h"
30#endif
31
2823a4c8 32#include "common.h"
33#include "font.h"
34
35#define MAX_PATH 1024
36
37// Blatantly stolen and trimmed from MZX (megazeux.sourceforge.net)
38
39#ifdef GP2X_BUILD
40
41#define FILE_LIST_ROWS ((int)((SDL_SCREEN_HEIGHT - 40) / FONT_HEIGHT))
42#define FILE_LIST_POSITION 5
43#define DIR_LIST_POSITION 260
44
45#else
46
47#define FILE_LIST_ROWS 25
48#define FILE_LIST_POSITION 5
49#define DIR_LIST_POSITION 360
50
51#endif
52
53#ifdef PSP_BUILD
54
55#define color16(red, green, blue) \
56 (blue << 11) | (green << 5) | red \
57
58#else
59
60#define color16(red, green, blue) \
61 (red << 11) | (green << 5) | blue \
62
63#endif
64
65#ifdef GP2X_BUILD
66
67#define COLOR_BG color16(0, 0, 0)
68
69#else
70
71#define COLOR_BG color16(2, 8, 10)
72
73#endif
74
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)
80
81int sort_function(const void *dest_str_ptr, const void *src_str_ptr)
82{
83 char *dest_str = *((char **)dest_str_ptr);
84 char *src_str = *((char **)src_str_ptr);
85
86 if(src_str[0] == '.')
87 return 1;
88
89 if(dest_str[0] == '.')
90 return -1;
91
92 return strcasecmp(dest_str, src_str);
93}
94
95s32 load_file(u8 **wildcards, u8 *result)
96{
97 DIR *current_dir;
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;
105 u8 **file_list;
106 u8 **dir_list;
107 u32 num_files;
108 u32 num_dirs;
109 u8 *file_name;
110 u32 file_name_length;
111 u32 ext_pos = -1;
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;
123 u32 repeat;
124 u32 i;
125 gui_action_type gui_action;
126
127 while(return_value == 1)
128 {
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;
135
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);
142
143 num_files = 0;
144 num_dirs = 0;
145 chosen_file = 0;
146 chosen_dir = 0;
147
148 getcwd(current_dir_name, MAX_PATH);
149
150 current_dir = opendir(current_dir_name);
151
152 do
153 {
154 if(current_dir)
155 current_file = readdir(current_dir);
156 else
157 current_file = NULL;
158
159 if(current_file)
160 {
161 file_name = current_file->d_name;
162 file_name_length = strlen(file_name);
163
164 if((stat(file_name, &file_info) >= 0) &&
165 ((file_name[0] != '.') || (file_name[1] == '.')))
166 {
167 if(S_ISDIR(file_info.st_mode))
168 {
169 dir_list[num_dirs] =
170 (u8 *)malloc(file_name_length + 1);
171
172 sprintf(dir_list[num_dirs], "%s", file_name);
173
174 num_dirs++;
175 }
176 else
177 {
178 // Must match one of the wildcards, also ignore the .
179 if(file_name_length >= 4)
180 {
181 if(file_name[file_name_length - 4] == '.')
182 ext_pos = file_name_length - 4;
183 else
184
185 if(file_name[file_name_length - 3] == '.')
186 ext_pos = file_name_length - 3;
187
188 else
189 ext_pos = 0;
190
191 for(i = 0; wildcards[i] != NULL; i++)
192 {
193 if(!strcasecmp((file_name + ext_pos),
194 wildcards[i]))
195 {
196 file_list[num_files] =
197 (u8 *)malloc(file_name_length + 1);
198
199 sprintf(file_list[num_files], "%s", file_name);
200
201 num_files++;
202 break;
203 }
204 }
205 }
206 }
207 }
208
209 if(num_files == total_filenames_allocated)
210 {
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;
216 }
217
218 if(num_dirs == total_dirnames_allocated)
219 {
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;
225 }
226 }
227 } while(current_file);
228
229 qsort((void *)file_list, num_files, sizeof(u8 *), sort_function);
230 qsort((void *)dir_list, num_dirs, sizeof(u8 *), sort_function);
231
232 closedir(current_dir);
233
234 current_dir_length = strlen(current_dir_name);
235
236 if(current_dir_length > 80)
237 {
238
239#ifdef GP2X_BUILD
240 snprintf(current_dir_short, 80,
241 "...%s", current_dir_name + current_dir_length - 77);
242#else
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;
247#endif
248 }
249 else
250 {
251#ifdef GP2X_BUILD
252 snprintf(current_dir_short, 80, "%s", current_dir_name);
253#else
254 memcpy(current_dir_short, current_dir_name,
255 current_dir_length + 1);
256#endif
257 }
258
259 repeat = 1;
260
261 if(num_files == 0)
262 current_column = 1;
263
264 clear_screen(COLOR_BG);
265 {
266 u8 print_buffer[81];
267
268 while(repeat)
269 {
270 flip_screen();
271
272 print_string(current_dir_short, COLOR_ACTIVE_ITEM, COLOR_BG, 0, 0);
273#ifdef GP2X_BUILD
274 print_string("Press X to return to the main menu.",
275 COLOR_HELP_TEXT, COLOR_BG, 20, 220);
276#else
277 print_string("Press X to return to the main menu.",
278 COLOR_HELP_TEXT, COLOR_BG, 20, 260);
279#endif
280
281 for(i = 0, current_file_number = i + current_file_scroll_value;
282 i < FILE_LIST_ROWS; i++, current_file_number++)
283 {
284 if(current_file_number < num_files)
285 {
286 if((current_file_number == current_file_selection) &&
287 (current_column == 0))
288 {
289 print_string(file_list[current_file_number], COLOR_ACTIVE_ITEM,
290 COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10));
291 }
292 else
293 {
294 print_string(file_list[current_file_number], COLOR_INACTIVE_ITEM,
295 COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10));
296 }
297 }
298 }
299
300 for(i = 0, current_dir_number = i + current_dir_scroll_value;
301 i < FILE_LIST_ROWS; i++, current_dir_number++)
302 {
303 if(current_dir_number < num_dirs)
304 {
305 if((current_dir_number == current_dir_selection) &&
306 (current_column == 1))
307 {
308 print_string(dir_list[current_dir_number], COLOR_ACTIVE_ITEM,
309 COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10));
310 }
311 else
312 {
313 print_string(dir_list[current_dir_number], COLOR_INACTIVE_ITEM,
314 COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10));
315 }
316 }
317 }
318
319 gui_action = get_gui_input();
320
321 switch(gui_action)
322 {
323 case CURSOR_DOWN:
324 if(current_column == 0)
325 {
326 if(current_file_selection < (num_files - 1))
327 {
328 current_file_selection++;
329 if(current_file_in_scroll == (FILE_LIST_ROWS - 1))
330 {
331 clear_screen(COLOR_BG);
332 current_file_scroll_value++;
333 }
334 else
335 {
336 current_file_in_scroll++;
337 }
338 }
339 }
340 else
341 {
342 if(current_dir_selection < (num_dirs - 1))
343 {
344 current_dir_selection++;
345 if(current_dir_in_scroll == (FILE_LIST_ROWS - 1))
346 {
347 clear_screen(COLOR_BG);
348 current_dir_scroll_value++;
349 }
350 else
351 {
352 current_dir_in_scroll++;
353 }
354 }
355 }
356
357 break;
358
359 case CURSOR_UP:
360 if(current_column == 0)
361 {
362 if(current_file_selection)
363 {
364 current_file_selection--;
365 if(current_file_in_scroll == 0)
366 {
367 clear_screen(COLOR_BG);
368 current_file_scroll_value--;
369 }
370 else
371 {
372 current_file_in_scroll--;
373 }
374 }
375 }
376 else
377 {
378 if(current_dir_selection)
379 {
380 current_dir_selection--;
381 if(current_dir_in_scroll == 0)
382 {
383 clear_screen(COLOR_BG);
384 current_dir_scroll_value--;
385 }
386 else
387 {
388 current_dir_in_scroll--;
389 }
390 }
391 }
392 break;
393
394 case CURSOR_RIGHT:
395 if(current_column == 0)
396 {
397 if(num_dirs != 0)
398 current_column = 1;
399 }
400 break;
401
402 case CURSOR_LEFT:
403 if(current_column == 1)
404 {
405 if(num_files != 0)
406 current_column = 0;
407 }
408 break;
409
410 case CURSOR_SELECT:
411 if(current_column == 1)
412 {
413 repeat = 0;
414 chdir(dir_list[current_dir_selection]);
415 }
416 else
417 {
418 if(num_files != 0)
419 {
420 repeat = 0;
421 return_value = 0;
422 strcpy(result, file_list[current_file_selection]);
423 }
424 }
425 break;
426
427 case CURSOR_BACK:
428#ifdef PSP_BUILD
429 if(!strcmp(current_dir_name, "ms0:/PSP"))
430 break;
431#endif
432 repeat = 0;
433 chdir("..");
434 break;
435
436 case CURSOR_EXIT:
437 return_value = -1;
438 repeat = 0;
439 break;
440 }
441 }
442 }
443
444 for(i = 0; i < num_files; i++)
445 {
446 free(file_list[i]);
447 }
448 free(file_list);
449
450 for(i = 0; i < num_dirs; i++)
451 {
452 free(dir_list[i]);
453 }
454 free(dir_list);
455 }
456
457 clear_screen(COLOR_BG);
458
459 return return_value;
460}
461
462typedef enum
463{
464 NUMBER_SELECTION_OPTION = 0x01,
465 STRING_SELECTION_OPTION = 0x02,
466 SUBMENU_OPTION = 0x04,
467 ACTION_OPTION = 0x08
468} menu_option_type_enum;
469
470struct _menu_type
471{
472 void (* init_function)();
473 void (* passive_function)();
474 struct _menu_option_type *options;
475 u32 num_options;
476};
477
478struct _menu_option_type
479{
480 void (* action_function)();
481 void (* passive_function)();
482 struct _menu_type *sub_menu;
483 char *display_string;
484 void *options;
485 u32 *current_option;
486 u32 num_options;
487 char *help_string;
488 u32 line_number;
489 menu_option_type_enum option_type;
490};
491
492typedef struct _menu_option_type menu_option_type;
493typedef struct _menu_type menu_type;
494
495#define make_menu(name, init_function, passive_function) \
496 menu_type name##_menu = \
497 { \
498 init_function, \
499 passive_function, \
500 name##_options, \
501 sizeof(name##_options) / sizeof(menu_option_type) \
502 } \
503
504#define gamepad_config_option(display_string, number) \
505{ \
506 NULL, \
507 menu_fix_gamepad_help, \
508 NULL, \
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]]], \
515 number, \
516 STRING_SELECTION_OPTION \
517} \
518
519#define analog_config_option(display_string, number) \
520{ \
521 NULL, \
522 menu_fix_gamepad_help, \
523 NULL, \
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]], \
529 number + 2, \
530 STRING_SELECTION_OPTION \
531} \
532
533#define cheat_option(number) \
534{ \
535 NULL, \
536 NULL, \
537 NULL, \
538 cheat_format_str[number], \
539 enable_disable_options, \
540 &(cheats[number].cheat_active), \
541 2, \
542 "Activate/deactivate this cheat code.", \
543 number, \
544 STRING_SELECTION_OPTION \
545} \
546
547#define action_option(action_function, passive_function, display_string, \
548 help_string, line_number) \
549{ \
550 action_function, \
551 passive_function, \
552 NULL, \
553 display_string, \
554 NULL, \
555 NULL, \
556 0, \
557 help_string, \
558 line_number, \
559 ACTION_OPTION \
560} \
561
562#define submenu_option(sub_menu, display_string, help_string, line_number) \
563{ \
564 NULL, \
565 NULL, \
566 sub_menu, \
567 display_string, \
568 NULL, \
569 NULL, \
570 sizeof(sub_menu) / sizeof(menu_option_type), \
571 help_string, \
572 line_number, \
573 SUBMENU_OPTION \
574} \
575
576#define selection_option(passive_function, display_string, options, \
577 option_ptr, num_options, help_string, line_number, type) \
578{ \
579 NULL, \
580 passive_function, \
581 NULL, \
582 display_string, \
583 options, \
584 option_ptr, \
585 num_options, \
586 help_string, \
587 line_number, \
588 type \
589} \
590
591#define action_selection_option(action_function, passive_function, \
592 display_string, options, option_ptr, num_options, help_string, line_number, \
593 type) \
594{ \
595 action_function, \
596 passive_function, \
597 NULL, \
598 display_string, \
599 options, \
600 option_ptr, \
601 num_options, \
602 help_string, \
603 line_number, \
604 type | ACTION_OPTION \
605} \
606
607
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)\
612
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) \
617
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) \
623
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) \
629
630#define numeric_selection_action_hide_option(action_function, \
631 passive_function, display_string, option_ptr, num_options, help_string, \
632 line_number) \
633 action_selection_option(action_function, passive_function, \
634 display_string, NULL, option_ptr, num_options, help_string, \
635 line_number, NUMBER_SELECTION_OPTION) \
636
637
638#define GAMEPAD_MENU_WIDTH 15
639
640#ifdef PSP_BUILD
641
642u32 gamepad_config_line_to_button[] =
643 { 8, 6, 7, 9, 1, 2, 3, 0, 4, 5, 11, 10 };
644
645#endif
646
647#ifdef GP2X_BUILD
648
649u32 gamepad_config_line_to_button[] =
90206450 650 { 0, 2, 1, 3, 8, 9, 10, 11, 6, 7, 4, 5, 14 };
2823a4c8 651
652#endif
653
654
655s32 load_game_config_file()
656{
657 u8 game_config_filename[512];
658 u32 file_loaded = 0;
659 u32 i;
660 change_ext(gamepak_filename, game_config_filename, ".cfg");
661
662 file_open(game_config_file, game_config_filename, read);
663
664 if(file_check_valid(game_config_file))
665 {
666 u32 file_size = file_length(game_config_filename, game_config_file);
667
668 // Sanity check: File size must be the right size
669 if(file_size == 56)
670 {
671 u32 file_options[file_size / 4];
672
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];
678
90206450 679#ifdef GP2X_BUILD
680 if(clock_speed >= 300)
681 clock_speed = 200;
682#else
2823a4c8 683 if(clock_speed > 333)
684 clock_speed = 333;
90206450 685#endif
2823a4c8 686
687 if(clock_speed < 33)
688 clock_speed = 33;
689
690 if(frameskip_value < 0)
691 frameskip_value = 0;
692
693 if(frameskip_value > 99)
694 frameskip_value = 99;
695
696 for(i = 0; i < 10; i++)
697 {
698 cheats[i].cheat_active = file_options[3 + i] % 2;
699 cheats[i].cheat_name[0] = 0;
700 }
701
702 file_close(game_config_file);
703 file_loaded = 1;
704 }
705 }
706
707 if(file_loaded)
708 return 0;
709
710 current_frameskip_type = auto_frameskip;
711 frameskip_value = 4;
712 random_skip = 0;
90206450 713#ifdef GP2X_BUILD
714 clock_speed = 200;
715#else
2823a4c8 716 clock_speed = 333;
90206450 717#endif
2823a4c8 718
719 for(i = 0; i < 10; i++)
720 {
721 cheats[i].cheat_active = 0;
722 cheats[i].cheat_name[0] = 0;
723 }
724
725 return -1;
726}
727
728s32 load_config_file()
729{
730 u8 config_path[512];
731
732 #if (defined(PSP_BUILD) || defined(ARM_ARCH)) && !defined(_WIN32_WCE)
733 sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
734 #else
735 sprintf(config_path, "%s\\%s", main_path, GPSP_CONFIG_FILENAME);
736 #endif
737
738 file_open(config_file, config_path, read);
739
740 if(file_check_valid(config_file))
741 {
742 u32 file_size = file_length(config_path, config_file);
743
744 // Sanity check: File size must be the right size
745 if(file_size == 92)
746 {
747 u32 file_options[file_size / 4];
748 u32 i;
749 s32 menu_button = -1;
750 file_read_array(config_file, file_options);
751
752 screen_scale = file_options[0] % 3;
753 screen_filter = file_options[1] % 2;
754 global_enable_audio = file_options[2] % 2;
755
756#ifdef PSP_BUILD
757 audio_buffer_size_number = file_options[3] % 10;
758#else
759 audio_buffer_size_number = file_options[3] % 11;
760#endif
761
762 update_backup_flag = file_options[4] % 2;
763 global_enable_analog = file_options[5] % 2;
764 analog_sensitivity_level = file_options[6] % 8;
765
766#ifdef PSP_BUILD
767 scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2);
768#endif
769
770 // Sanity check: Make sure there's a MENU or FRAMESKIP
771 // key, if not assign to triangle
772
773#ifndef PC_BUILD
774 for(i = 0; i < 16; i++)
775 {
776 gamepad_config_map[i] = file_options[7 + i] %
777 (BUTTON_ID_NONE + 1);
778
779 if(gamepad_config_map[i] == BUTTON_ID_MENU)
780 {
781 menu_button = i;
782 }
783 }
784
785 if(menu_button == -1)
786 {
787 gamepad_config_map[0] = BUTTON_ID_MENU;
788 }
789#endif
790
791 file_close(config_file);
792 }
793
794 return 0;
795 }
796
797 return -1;
798}
799
800s32 save_game_config_file()
801{
802 u8 game_config_filename[512];
803 u32 i;
804
805 change_ext(gamepak_filename, game_config_filename, ".cfg");
806
807 file_open(game_config_file, game_config_filename, write);
808
809 if(file_check_valid(game_config_file))
810 {
811 u32 file_options[14];
812
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;
817
818 for(i = 0; i < 10; i++)
819 {
820 file_options[4 + i] = cheats[i].cheat_active;
821 }
822
823 file_write_array(game_config_file, file_options);
824
825 file_close(game_config_file);
826
827 return 0;
828 }
829
830 return -1;
831}
832
833s32 save_config_file()
834{
835 u8 config_path[512];
836
837 #if (defined(PSP_BUILD) || defined(ARM_ARCH)) && !defined(_WIN32_WCE)
838 sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME);
839 #else
840 sprintf(config_path, "%s\\%s", main_path, GPSP_CONFIG_FILENAME);
841 #endif
842
843 file_open(config_file, config_path, write);
844
845 save_game_config_file();
846
847 if(file_check_valid(config_file))
848 {
849 u32 file_options[23];
850 u32 i;
851
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;
859
860#ifndef PC_BUILD
861 for(i = 0; i < 16; i++)
862 {
863 file_options[7 + i] = gamepad_config_map[i];
864 }
865#endif
866
867 file_write_array(config_file, file_options);
868
869 file_close(config_file);
870
871 return 0;
872 }
873
874 return -1;
875}
876
877typedef enum
878{
879 MAIN_MENU,
880 GAMEPAD_MENU,
881 SAVESTATE_MENU,
882 FRAMESKIP_MENU,
883 CHEAT_MENU
884} menu_enum;
885
886u32 savestate_slot = 0;
887
888void get_savestate_snapshot(u8 *savestate_filename)
889{
890 u16 snapshot_buffer[240 * 160];
891 u8 savestate_timestamp_string[80];
892
893 file_open(savestate_file, savestate_filename, read);
894
895 if(file_check_valid(savestate_file))
896 {
897 u8 weekday_strings[7][11] =
898 {
899 "Sunday", "Monday", "Tuesday", "Wednesday",
900 "Thursday", "Friday", "Saturday"
901 };
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);
906
907 file_close(savestate_file);
908
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);
915
916 savestate_timestamp_string[40] = 0;
917 print_string(savestate_timestamp_string, COLOR_HELP_TEXT, COLOR_BG,
918 10, 40);
919 }
920 else
921 {
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,
926 COLOR_BG, 10, 40);
927 }
928
929#ifndef GP2X_BUILD
930 blit_to_screen(snapshot_buffer, 240, 160, 230, 40);
931#endif
932}
933
934void get_savestate_filename(u32 slot, u8 *name_buffer)
935{
936 u8 savestate_ext[16];
937
938 sprintf(savestate_ext, "%d.svs", slot);
939 change_ext(gamepak_filename, name_buffer, savestate_ext);
940
941 get_savestate_snapshot(name_buffer);
942}
943
944void get_savestate_filename_noshot(u32 slot, u8 *name_buffer)
945{
946 u8 savestate_ext[16];
947
948 sprintf(savestate_ext, "%d.svs", slot);
949 change_ext(gamepak_filename, name_buffer, savestate_ext);
950}
951
952#ifdef PSP_BUILD
953 void _flush_cache()
954 {
955 invalidate_all_cache();
956 }
957#endif
958
959u32 menu(u16 *original_screen)
960{
90206450 961 u32 clock_speed_number;
962#ifdef GP2X_BUILD
963 static u32 clock_speed_old = 200;
964#endif
2823a4c8 965 u8 print_buffer[81];
966 u32 _current_option = 0;
967 gui_action_type gui_action;
968 menu_enum _current_menu = MAIN_MENU;
969 u32 i;
970 u32 repeat = 1;
971 u32 return_value = 0;
972 u32 first_load = 0;
973 u8 savestate_ext[16];
974 u8 current_savestate_filename[512];
975 u8 line_buffer[80];
976 u8 cheat_format_str[10][41];
977
978 menu_type *current_menu;
979 menu_option_type *current_option;
980 menu_option_type *display_option;
981 u32 current_option_num;
982
983 auto void choose_menu();
984 auto void clear_help();
985
986 u8 *gamepad_help[] =
987 {
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.",
992 "A button on GBA.",
993 "B button on GBA.",
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.",
1009 "Does nothing."
1010 };
1011
1012 void menu_exit()
1013 {
1014 if(!first_load)
1015 repeat = 0;
1016 }
1017
1018 void menu_quit()
1019 {
90206450 1020 #ifdef PSP_BUILD
2823a4c8 1021 clock_speed = (clock_speed_number + 1) * 33;
90206450 1022 #elif defined(GP2X_BUILD)
1023 clock_speed = 150 + clock_speed_number * 10;
1024 #endif
2823a4c8 1025 save_config_file();
1026 quit();
1027 }
1028
1029 void menu_load()
1030 {
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)
1035 {
1036 if(load_gamepak(load_filename) == -1)
1037 {
1038 quit();
1039 }
1040 reset_gba();
1041 return_value = 1;
1042 repeat = 0;
1043 reg[CHANGED_PC_STATUS] = 1;
1044 }
1045 else
1046 {
1047 choose_menu(current_menu);
1048 }
1049 }
1050
1051 void menu_restart()
1052 {
1053 if(!first_load)
1054 {
1055 reset_gba();
1056 reg[CHANGED_PC_STATUS] = 1;
1057 return_value = 1;
1058 repeat = 0;
1059 }
1060 }
1061
1062 void menu_change_state()
1063 {
1064 get_savestate_filename(savestate_slot, current_savestate_filename);
1065 }
1066
1067 void menu_save_state()
1068 {
1069 if(!first_load)
1070 {
1071 get_savestate_filename_noshot(savestate_slot,
1072 current_savestate_filename);
1073 save_state(current_savestate_filename, original_screen);
1074 }
1075 menu_change_state();
1076 }
1077
1078 void menu_load_state()
1079 {
1080 if(!first_load)
1081 {
1082 load_state(current_savestate_filename);
1083 return_value = 1;
1084 repeat = 0;
1085 }
1086 }
1087
1088 void menu_load_state_file()
1089 {
1090 u8 *file_ext[] = { ".svs", NULL };
1091 u8 load_filename[512];
1092 if(load_file(file_ext, load_filename) != -1)
1093 {
1094 load_state(load_filename);
1095 return_value = 1;
1096 repeat = 0;
1097 }
1098 else
1099 {
1100 choose_menu(current_menu);
1101 }
1102 }
1103
1104 void menu_fix_gamepad_help()
1105 {
1106#ifndef PC_BUILD
1107 clear_help();
1108 current_option->help_string =
1109 gamepad_help[gamepad_config_map[
1110 gamepad_config_line_to_button[current_option_num]]];
1111#endif
1112 }
1113
1114 void submenu_graphics_sound()
1115 {
1116
1117 }
1118
1119 void submenu_cheats_misc()
1120 {
1121
1122 }
1123
1124 void submenu_gamepad()
1125 {
1126
1127 }
1128
1129 void submenu_analog()
1130 {
1131
1132 }
1133
1134 void submenu_savestate()
1135 {
1136 print_string("Savestate options:", COLOR_ACTIVE_ITEM, COLOR_BG, 10, 70);
1137 menu_change_state();
1138 }
1139
1140 void submenu_main()
1141 {
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);
1147
1148 get_savestate_filename_noshot(savestate_slot,
1149 current_savestate_filename);
1150 }
1151
1152 u8 *yes_no_options[] = { "no", "yes" };
1153 u8 *enable_disable_options[] = { "disabled", "enabled" };
1154
1155 u8 *scale_options[] =
1156 {
90206450 1157 "unscaled 3:2", "scaled 3:2", "fullscreen"
1158#ifdef PSP_BUILD
1159 " 16:9"
1160#endif
2823a4c8 1161 };
1162
1163 u8 *frameskip_options[] = { "automatic", "manual", "off" };
1164 u8 *frameskip_variation_options[] = { "uniform", "random" };
1165
1166#ifndef PSP_BUILD
1167 u8 *audio_buffer_options[] =
1168 {
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"
1172 };
1173#else
1174 u8 *audio_buffer_options[] =
1175 {
1176 "3072 bytes", "4096 bytes", "5120 bytes", "6144 bytes", "7168 bytes",
1177 "8192 bytes", "9216 bytes", "10240 bytes", "11264 bytes", "12288 bytes"
1178 };
1179
1180#endif
1181
1182 u8 *update_backup_options[] = { "Exit only", "Automatic" };
1183
90206450 1184#ifdef GP2X_BUILD
1185 u8 *clock_speed_options[] =
1186 {
1187 "150MHz", "160MHz", "170MHz", "180MHz", "190MHz",
1188 "200MHz", "210MHz", "220MHz", "230MHz", "240MHz",
1189 "250MHz", "260MHz", "270MHz", "280MHz", "290MHz"
1190 };
1191#else
2823a4c8 1192 u8 *clock_speed_options[] =
1193 {
1194 "33MHz", "66MHz", "100MHz", "133MHz", "166MHz", "200MHz", "233MHz",
1195 "266MHz", "300MHz", "333MHz"
1196 };
90206450 1197#endif
2823a4c8 1198
1199 u8 *gamepad_config_buttons[] =
1200 {
1201 "UP",
1202 "DOWN",
1203 "LEFT",
1204 "RIGHT",
1205 "A",
1206 "B",
1207 "L",
1208 "R",
1209 "START",
1210 "SELECT",
1211 "MENU",
1212 "FASTFORWARD",
1213 "LOAD STATE",
1214 "SAVE STATE",
1215 "RAPIDFIRE A",
1216 "RAPIDFIRE B",
1217 "RAPIDFIRE L",
1218 "RAPIDFIRE R",
1219 "VOLUME UP",
1220 "VOLUME DOWN",
1221 "DISPLAY FPS",
1222 "NOTHING"
1223 };
1224
1225 // Marker for help information, don't go past this mark (except \n)------*
1226 menu_option_type graphics_sound_options[] =
1227 {
1228 string_selection_option(NULL, "Display scaling", scale_options,
4cdfc0bc 1229 (u32 *)(&screen_scale),
1230#ifdef WIZ_BUILD
1231 2,
1232#else
1233 3,
1234#endif
90206450 1235#ifndef GP2X_BUILD
2823a4c8 1236 "Determines how the GBA screen is resized in relation to the entire\n"
1237 "screen. Select unscaled 3:2 for GBA resolution, scaled 3:2 for GBA\n"
1238 "aspect ratio scaled to fill the height of the PSP screen, and\n"
90206450 1239 "fullscreen to fill the entire PSP screen."
1240#endif
1241 "", 2),
1242#ifndef GP2X_BUILD
2823a4c8 1243 string_selection_option(NULL, "Screen filtering", yes_no_options,
1244 (u32 *)(&screen_filter), 2,
1245 "Determines whether or not bilinear filtering should be used when\n"
1246 "scaling the screen. Selecting this will produce a more even and\n"
1247 "smooth image, at the cost of being blurry and having less vibrant\n"
1248 "colors.", 3),
90206450 1249#endif
2823a4c8 1250 string_selection_option(NULL, "Frameskip type", frameskip_options,
1251 (u32 *)(&current_frameskip_type), 3,
90206450 1252#ifndef GP2X_BUILD
4cdfc0bc 1253 "Determines what kind of frameskipping to use.\n"
2823a4c8 1254 "Frameskipping may improve emulation speed of many games.\n"
4cdfc0bc 1255#endif
2823a4c8 1256 "Off: Do not skip any frames.\n"
4cdfc0bc 1257 "Auto: Skip up to N frames (see next opt) as needed.\n"
90206450 1258 "Manual: Always render only 1 out of N + 1 frames."
4cdfc0bc 1259 , 5),
2823a4c8 1260 numeric_selection_option(NULL, "Frameskip value", &frameskip_value, 100,
90206450 1261#ifndef GP2X_BUILD
2823a4c8 1262 "For auto frameskip, determines the maximum number of frames that\n"
1263 "are allowed to be skipped consecutively.\n"
1264 "For manual frameskip, determines the number of frames that will\n"
90206450 1265 "always be skipped."
1266#endif
1267 "", 6),
2823a4c8 1268 string_selection_option(NULL, "Framskip variation",
1269 frameskip_variation_options, &random_skip, 2,
90206450 1270#ifndef GP2X_BUILD
2823a4c8 1271 "If objects in the game flicker at a regular rate certain manual\n"
1272 "frameskip values may cause them to normally disappear. Change this\n"
1273 "value to 'random' to avoid this. Do not use otherwise, as it tends to\n"
90206450 1274 "make the image quality worse, especially in high motion games."
1275#endif
1276 "", 7),
2823a4c8 1277 string_selection_option(NULL, "Audio output", yes_no_options,
1278 &global_enable_audio, 2,
90206450 1279 "Select 'no' to turn off all audio output. This will\n"
1280 "not result in a significant change in performance.", 9),
2823a4c8 1281#ifndef PSP_BUILD
1282 string_selection_option(NULL, "Audio buffer", audio_buffer_options,
1283 &audio_buffer_size_number, 11,
1284#else
1285 string_selection_option(NULL, "Audio buffer", audio_buffer_options,
1286 &audio_buffer_size_number, 10,
1287#endif
1288
4742480d 1289#ifdef PSP_BUILD
2823a4c8 1290 "Set the size (in bytes) of the audio buffer. Larger values may result\n"
1291 "in slightly better performance at the cost of latency; the lowest\n"
1292 "value will give the most responsive audio.\n"
1293 "This option requires gpSP to be restarted before it will take effect.",
4742480d 1294#else
1295 "Set the size (in bytes) of the audio buffer.\n"
1296 "This option requires gpSP restart to take effect.",
1297#endif
2823a4c8 1298 10),
1299 submenu_option(NULL, "Back", "Return to the main menu.", 12)
1300 };
1301
1302 make_menu(graphics_sound, submenu_graphics_sound, NULL);
1303
1304 menu_option_type cheats_misc_options[] =
1305 {
1306 cheat_option(0),
1307 cheat_option(1),
1308 cheat_option(2),
1309 cheat_option(3),
1310 cheat_option(4),
1311 cheat_option(5),
1312 cheat_option(6),
1313 cheat_option(7),
1314 cheat_option(8),
1315 cheat_option(9),
1316 string_selection_option(NULL, "Clock speed",
90206450 1317 clock_speed_options, &clock_speed_number,
1318#ifdef GP2X_BUILD
1319 15,
1320#else
1321 10,
1322#endif
1323 "Change the clock speed of the device. Higher clock\n"
1324 "speed will yield better performance, but will drain\n"
1325 "battery life further.", 11),
2823a4c8 1326 string_selection_option(NULL, "Update backup",
1327 update_backup_options, &update_backup_flag, 2,
90206450 1328#ifdef GP2X_BUILD
1329 "Determines when in-game save files should be\n"
1330 "written back to SD card.",
1331#else
2823a4c8 1332 "Determines when in-game save files should be written back to\n"
1333 "memstick. If set to 'automatic' writebacks will occur shortly after\n"
1334 "the game's backup is altered. On 'exit only' it will only be written\n"
1335 "back when you exit from this menu (NOT from using the home button).\n"
90206450 1336 "Use the latter with extreme care.",
1337#endif
1338 12),
2823a4c8 1339 submenu_option(NULL, "Back", "Return to the main menu.", 14)
1340 };
1341
1342 make_menu(cheats_misc, submenu_cheats_misc, NULL);
1343
1344 menu_option_type savestate_options[] =
1345 {
1346 numeric_selection_action_hide_option(menu_load_state, menu_change_state,
1347 "Load savestate from current slot", &savestate_slot, 10,
90206450 1348 "Select to load the game state from the current slot\n"
1349 "for this game.\n"
2823a4c8 1350 "Press left + right to change the current slot.", 6),
1351 numeric_selection_action_hide_option(menu_save_state, menu_change_state,
1352 "Save savestate to current slot", &savestate_slot, 10,
90206450 1353 "Select to save the game state to the current slot\n"
1354 "for this game.\n"
2823a4c8 1355 "Press left + right to change the current slot.", 7),
1356 numeric_selection_action_hide_option(menu_load_state_file,
1357 menu_change_state,
1358 "Load savestate from file", &savestate_slot, 10,
1359 "Restore gameplay from a savestate file.\n"
90206450 1360 "Note: The same file used to save the state must be\n"
1361 "present.\n", 9),
2823a4c8 1362 numeric_selection_option(menu_change_state,
1363 "Current savestate slot", &savestate_slot, 10,
1364 "Change the current savestate slot.\n", 11),
1365 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1366 };
1367
1368 make_menu(savestate, submenu_savestate, NULL);
1369
1370#ifdef PSP_BUILD
1371
1372 menu_option_type gamepad_config_options[] =
1373 {
1374 gamepad_config_option("D-pad up ", 0),
1375 gamepad_config_option("D-pad down ", 1),
1376 gamepad_config_option("D-pad left ", 2),
1377 gamepad_config_option("D-pad right ", 3),
1378 gamepad_config_option("Circle ", 4),
1379 gamepad_config_option("Cross ", 5),
1380 gamepad_config_option("Square ", 6),
1381 gamepad_config_option("Triangle ", 7),
1382 gamepad_config_option("Left Trigger ", 8),
1383 gamepad_config_option("Right Trigger", 9),
1384 gamepad_config_option("Start ", 10),
1385 gamepad_config_option("Select ", 11),
1386 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1387 };
1388
1389
1390 menu_option_type analog_config_options[] =
1391 {
1392 analog_config_option("Analog up ", 0),
1393 analog_config_option("Analog down ", 1),
1394 analog_config_option("Analog left ", 2),
1395 analog_config_option("Analog right", 3),
1396 string_selection_option(NULL, "Enable analog", yes_no_options,
1397 &global_enable_analog, 2,
1398 "Select 'no' to block analog input entirely.", 7),
1399 numeric_selection_option(NULL, "Analog sensitivity",
1400 &analog_sensitivity_level, 10,
1401 "Determine sensitivity/responsiveness of the analog input.\n"
1402 "Lower numbers are less sensitive.", 8),
1403 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1404 };
1405
1406#endif
1407
1408#ifdef GP2X_BUILD
1409
1410 menu_option_type gamepad_config_options[] =
1411 {
1412 gamepad_config_option("D-pad up ", 0),
1413 gamepad_config_option("D-pad down ", 1),
1414 gamepad_config_option("D-pad left ", 2),
1415 gamepad_config_option("D-pad right ", 3),
1416 gamepad_config_option("A ", 4),
1417 gamepad_config_option("B ", 5),
1418 gamepad_config_option("X ", 6),
1419 gamepad_config_option("Y ", 7),
1420 gamepad_config_option("Left Trigger ", 8),
1421 gamepad_config_option("Right Trigger", 9),
4cdfc0bc 1422#ifdef WIZ_BUILD
1423 gamepad_config_option("Menu ", 10),
1424#else
2823a4c8 1425 gamepad_config_option("Start ", 10),
4cdfc0bc 1426#endif
2823a4c8 1427 gamepad_config_option("Select ", 11),
4cdfc0bc 1428#ifndef WIZ_BUILD
90206450 1429 gamepad_config_option("Stick Push ", 12),
4cdfc0bc 1430#endif
90206450 1431 submenu_option(NULL, "Back", "Return to the main menu.", 14)
2823a4c8 1432 };
1433
1434
1435 menu_option_type analog_config_options[] =
1436 {
1437 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1438 };
1439
1440#endif
1441
1442#ifdef PC_BUILD
1443
1444 menu_option_type gamepad_config_options[] =
1445 {
1446 submenu_option(NULL, "Back", "Return to the main menu.", 13)
1447 };
1448
1449 menu_option_type analog_config_options[] =
1450 {
1451 submenu_option(NULL, "Back", "Return to the main menu.", 11)
1452 };
1453
1454#endif
1455
1456 make_menu(gamepad_config, submenu_gamepad, NULL);
1457 make_menu(analog_config, submenu_analog, NULL);
1458
1459 menu_option_type main_options[] =
1460 {
1461 submenu_option(&graphics_sound_menu, "Graphics and Sound options",
90206450 1462 "Select to set display parameters and frameskip\n"
1463 "behavior, audio on/off, buffer size, and filtering.", 0),
2823a4c8 1464 numeric_selection_action_option(menu_load_state, NULL,
1465 "Load state from slot", &savestate_slot, 10,
90206450 1466 "Select to load the game state from the current slot\n"
1467 "for this game, if it exists.\n"
2823a4c8 1468 "Press left + right to change the current slot.", 2),
1469 numeric_selection_action_option(menu_save_state, NULL,
1470 "Save state to slot", &savestate_slot, 10,
90206450 1471 "Select to save the game state to the current slot\n"
1472 "for this game. See the extended menu for more info.\n"
2823a4c8 1473 "Press left + right to change the current slot.", 3),
1474 submenu_option(&savestate_menu, "Savestate options",
90206450 1475 "Select to enter a menu for loading, saving, and\n"
1476 "viewing the currently active savestate for this game\n"
1477 "(or to load a savestate file from another game)", 4),
2823a4c8 1478 submenu_option(&gamepad_config_menu, "Configure gamepad input",
90206450 1479 "Select to change the in-game behavior of buttons\n"
1480 "and d-pad.", 6),
1481#ifndef GP2X_BUILD
2823a4c8 1482 submenu_option(&analog_config_menu, "Configure analog input",
1483 "Select to change the in-game behavior of the PSP analog nub.", 7),
90206450 1484#endif
2823a4c8 1485 submenu_option(&cheats_misc_menu, "Cheats and Miscellaneous options",
90206450 1486 "Select to manage cheats, set backup behavior,\n"
1487 "and set device clock speed.", 9),
2823a4c8 1488 action_option(menu_load, NULL, "Load new game",
90206450 1489 "Select to load a new game\n"
1490 "(will exit a game if currently playing).", 11),
2823a4c8 1491 action_option(menu_restart, NULL, "Restart game",
90206450 1492 "Select to reset the GBA with the current game\n"
1493 "loaded.", 12),
2823a4c8 1494 action_option(menu_exit, NULL, "Return to game",
1495 "Select to exit this menu and resume gameplay.", 13),
1496 action_option(menu_quit, NULL, "Exit gpSP",
90206450 1497 "Select to exit gpSP and return to the menu.", 15)
2823a4c8 1498 };
1499
1500 make_menu(main, submenu_main, NULL);
1501
1502 void choose_menu(menu_type *new_menu)
1503 {
1504 if(new_menu == NULL)
1505 new_menu = &main_menu;
1506
1507 clear_screen(COLOR_BG);
1508
1509#ifndef GP2X_BUILD
1510 blit_to_screen(original_screen, 240, 160, 230, 40);
1511#endif
1512
1513 current_menu = new_menu;
1514 current_option = new_menu->options;
1515 current_option_num = 0;
1516 if(current_menu->init_function)
1517 current_menu->init_function();
1518 }
1519
1520 void clear_help()
1521 {
1522 for(i = 0; i < 6; i++)
1523 {
90206450 1524 print_string_pad(" ", COLOR_BG, COLOR_BG, 8, 210 + (i * 10), 70);
2823a4c8 1525 }
1526 }
1527
90206450 1528#ifdef PSP_BUILD
1529 clock_speed_number = (clock_speed / 33) - 1;
1530#elif defined(GP2X_BUILD)
1531 clock_speed_number = (clock_speed - 150) / 10;
1532#endif
1533
2823a4c8 1534 video_resolution_large();
1535
1536#ifndef GP2X_BUILD
1537 SDL_LockMutex(sound_mutex);
1538#endif
1539 SDL_PauseAudio(1);
1540
1541#ifndef GP2X_BUILD
1542 SDL_UnlockMutex(sound_mutex);
1543#endif
1544
1545 if(gamepak_filename[0] == 0)
1546 {
1547 first_load = 1;
1548 memset(original_screen, 0x00, 240 * 160 * 2);
1549 print_string_ext("No game loaded yet.", 0xFFFF, 0x0000,
1550 60, 75,original_screen, 240, 0);
1551 }
1552
1553 choose_menu(&main_menu);
1554
1555 for(i = 0; i < 10; i++)
1556 {
1557 if(i >= num_cheats)
1558 {
1559 sprintf(cheat_format_str[i], "cheat %d (none loaded)", i);
1560 }
1561 else
1562 {
1563 sprintf(cheat_format_str[i], "cheat %d (%s): %%s", i,
1564 cheats[i].cheat_name);
1565 }
1566 }
1567
1568 current_menu->init_function();
1569
1570 while(repeat)
1571 {
1572 display_option = current_menu->options;
1573
1574 for(i = 0; i < current_menu->num_options; i++, display_option++)
1575 {
1576 if(display_option->option_type & NUMBER_SELECTION_OPTION)
1577 {
1578 sprintf(line_buffer, display_option->display_string,
1579 *(display_option->current_option));
1580 }
1581 else
1582
1583 if(display_option->option_type & STRING_SELECTION_OPTION)
1584 {
1585 sprintf(line_buffer, display_option->display_string,
1586 ((u32 *)display_option->options)[*(display_option->current_option)]);
1587 }
1588 else
1589 {
1590 strcpy(line_buffer, display_option->display_string);
1591 }
1592
1593 if(display_option == current_option)
1594 {
1595 print_string_pad(line_buffer, COLOR_ACTIVE_ITEM, COLOR_BG, 10,
1596 (display_option->line_number * 10) + 40, 36);
1597 }
1598 else
1599 {
1600 print_string_pad(line_buffer, COLOR_INACTIVE_ITEM, COLOR_BG, 10,
1601 (display_option->line_number * 10) + 40, 36);
1602 }
1603 }
1604
1605 print_string(current_option->help_string, COLOR_HELP_TEXT,
90206450 1606 COLOR_BG, 8, 210);
2823a4c8 1607
1608 flip_screen();
1609
1610 gui_action = get_gui_input();
1611
1612 switch(gui_action)
1613 {
1614 case CURSOR_DOWN:
1615 current_option_num = (current_option_num + 1) %
1616 current_menu->num_options;
1617
1618 current_option = current_menu->options + current_option_num;
1619 clear_help();
1620 break;
1621
1622 case CURSOR_UP:
1623 if(current_option_num)
1624 current_option_num--;
1625 else
1626 current_option_num = current_menu->num_options - 1;
1627
1628 current_option = current_menu->options + current_option_num;
1629 clear_help();
1630 break;
1631
1632 case CURSOR_RIGHT:
1633 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1634 STRING_SELECTION_OPTION))
1635 {
1636 *(current_option->current_option) =
1637 (*current_option->current_option + 1) %
1638 current_option->num_options;
1639
1640 if(current_option->passive_function)
1641 current_option->passive_function();
1642 }
1643 break;
1644
1645 case CURSOR_LEFT:
1646 if(current_option->option_type & (NUMBER_SELECTION_OPTION |
1647 STRING_SELECTION_OPTION))
1648 {
1649 u32 current_option_val = *(current_option->current_option);
1650
1651 if(current_option_val)
1652 current_option_val--;
1653 else
1654 current_option_val = current_option->num_options - 1;
1655
1656 *(current_option->current_option) = current_option_val;
1657
1658 if(current_option->passive_function)
1659 current_option->passive_function();
1660 }
1661 break;
1662
1663 case CURSOR_EXIT:
1664 if(current_menu == &main_menu)
1665 menu_exit();
1666
1667 choose_menu(&main_menu);
1668 break;
1669
1670 case CURSOR_SELECT:
1671 if(current_option->option_type & ACTION_OPTION)
1672 current_option->action_function();
1673
1674 if(current_option->option_type & SUBMENU_OPTION)
1675 choose_menu(current_option->sub_menu);
1676 break;
1677 }
1678 }
1679
1680 set_gba_resolution(screen_scale);
1681 video_resolution_small();
1682
2823a4c8 1683 #ifdef PSP_BUILD
90206450 1684 clock_speed = (clock_speed_number + 1) * 33;
2823a4c8 1685 scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2);
90206450 1686 #elif defined(GP2X_BUILD)
1687 clock_speed = 150 + clock_speed_number * 10;
1688 if (clock_speed != clock_speed_old)
1689 {
1690 printf("about to set CPU clock to %iMHz\n", clock_speed);
1691 set_FCLK(clock_speed);
1692 clock_speed_old = clock_speed;
1693 }
2823a4c8 1694 #endif
1695
1696 SDL_PauseAudio(0);
1697
1698 return return_value;
1699}