diff options
author | notaz | 2009-05-21 18:48:31 +0300 |
---|---|---|
committer | notaz | 2009-05-21 18:48:31 +0300 |
commit | 2823a4c8196a02da86ee180cf55586d4e8c91a2f (patch) | |
tree | 7e9b3f35b55af9917b3a05dd32de14be9a8c3f3c /gui.c | |
download | picogpsp-2823a4c8196a02da86ee180cf55586d4e8c91a2f.tar.gz picogpsp-2823a4c8196a02da86ee180cf55586d4e8c91a2f.tar.bz2 picogpsp-2823a4c8196a02da86ee180cf55586d4e8c91a2f.zip |
original source from gpsp09-2xb_src.tar.bz2
Diffstat (limited to 'gui.c')
-rw-r--r-- | gui.c | 1605 |
1 files changed, 1605 insertions, 0 deletions
@@ -0,0 +1,1605 @@ +/* gameplaySP + * + * Copyright (C) 2006 Exophase <exophase@gmail.com> + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licens e as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _WIN32_WCE + +#include <sys/stat.h> +#include <unistd.h> +#include <ctype.h> +#include <dirent.h> + +#endif + +#include "common.h" +#include "font.h" + +#define MAX_PATH 1024 + +// Blatantly stolen and trimmed from MZX (megazeux.sourceforge.net) + +#ifdef GP2X_BUILD + +#define FILE_LIST_ROWS ((int)((SDL_SCREEN_HEIGHT - 40) / FONT_HEIGHT)) +#define FILE_LIST_POSITION 5 +#define DIR_LIST_POSITION 260 + +#else + +#define FILE_LIST_ROWS 25 +#define FILE_LIST_POSITION 5 +#define DIR_LIST_POSITION 360 + +#endif + +#ifdef PSP_BUILD + +#define color16(red, green, blue) \ + (blue << 11) | (green << 5) | red \ + +#else + +#define color16(red, green, blue) \ + (red << 11) | (green << 5) | blue \ + +#endif + +#ifdef GP2X_BUILD + +#define COLOR_BG color16(0, 0, 0) + +#else + +#define COLOR_BG color16(2, 8, 10) + +#endif + +#define COLOR_ROM_INFO color16(22, 36, 26) +#define COLOR_ACTIVE_ITEM color16(31, 63, 31) +#define COLOR_INACTIVE_ITEM color16(13, 40, 18) +#define COLOR_FRAMESKIP_BAR color16(15, 31, 31) +#define COLOR_HELP_TEXT color16(16, 40, 24) + +int sort_function(const void *dest_str_ptr, const void *src_str_ptr) +{ + char *dest_str = *((char **)dest_str_ptr); + char *src_str = *((char **)src_str_ptr); + + if(src_str[0] == '.') + return 1; + + if(dest_str[0] == '.') + return -1; + + return strcasecmp(dest_str, src_str); +} + +s32 load_file(u8 **wildcards, u8 *result) +{ + DIR *current_dir; + struct dirent *current_file; + struct stat file_info; + u8 current_dir_name[MAX_PATH]; + u8 current_dir_short[81]; + u32 current_dir_length; + u32 total_filenames_allocated; + u32 total_dirnames_allocated; + u8 **file_list; + u8 **dir_list; + u32 num_files; + u32 num_dirs; + u8 *file_name; + u32 file_name_length; + u32 ext_pos = -1; + u32 chosen_file, chosen_dir; + u32 dialog_result = 1; + s32 return_value = 1; + u32 current_file_selection; + u32 current_file_scroll_value; + u32 current_dir_selection; + u32 current_dir_scroll_value; + u32 current_file_in_scroll; + u32 current_dir_in_scroll; + u32 current_file_number, current_dir_number; + u32 current_column = 0; + u32 repeat; + u32 i; + gui_action_type gui_action; + + while(return_value == 1) + { + current_file_selection = 0; + current_file_scroll_value = 0; + current_dir_selection = 0; + current_dir_scroll_value = 0; + current_file_in_scroll = 0; + current_dir_in_scroll = 0; + + total_filenames_allocated = 32; + total_dirnames_allocated = 32; + file_list = (u8 **)malloc(sizeof(u8 *) * 32); + dir_list = (u8 **)malloc(sizeof(u8 *) * 32); + memset(file_list, 0, sizeof(u8 *) * 32); + memset(dir_list, 0, sizeof(u8 *) * 32); + + num_files = 0; + num_dirs = 0; + chosen_file = 0; + chosen_dir = 0; + + getcwd(current_dir_name, MAX_PATH); + + current_dir = opendir(current_dir_name); + + do + { + if(current_dir) + current_file = readdir(current_dir); + else + current_file = NULL; + + if(current_file) + { + file_name = current_file->d_name; + file_name_length = strlen(file_name); + + if((stat(file_name, &file_info) >= 0) && + ((file_name[0] != '.') || (file_name[1] == '.'))) + { + if(S_ISDIR(file_info.st_mode)) + { + dir_list[num_dirs] = + (u8 *)malloc(file_name_length + 1); + + sprintf(dir_list[num_dirs], "%s", file_name); + + num_dirs++; + } + else + { + // Must match one of the wildcards, also ignore the . + if(file_name_length >= 4) + { + if(file_name[file_name_length - 4] == '.') + ext_pos = file_name_length - 4; + else + + if(file_name[file_name_length - 3] == '.') + ext_pos = file_name_length - 3; + + else + ext_pos = 0; + + for(i = 0; wildcards[i] != NULL; i++) + { + if(!strcasecmp((file_name + ext_pos), + wildcards[i])) + { + file_list[num_files] = + (u8 *)malloc(file_name_length + 1); + + sprintf(file_list[num_files], "%s", file_name); + + num_files++; + break; + } + } + } + } + } + + if(num_files == total_filenames_allocated) + { + file_list = (u8 **)realloc(file_list, sizeof(u8 *) * + total_filenames_allocated * 2); + memset(file_list + total_filenames_allocated, 0, + sizeof(u8 *) * total_filenames_allocated); + total_filenames_allocated *= 2; + } + + if(num_dirs == total_dirnames_allocated) + { + dir_list = (u8 **)realloc(dir_list, sizeof(u8 *) * + total_dirnames_allocated * 2); + memset(dir_list + total_dirnames_allocated, 0, + sizeof(u8 *) * total_dirnames_allocated); + total_dirnames_allocated *= 2; + } + } + } while(current_file); + + qsort((void *)file_list, num_files, sizeof(u8 *), sort_function); + qsort((void *)dir_list, num_dirs, sizeof(u8 *), sort_function); + + closedir(current_dir); + + current_dir_length = strlen(current_dir_name); + + if(current_dir_length > 80) + { + +#ifdef GP2X_BUILD + snprintf(current_dir_short, 80, + "...%s", current_dir_name + current_dir_length - 77); +#else + memcpy(current_dir_short, "...", 3); + memcpy(current_dir_short + 3, + current_dir_name + current_dir_length - 77, 77); + current_dir_short[80] = 0; +#endif + } + else + { +#ifdef GP2X_BUILD + snprintf(current_dir_short, 80, "%s", current_dir_name); +#else + memcpy(current_dir_short, current_dir_name, + current_dir_length + 1); +#endif + } + + repeat = 1; + + if(num_files == 0) + current_column = 1; + + clear_screen(COLOR_BG); + { + u8 print_buffer[81]; + + while(repeat) + { + flip_screen(); + + print_string(current_dir_short, COLOR_ACTIVE_ITEM, COLOR_BG, 0, 0); +#ifdef GP2X_BUILD + print_string("Press X to return to the main menu.", + COLOR_HELP_TEXT, COLOR_BG, 20, 220); +#else + print_string("Press X to return to the main menu.", + COLOR_HELP_TEXT, COLOR_BG, 20, 260); +#endif + + for(i = 0, current_file_number = i + current_file_scroll_value; + i < FILE_LIST_ROWS; i++, current_file_number++) + { + if(current_file_number < num_files) + { + if((current_file_number == current_file_selection) && + (current_column == 0)) + { + print_string(file_list[current_file_number], COLOR_ACTIVE_ITEM, + COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10)); + } + else + { + print_string(file_list[current_file_number], COLOR_INACTIVE_ITEM, + COLOR_BG, FILE_LIST_POSITION, ((i + 1) * 10)); + } + } + } + + for(i = 0, current_dir_number = i + current_dir_scroll_value; + i < FILE_LIST_ROWS; i++, current_dir_number++) + { + if(current_dir_number < num_dirs) + { + if((current_dir_number == current_dir_selection) && + (current_column == 1)) + { + print_string(dir_list[current_dir_number], COLOR_ACTIVE_ITEM, + COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10)); + } + else + { + print_string(dir_list[current_dir_number], COLOR_INACTIVE_ITEM, + COLOR_BG, DIR_LIST_POSITION, ((i + 1) * 10)); + } + } + } + + gui_action = get_gui_input(); + + switch(gui_action) + { + case CURSOR_DOWN: + if(current_column == 0) + { + if(current_file_selection < (num_files - 1)) + { + current_file_selection++; + if(current_file_in_scroll == (FILE_LIST_ROWS - 1)) + { + clear_screen(COLOR_BG); + current_file_scroll_value++; + } + else + { + current_file_in_scroll++; + } + } + } + else + { + if(current_dir_selection < (num_dirs - 1)) + { + current_dir_selection++; + if(current_dir_in_scroll == (FILE_LIST_ROWS - 1)) + { + clear_screen(COLOR_BG); + current_dir_scroll_value++; + } + else + { + current_dir_in_scroll++; + } + } + } + + break; + + case CURSOR_UP: + if(current_column == 0) + { + if(current_file_selection) + { + current_file_selection--; + if(current_file_in_scroll == 0) + { + clear_screen(COLOR_BG); + current_file_scroll_value--; + } + else + { + current_file_in_scroll--; + } + } + } + else + { + if(current_dir_selection) + { + current_dir_selection--; + if(current_dir_in_scroll == 0) + { + clear_screen(COLOR_BG); + current_dir_scroll_value--; + } + else + { + current_dir_in_scroll--; + } + } + } + break; + + case CURSOR_RIGHT: + if(current_column == 0) + { + if(num_dirs != 0) + current_column = 1; + } + break; + + case CURSOR_LEFT: + if(current_column == 1) + { + if(num_files != 0) + current_column = 0; + } + break; + + case CURSOR_SELECT: + if(current_column == 1) + { + repeat = 0; + chdir(dir_list[current_dir_selection]); + } + else + { + if(num_files != 0) + { + repeat = 0; + return_value = 0; + strcpy(result, file_list[current_file_selection]); + } + } + break; + + case CURSOR_BACK: +#ifdef PSP_BUILD + if(!strcmp(current_dir_name, "ms0:/PSP")) + break; +#endif + repeat = 0; + chdir(".."); + break; + + case CURSOR_EXIT: + return_value = -1; + repeat = 0; + break; + } + } + } + + for(i = 0; i < num_files; i++) + { + free(file_list[i]); + } + free(file_list); + + for(i = 0; i < num_dirs; i++) + { + free(dir_list[i]); + } + free(dir_list); + } + + clear_screen(COLOR_BG); + + return return_value; +} + +typedef enum +{ + NUMBER_SELECTION_OPTION = 0x01, + STRING_SELECTION_OPTION = 0x02, + SUBMENU_OPTION = 0x04, + ACTION_OPTION = 0x08 +} menu_option_type_enum; + +struct _menu_type +{ + void (* init_function)(); + void (* passive_function)(); + struct _menu_option_type *options; + u32 num_options; +}; + +struct _menu_option_type +{ + void (* action_function)(); + void (* passive_function)(); + struct _menu_type *sub_menu; + char *display_string; + void *options; + u32 *current_option; + u32 num_options; + char *help_string; + u32 line_number; + menu_option_type_enum option_type; +}; + +typedef struct _menu_option_type menu_option_type; +typedef struct _menu_type menu_type; + +#define make_menu(name, init_function, passive_function) \ + menu_type name##_menu = \ + { \ + init_function, \ + passive_function, \ + name##_options, \ + sizeof(name##_options) / sizeof(menu_option_type) \ + } \ + +#define gamepad_config_option(display_string, number) \ +{ \ + NULL, \ + menu_fix_gamepad_help, \ + NULL, \ + display_string ": %s", \ + gamepad_config_buttons, \ + gamepad_config_map + gamepad_config_line_to_button[number], \ + sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \ + gamepad_help[gamepad_config_map[ \ + gamepad_config_line_to_button[number]]], \ + number, \ + STRING_SELECTION_OPTION \ +} \ + +#define analog_config_option(display_string, number) \ +{ \ + NULL, \ + menu_fix_gamepad_help, \ + NULL, \ + display_string ": %s", \ + gamepad_config_buttons, \ + gamepad_config_map + number + 12, \ + sizeof(gamepad_config_buttons) / sizeof(gamepad_config_buttons[0]), \ + gamepad_help[gamepad_config_map[number + 12]], \ + number + 2, \ + STRING_SELECTION_OPTION \ +} \ + +#define cheat_option(number) \ +{ \ + NULL, \ + NULL, \ + NULL, \ + cheat_format_str[number], \ + enable_disable_options, \ + &(cheats[number].cheat_active), \ + 2, \ + "Activate/deactivate this cheat code.", \ + number, \ + STRING_SELECTION_OPTION \ +} \ + +#define action_option(action_function, passive_function, display_string, \ + help_string, line_number) \ +{ \ + action_function, \ + passive_function, \ + NULL, \ + display_string, \ + NULL, \ + NULL, \ + 0, \ + help_string, \ + line_number, \ + ACTION_OPTION \ +} \ + +#define submenu_option(sub_menu, display_string, help_string, line_number) \ +{ \ + NULL, \ + NULL, \ + sub_menu, \ + display_string, \ + NULL, \ + NULL, \ + sizeof(sub_menu) / sizeof(menu_option_type), \ + help_string, \ + line_number, \ + SUBMENU_OPTION \ +} \ + +#define selection_option(passive_function, display_string, options, \ + option_ptr, num_options, help_string, line_number, type) \ +{ \ + NULL, \ + passive_function, \ + NULL, \ + display_string, \ + options, \ + option_ptr, \ + num_options, \ + help_string, \ + line_number, \ + type \ +} \ + +#define action_selection_option(action_function, passive_function, \ + display_string, options, option_ptr, num_options, help_string, line_number, \ + type) \ +{ \ + action_function, \ + passive_function, \ + NULL, \ + display_string, \ + options, \ + option_ptr, \ + num_options, \ + help_string, \ + line_number, \ + type | ACTION_OPTION \ +} \ + + +#define string_selection_option(passive_function, display_string, options, \ + option_ptr, num_options, help_string, line_number) \ + selection_option(passive_function, display_string ": %s", options, \ + option_ptr, num_options, help_string, line_number, STRING_SELECTION_OPTION)\ + +#define numeric_selection_option(passive_function, display_string, \ + option_ptr, num_options, help_string, line_number) \ + selection_option(passive_function, display_string ": %d", NULL, option_ptr, \ + num_options, help_string, line_number, NUMBER_SELECTION_OPTION) \ + +#define string_selection_action_option(action_function, passive_function, \ + display_string, options, option_ptr, num_options, help_string, line_number) \ + action_selection_option(action_function, passive_function, \ + display_string ": %s", options, option_ptr, num_options, help_string, \ + line_number, STRING_SELECTION_OPTION) \ + +#define numeric_selection_action_option(action_function, passive_function, \ + display_string, option_ptr, num_options, help_string, line_number) \ + action_selection_option(action_function, passive_function, \ + display_string ": %d", NULL, option_ptr, num_options, help_string, \ + line_number, NUMBER_SELECTION_OPTION) \ + +#define numeric_selection_action_hide_option(action_function, \ + passive_function, display_string, option_ptr, num_options, help_string, \ + line_number) \ + action_selection_option(action_function, passive_function, \ + display_string, NULL, option_ptr, num_options, help_string, \ + line_number, NUMBER_SELECTION_OPTION) \ + + +#define GAMEPAD_MENU_WIDTH 15 + +#ifdef PSP_BUILD + +u32 gamepad_config_line_to_button[] = + { 8, 6, 7, 9, 1, 2, 3, 0, 4, 5, 11, 10 }; + +#endif + +#ifdef GP2X_BUILD + +u32 gamepad_config_line_to_button[] = + { 0, 2, 1, 3, 8, 9, 10, 11, 6, 7, 4, 5 }; + +#endif + + +s32 load_game_config_file() +{ + u8 game_config_filename[512]; + u32 file_loaded = 0; + u32 i; + change_ext(gamepak_filename, game_config_filename, ".cfg"); + + file_open(game_config_file, game_config_filename, read); + + if(file_check_valid(game_config_file)) + { + u32 file_size = file_length(game_config_filename, game_config_file); + + // Sanity check: File size must be the right size + if(file_size == 56) + { + u32 file_options[file_size / 4]; + + file_read_array(game_config_file, file_options); + current_frameskip_type = file_options[0] % 3; + frameskip_value = file_options[1]; + random_skip = file_options[2] % 2; + clock_speed = file_options[3]; + + if(clock_speed > 333) + clock_speed = 333; + + if(clock_speed < 33) + clock_speed = 33; + + if(frameskip_value < 0) + frameskip_value = 0; + + if(frameskip_value > 99) + frameskip_value = 99; + + for(i = 0; i < 10; i++) + { + cheats[i].cheat_active = file_options[3 + i] % 2; + cheats[i].cheat_name[0] = 0; + } + + file_close(game_config_file); + file_loaded = 1; + } + } + + if(file_loaded) + return 0; + + current_frameskip_type = auto_frameskip; + frameskip_value = 4; + random_skip = 0; + clock_speed = 333; + + for(i = 0; i < 10; i++) + { + cheats[i].cheat_active = 0; + cheats[i].cheat_name[0] = 0; + } + + return -1; +} + +s32 load_config_file() +{ + u8 config_path[512]; + + #if (defined(PSP_BUILD) || defined(ARM_ARCH)) && !defined(_WIN32_WCE) + sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME); + #else + sprintf(config_path, "%s\\%s", main_path, GPSP_CONFIG_FILENAME); + #endif + + file_open(config_file, config_path, read); + + if(file_check_valid(config_file)) + { + u32 file_size = file_length(config_path, config_file); + + // Sanity check: File size must be the right size + if(file_size == 92) + { + u32 file_options[file_size / 4]; + u32 i; + s32 menu_button = -1; + file_read_array(config_file, file_options); + + screen_scale = file_options[0] % 3; + screen_filter = file_options[1] % 2; + global_enable_audio = file_options[2] % 2; + +#ifdef PSP_BUILD + audio_buffer_size_number = file_options[3] % 10; +#else + audio_buffer_size_number = file_options[3] % 11; +#endif + + update_backup_flag = file_options[4] % 2; + global_enable_analog = file_options[5] % 2; + analog_sensitivity_level = file_options[6] % 8; + +#ifdef PSP_BUILD + scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2); +#endif + + // Sanity check: Make sure there's a MENU or FRAMESKIP + // key, if not assign to triangle + +#ifndef PC_BUILD + for(i = 0; i < 16; i++) + { + gamepad_config_map[i] = file_options[7 + i] % + (BUTTON_ID_NONE + 1); + + if(gamepad_config_map[i] == BUTTON_ID_MENU) + { + menu_button = i; + } + } + + if(menu_button == -1) + { + gamepad_config_map[0] = BUTTON_ID_MENU; + } +#endif + + file_close(config_file); + } + + return 0; + } + + return -1; +} + +s32 save_game_config_file() +{ + u8 game_config_filename[512]; + u32 i; + + change_ext(gamepak_filename, game_config_filename, ".cfg"); + + file_open(game_config_file, game_config_filename, write); + + if(file_check_valid(game_config_file)) + { + u32 file_options[14]; + + file_options[0] = current_frameskip_type; + file_options[1] = frameskip_value; + file_options[2] = random_skip; + file_options[3] = clock_speed; + + for(i = 0; i < 10; i++) + { + file_options[4 + i] = cheats[i].cheat_active; + } + + file_write_array(game_config_file, file_options); + + file_close(game_config_file); + + return 0; + } + + return -1; +} + +s32 save_config_file() +{ + u8 config_path[512]; + + #if (defined(PSP_BUILD) || defined(ARM_ARCH)) && !defined(_WIN32_WCE) + sprintf(config_path, "%s/%s", main_path, GPSP_CONFIG_FILENAME); + #else + sprintf(config_path, "%s\\%s", main_path, GPSP_CONFIG_FILENAME); + #endif + + file_open(config_file, config_path, write); + + save_game_config_file(); + + if(file_check_valid(config_file)) + { + u32 file_options[23]; + u32 i; + + file_options[0] = screen_scale; + file_options[1] = screen_filter; + file_options[2] = global_enable_audio; + file_options[3] = audio_buffer_size_number; + file_options[4] = update_backup_flag; + file_options[5] = global_enable_analog; + file_options[6] = analog_sensitivity_level; + +#ifndef PC_BUILD + for(i = 0; i < 16; i++) + { + file_options[7 + i] = gamepad_config_map[i]; + } +#endif + + file_write_array(config_file, file_options); + + file_close(config_file); + + return 0; + } + + return -1; +} + +typedef enum +{ + MAIN_MENU, + GAMEPAD_MENU, + SAVESTATE_MENU, + FRAMESKIP_MENU, + CHEAT_MENU +} menu_enum; + +u32 savestate_slot = 0; + +void get_savestate_snapshot(u8 *savestate_filename) +{ + u16 snapshot_buffer[240 * 160]; + u8 savestate_timestamp_string[80]; + + file_open(savestate_file, savestate_filename, read); + + if(file_check_valid(savestate_file)) + { + u8 weekday_strings[7][11] = + { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday" + }; + time_t savestate_time_flat; + struct tm *current_time; + file_read_array(savestate_file, snapshot_buffer); + file_read_variable(savestate_file, savestate_time_flat); + + file_close(savestate_file); + + current_time = localtime(&savestate_time_flat); + sprintf(savestate_timestamp_string, + "%s %02d/%02d/%04d %02d:%02d:%02d ", + weekday_strings[current_time->tm_wday], current_time->tm_mon + 1, + current_time->tm_mday, current_time->tm_year + 1900, + current_time->tm_hour, current_time->tm_min, current_time->tm_sec); + + savestate_timestamp_string[40] = 0; + print_string(savestate_timestamp_string, COLOR_HELP_TEXT, COLOR_BG, + 10, 40); + } + else + { + memset(snapshot_buffer, 0, 240 * 160 * 2); + print_string_ext("No savestate exists for this slot.", + 0xFFFF, 0x0000, 15, 75, snapshot_buffer, 240, 0); + print_string("---------- --/--/---- --:--:-- ", COLOR_HELP_TEXT, + COLOR_BG, 10, 40); + } + +#ifndef GP2X_BUILD + blit_to_screen(snapshot_buffer, 240, 160, 230, 40); +#endif +} + +void get_savestate_filename(u32 slot, u8 *name_buffer) +{ + u8 savestate_ext[16]; + + sprintf(savestate_ext, "%d.svs", slot); + change_ext(gamepak_filename, name_buffer, savestate_ext); + + get_savestate_snapshot(name_buffer); +} + +void get_savestate_filename_noshot(u32 slot, u8 *name_buffer) +{ + u8 savestate_ext[16]; + + sprintf(savestate_ext, "%d.svs", slot); + change_ext(gamepak_filename, name_buffer, savestate_ext); +} + +#ifdef PSP_BUILD + void _flush_cache() + { + invalidate_all_cache(); + } +#endif + +u32 menu(u16 *original_screen) +{ + u32 clock_speed_number = (clock_speed / 33) - 1; + u8 print_buffer[81]; + u32 _current_option = 0; + gui_action_type gui_action; + menu_enum _current_menu = MAIN_MENU; + u32 i; + u32 repeat = 1; + u32 return_value = 0; + u32 first_load = 0; + u8 savestate_ext[16]; + u8 current_savestate_filename[512]; + u8 line_buffer[80]; + u8 cheat_format_str[10][41]; + + menu_type *current_menu; + menu_option_type *current_option; + menu_option_type *display_option; + u32 current_option_num; + + auto void choose_menu(); + auto void clear_help(); + + u8 *gamepad_help[] = + { + "Up button on GBA d-pad.", + "Down button on GBA d-pad.", + "Left button on GBA d-pad.", + "Right button on GBA d-pad.", + "A button on GBA.", + "B button on GBA.", + "Left shoulder button on GBA.", + "Right shoulder button on GBA.", + "Start button on GBA.", + "Select button on GBA.", + "Brings up the options menu.", + "Toggles fastforward on/off.", + "Loads the game state from the current slot.", + "Saves the game state to the current slot.", + "Rapidly press/release the A button on GBA.", + "Rapidly press/release the B button on GBA.", + "Rapidly press/release the L shoulder on GBA.", + "Rapidly press/release the R shoulder on GBA.", + "Increases the volume.", + "Decreases the volume.", + "Displays virtual/drawn frames per second.", + "Does nothing." + }; + + void menu_exit() + { + if(!first_load) + repeat = 0; + } + + void menu_quit() + { + clock_speed = (clock_speed_number + 1) * 33; + save_config_file(); + quit(); + } + + void menu_load() + { + u8 *file_ext[] = { ".gba", ".bin", ".zip", NULL }; + u8 load_filename[512]; + save_game_config_file(); + if(load_file(file_ext, load_filename) != -1) + { + if(load_gamepak(load_filename) == -1) + { + quit(); + } + reset_gba(); + return_value = 1; + repeat = 0; + reg[CHANGED_PC_STATUS] = 1; + } + else + { + choose_menu(current_menu); + } + } + + void menu_restart() + { + if(!first_load) + { + reset_gba(); + reg[CHANGED_PC_STATUS] = 1; + return_value = 1; + repeat = 0; + } + } + + void menu_change_state() + { + get_savestate_filename(savestate_slot, current_savestate_filename); + } + + void menu_save_state() + { + if(!first_load) + { + get_savestate_filename_noshot(savestate_slot, + current_savestate_filename); + save_state(current_savestate_filename, original_screen); + } + menu_change_state(); + } + + void menu_load_state() + { + if(!first_load) + { + load_state(current_savestate_filename); + return_value = 1; + repeat = 0; + } + } + + void menu_load_state_file() + { + u8 *file_ext[] = { ".svs", NULL }; + u8 load_filename[512]; + if(load_file(file_ext, load_filename) != -1) + { + load_state(load_filename); + return_value = 1; + repeat = 0; + } + else + { + choose_menu(current_menu); + } + } + + void menu_fix_gamepad_help() + { +#ifndef PC_BUILD + clear_help(); + current_option->help_string = + gamepad_help[gamepad_config_map[ + gamepad_config_line_to_button[current_option_num]]]; +#endif + } + + void submenu_graphics_sound() + { + + } + + void submenu_cheats_misc() + { + + } + + void submenu_gamepad() + { + + } + + void submenu_analog() + { + + } + + void submenu_savestate() + { + print_string("Savestate options:", COLOR_ACTIVE_ITEM, COLOR_BG, 10, 70); + menu_change_state(); + } + + void submenu_main() + { + strncpy(print_buffer, gamepak_filename, 80); + print_string(print_buffer, COLOR_ROM_INFO, COLOR_BG, 10, 10); + sprintf(print_buffer, "%s %s %s", gamepak_title, + gamepak_code, gamepak_maker); + print_string(print_buffer, COLOR_ROM_INFO, COLOR_BG, 10, 20); + + get_savestate_filename_noshot(savestate_slot, + current_savestate_filename); + } + + u8 *yes_no_options[] = { "no", "yes" }; + u8 *enable_disable_options[] = { "disabled", "enabled" }; + + u8 *scale_options[] = + { + "unscaled 3:2", "scaled 3:2", "fullscreen 16:9" + }; + + u8 *frameskip_options[] = { "automatic", "manual", "off" }; + u8 *frameskip_variation_options[] = { "uniform", "random" }; + +#ifndef PSP_BUILD + u8 *audio_buffer_options[] = + { + "16 bytes", "32 bytes", "64 bytes", + "128 bytes", "256 bytes", "512 bytes", "1024 bytes", "2048 bytes", + "4096 bytes", "8192 bytes", "16284 bytes" + }; +#else + u8 *audio_buffer_options[] = + { + "3072 bytes", "4096 bytes", "5120 bytes", "6144 bytes", "7168 bytes", + "8192 bytes", "9216 bytes", "10240 bytes", "11264 bytes", "12288 bytes" + }; + +#endif + + u8 *update_backup_options[] = { "Exit only", "Automatic" }; + + u8 *clock_speed_options[] = + { + "33MHz", "66MHz", "100MHz", "133MHz", "166MHz", "200MHz", "233MHz", + "266MHz", "300MHz", "333MHz" + }; + + u8 *gamepad_config_buttons[] = + { + "UP", + "DOWN", + "LEFT", + "RIGHT", + "A", + "B", + "L", + "R", + "START", + "SELECT", + "MENU", + "FASTFORWARD", + "LOAD STATE", + "SAVE STATE", + "RAPIDFIRE A", + "RAPIDFIRE B", + "RAPIDFIRE L", + "RAPIDFIRE R", + "VOLUME UP", + "VOLUME DOWN", + "DISPLAY FPS", + "NOTHING" + }; + + // Marker for help information, don't go past this mark (except \n)------* + menu_option_type graphics_sound_options[] = + { + string_selection_option(NULL, "Display scaling", scale_options, + (u32 *)(&screen_scale), 3, + "Determines how the GBA screen is resized in relation to the entire\n" + "screen. Select unscaled 3:2 for GBA resolution, scaled 3:2 for GBA\n" + "aspect ratio scaled to fill the height of the PSP screen, and\n" + "fullscreen to fill the entire PSP screen.", 2), + string_selection_option(NULL, "Screen filtering", yes_no_options, + (u32 *)(&screen_filter), 2, + "Determines whether or not bilinear filtering should be used when\n" + "scaling the screen. Selecting this will produce a more even and\n" + "smooth image, at the cost of being blurry and having less vibrant\n" + "colors.", 3), + string_selection_option(NULL, "Frameskip type", frameskip_options, + (u32 *)(¤t_frameskip_type), 3, + "Determines what kind of frameskipping should be employed.\n" + "Frameskipping may improve emulation speed of many games.\n" + "Off: Do not skip any frames.\n" + "Auto: Skip up to N frames (see next option) as needed.\n" + "Manual: Always render only 1 out of N + 1 frames.", 5), + numeric_selection_option(NULL, "Frameskip value", &frameskip_value, 100, + "For auto frameskip, determines the maximum number of frames that\n" + "are allowed to be skipped consecutively.\n" + "For manual frameskip, determines the number of frames that will\n" + "always be skipped.", 6), + string_selection_option(NULL, "Framskip variation", + frameskip_variation_options, &random_skip, 2, + "If objects in the game flicker at a regular rate certain manual\n" + "frameskip values may cause them to normally disappear. Change this\n" + "value to 'random' to avoid this. Do not use otherwise, as it tends to\n" + "make the image quality worse, especially in high motion games.", 7), + string_selection_option(NULL, "Audio output", yes_no_options, + &global_enable_audio, 2, + "Select 'no' to turn off all audio output. This will not result in a\n" + "significant change in performance.", 9), +#ifndef PSP_BUILD + string_selection_option(NULL, "Audio buffer", audio_buffer_options, + &audio_buffer_size_number, 11, +#else + string_selection_option(NULL, "Audio buffer", audio_buffer_options, + &audio_buffer_size_number, 10, +#endif + + "Set the size (in bytes) of the audio buffer. Larger values may result\n" + "in slightly better performance at the cost of latency; the lowest\n" + "value will give the most responsive audio.\n" + "This option requires gpSP to be restarted before it will take effect.", + 10), + submenu_option(NULL, "Back", "Return to the main menu.", 12) + }; + + make_menu(graphics_sound, submenu_graphics_sound, NULL); + + menu_option_type cheats_misc_options[] = + { + cheat_option(0), + cheat_option(1), + cheat_option(2), + cheat_option(3), + cheat_option(4), + cheat_option(5), + cheat_option(6), + cheat_option(7), + cheat_option(8), + cheat_option(9), + string_selection_option(NULL, "Clock speed", + clock_speed_options, &clock_speed_number, 10, + "Change the clock speed of the device. Higher clock speed will yield\n" + "better performance, but will use drain battery life further.", 11), + string_selection_option(NULL, "Update backup", + update_backup_options, &update_backup_flag, 2, + "Determines when in-game save files should be written back to\n" + "memstick. If set to 'automatic' writebacks will occur shortly after\n" + "the game's backup is altered. On 'exit only' it will only be written\n" + "back when you exit from this menu (NOT from using the home button).\n" + "Use the latter with extreme care.", 12), + submenu_option(NULL, "Back", "Return to the main menu.", 14) + }; + + make_menu(cheats_misc, submenu_cheats_misc, NULL); + + menu_option_type savestate_options[] = + { + numeric_selection_action_hide_option(menu_load_state, menu_change_state, + "Load savestate from current slot", &savestate_slot, 10, + "Select to load the game state from the current slot for this game.\n" + "Press left + right to change the current slot.", 6), + numeric_selection_action_hide_option(menu_save_state, menu_change_state, + "Save savestate to current slot", &savestate_slot, 10, + "Select to save the game state to the current slot for this game.\n" + "Press left + right to change the current slot.", 7), + numeric_selection_action_hide_option(menu_load_state_file, + menu_change_state, + "Load savestate from file", &savestate_slot, 10, + "Restore gameplay from a savestate file.\n" + "Note: The same file used to save the state must be present.\n", 9), + numeric_selection_option(menu_change_state, + "Current savestate slot", &savestate_slot, 10, + "Change the current savestate slot.\n", 11), + submenu_option(NULL, "Back", "Return to the main menu.", 13) + }; + + make_menu(savestate, submenu_savestate, NULL); + +#ifdef PSP_BUILD + + menu_option_type gamepad_config_options[] = + { + gamepad_config_option("D-pad up ", 0), + gamepad_config_option("D-pad down ", 1), + gamepad_config_option("D-pad left ", 2), + gamepad_config_option("D-pad right ", 3), + gamepad_config_option("Circle ", 4), + gamepad_config_option("Cross ", 5), + gamepad_config_option("Square ", 6), + gamepad_config_option("Triangle ", 7), + gamepad_config_option("Left Trigger ", 8), + gamepad_config_option("Right Trigger", 9), + gamepad_config_option("Start ", 10), + gamepad_config_option("Select ", 11), + submenu_option(NULL, "Back", "Return to the main menu.", 13) + }; + + + menu_option_type analog_config_options[] = + { + analog_config_option("Analog up ", 0), + analog_config_option("Analog down ", 1), + analog_config_option("Analog left ", 2), + analog_config_option("Analog right", 3), + string_selection_option(NULL, "Enable analog", yes_no_options, + &global_enable_analog, 2, + "Select 'no' to block analog input entirely.", 7), + numeric_selection_option(NULL, "Analog sensitivity", + &analog_sensitivity_level, 10, + "Determine sensitivity/responsiveness of the analog input.\n" + "Lower numbers are less sensitive.", 8), + submenu_option(NULL, "Back", "Return to the main menu.", 11) + }; + +#endif + +#ifdef GP2X_BUILD + + menu_option_type gamepad_config_options[] = + { + gamepad_config_option("D-pad up ", 0), + gamepad_config_option("D-pad down ", 1), + gamepad_config_option("D-pad left ", 2), + gamepad_config_option("D-pad right ", 3), + gamepad_config_option("A ", 4), + gamepad_config_option("B ", 5), + gamepad_config_option("X ", 6), + gamepad_config_option("Y ", 7), + gamepad_config_option("Left Trigger ", 8), + gamepad_config_option("Right Trigger", 9), + gamepad_config_option("Start ", 10), + gamepad_config_option("Select ", 11), + submenu_option(NULL, "Back", "Return to the main menu.", 13) + }; + + + menu_option_type analog_config_options[] = + { + submenu_option(NULL, "Back", "Return to the main menu.", 11) + }; + +#endif + +#ifdef PC_BUILD + + menu_option_type gamepad_config_options[] = + { + submenu_option(NULL, "Back", "Return to the main menu.", 13) + }; + + menu_option_type analog_config_options[] = + { + submenu_option(NULL, "Back", "Return to the main menu.", 11) + }; + +#endif + + make_menu(gamepad_config, submenu_gamepad, NULL); + make_menu(analog_config, submenu_analog, NULL); + + menu_option_type main_options[] = + { + submenu_option(&graphics_sound_menu, "Graphics and Sound options", + "Select to set display parameters and frameskip behavior,\n" + "audio on/off, audio buffer size, and audio filtering.", 0), + numeric_selection_action_option(menu_load_state, NULL, + "Load state from slot", &savestate_slot, 10, + "Select to load the game state from the current slot for this game,\n" + "if it exists (see the extended menu for more information)\n" + "Press left + right to change the current slot.", 2), + numeric_selection_action_option(menu_save_state, NULL, + "Save state to slot", &savestate_slot, 10, + "Select to save the game state to the current slot for this game.\n" + "See the extended menu for more information.\n" + "Press left + right to change the current slot.", 3), + submenu_option(&savestate_menu, "Savestate options", + "Select to enter a menu for loading, saving, and viewing the\n" + "currently active savestate for this game (or to load a savestate\n" + "file from another game)", 4), + submenu_option(&gamepad_config_menu, "Configure gamepad input", + "Select to change the in-game behavior of the PSP buttons and d-pad.", + 6), + submenu_option(&analog_config_menu, "Configure analog input", + "Select to change the in-game behavior of the PSP analog nub.", 7), + submenu_option(&cheats_misc_menu, "Cheats and Miscellaneous options", + "Select to manage cheats, set backup behavior, and set device clock\n" + "speed.", 9), + action_option(menu_load, NULL, "Load new game", + "Select to load a new game (will exit a game if currently playing).", + 11), + action_option(menu_restart, NULL, "Restart game", + "Select to reset the GBA with the current game loaded.", 12), + action_option(menu_exit, NULL, "Return to game", + "Select to exit this menu and resume gameplay.", 13), + action_option(menu_quit, NULL, "Exit gpSP", + "Select to exit gpSP and return to the PSP XMB/loader.", 15) + }; + + make_menu(main, submenu_main, NULL); + + void choose_menu(menu_type *new_menu) + { + if(new_menu == NULL) + new_menu = &main_menu; + + clear_screen(COLOR_BG); + +#ifndef GP2X_BUILD + blit_to_screen(original_screen, 240, 160, 230, 40); +#endif + + current_menu = new_menu; + current_option = new_menu->options; + current_option_num = 0; + if(current_menu->init_function) + current_menu->init_function(); + } + + void clear_help() + { + for(i = 0; i < 6; i++) + { + print_string_pad(" ", COLOR_BG, COLOR_BG, 30, 210 + (i * 10), 70); + } + } + + video_resolution_large(); + +#ifndef GP2X_BUILD + SDL_LockMutex(sound_mutex); +#endif + SDL_PauseAudio(1); + +#ifndef GP2X_BUILD + SDL_UnlockMutex(sound_mutex); +#endif + + if(gamepak_filename[0] == 0) + { + first_load = 1; + memset(original_screen, 0x00, 240 * 160 * 2); + print_string_ext("No game loaded yet.", 0xFFFF, 0x0000, + 60, 75,original_screen, 240, 0); + } + + choose_menu(&main_menu); + + for(i = 0; i < 10; i++) + { + if(i >= num_cheats) + { + sprintf(cheat_format_str[i], "cheat %d (none loaded)", i); + } + else + { + sprintf(cheat_format_str[i], "cheat %d (%s): %%s", i, + cheats[i].cheat_name); + } + } + + current_menu->init_function(); + + while(repeat) + { + display_option = current_menu->options; + + for(i = 0; i < current_menu->num_options; i++, display_option++) + { + if(display_option->option_type & NUMBER_SELECTION_OPTION) + { + sprintf(line_buffer, display_option->display_string, + *(display_option->current_option)); + } + else + + if(display_option->option_type & STRING_SELECTION_OPTION) + { + sprintf(line_buffer, display_option->display_string, + ((u32 *)display_option->options)[*(display_option->current_option)]); + } + else + { + strcpy(line_buffer, display_option->display_string); + } + + if(display_option == current_option) + { + print_string_pad(line_buffer, COLOR_ACTIVE_ITEM, COLOR_BG, 10, + (display_option->line_number * 10) + 40, 36); + } + else + { + print_string_pad(line_buffer, COLOR_INACTIVE_ITEM, COLOR_BG, 10, + (display_option->line_number * 10) + 40, 36); + } + } + + print_string(current_option->help_string, COLOR_HELP_TEXT, + COLOR_BG, 30, 210); + + flip_screen(); + + gui_action = get_gui_input(); + + switch(gui_action) + { + case CURSOR_DOWN: + current_option_num = (current_option_num + 1) % + current_menu->num_options; + + current_option = current_menu->options + current_option_num; + clear_help(); + break; + + case CURSOR_UP: + if(current_option_num) + current_option_num--; + else + current_option_num = current_menu->num_options - 1; + + current_option = current_menu->options + current_option_num; + clear_help(); + break; + + case CURSOR_RIGHT: + if(current_option->option_type & (NUMBER_SELECTION_OPTION | + STRING_SELECTION_OPTION)) + { + *(current_option->current_option) = + (*current_option->current_option + 1) % + current_option->num_options; + + if(current_option->passive_function) + current_option->passive_function(); + } + break; + + case CURSOR_LEFT: + if(current_option->option_type & (NUMBER_SELECTION_OPTION | + STRING_SELECTION_OPTION)) + { + u32 current_option_val = *(current_option->current_option); + + if(current_option_val) + current_option_val--; + else + current_option_val = current_option->num_options - 1; + + *(current_option->current_option) = current_option_val; + + if(current_option->passive_function) + current_option->passive_function(); + } + break; + + case CURSOR_EXIT: + if(current_menu == &main_menu) + menu_exit(); + + choose_menu(&main_menu); + break; + + case CURSOR_SELECT: + if(current_option->option_type & ACTION_OPTION) + current_option->action_function(); + + if(current_option->option_type & SUBMENU_OPTION) + choose_menu(current_option->sub_menu); + break; + } + } + + set_gba_resolution(screen_scale); + video_resolution_small(); + + clock_speed = (clock_speed_number + 1) * 33; + + #ifdef PSP_BUILD + scePowerSetClockFrequency(clock_speed, clock_speed, clock_speed / 2); + #endif + + SDL_PauseAudio(0); + + return return_value; +} |