diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 835b8758..00ec67d1 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:latest +FROM debian:bookworm-slim RUN apt-get update && \ apt-get upgrade -y && \ @@ -6,8 +6,9 @@ RUN apt-get update && \ wget https://github.com/DragonMinded/libdragon/releases/download/toolchain-continuous-prerelease/gcc-toolchain-mips64-x86_64.deb && \ dpkg -i gcc-toolchain-mips64-x86_64.deb && \ rm gcc-toolchain-mips64-x86_64.deb && \ - wget https://github.com/Polprzewodnikowy/SummerCart64/releases/download/v2.15.1/sc64-deployer-linux-v2.15.1.tar.gz && \ + wget https://github.com/Polprzewodnikowy/SummerCart64/releases/download/v2.16.0/sc64-deployer-linux-v2.16.0.tar.gz && \ tar -xf sc64-deployer-linux-v2.15.1.tar.gz -C /usr/local/bin && \ rm sc64-deployer-linux-v2.15.1.tar.gz && \ + git config --global --add safe.directory "*" && \ SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" && \ echo "$SNIPPET" >> "/root/.bashrc" diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index e2e43352..f86295de 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -6,7 +6,7 @@ "mounts": [ "source=n64flashcartmenu-bashhistory,target=/commandhistory,type=volume" ], - "postCreateCommand": "cd ./libdragon && ./build.sh", + "postCreateCommand": "git submodule update --init && cd ./libdragon && ./build.sh", "customizations": { "vscode": { "extensions": [ diff --git a/Makefile b/Makefile index 516a91ef..ef025402 100644 --- a/Makefile +++ b/Makefile @@ -12,20 +12,26 @@ include $(N64_INST)/include/n64.mk N64_CFLAGS += -iquote $(SOURCE_DIR) SRCS = \ + main.c \ boot/boot.c \ boot/crc32.c \ boot/ipl2.S \ flashcart/flashcart.c \ flashcart/sc64/sc64_internal.c \ flashcart/sc64/sc64.c \ - menu/menu_main.c \ - menu/menu_info.c \ - menu/menu_fileinfo.c \ - menu/settings.c \ - menu/rom_database.c \ - utils/fs.c \ libs/toml/toml.c \ - main.c + menu/actions.c \ + menu/menu.c \ + menu/path.c \ + menu/rom_database.c \ + menu/settings.c \ + menu/views/browser.c \ + menu/views/credits.c \ + menu/views/error.c \ + menu/views/file_info.c \ + menu/views/init.c \ + menu/views/load.c \ + utils/fs.c OBJS = $(addprefix $(BUILD_DIR)/, $(addsuffix .o,$(basename $(SRCS)))) diff --git a/src/boot/boot.c b/src/boot/boot.c index 765057c8..0ad9b4a0 100644 --- a/src/boot/boot.c +++ b/src/boot/boot.c @@ -17,7 +17,7 @@ static const ipl3_crc32_t ipl3_crc32[] = { { .crc32 = 0x587BD543, .seed = 0xAC }, // 5101 { .crc32 = 0x6170A4A1, .seed = 0x3F }, // 6101 { .crc32 = 0x009E9EA3, .seed = 0x3F }, // 7102 - { .crc32 = 0x90BB6CB5, .seed = 0x3F }, // x102 + { .crc32 = 0x90BB6CB5, .seed = 0x3F }, // 6102/7101 { .crc32 = 0x0B050EE0, .seed = 0x78 }, // x103 { .crc32 = 0x98BC2C86, .seed = 0x91 }, // x105 { .crc32 = 0xACC8580A, .seed = 0x85 }, // x106 @@ -38,33 +38,6 @@ static io32_t *boot_get_device_base (boot_params_t *params) { return device_base_address; } -static bool boot_detect_tv_type (boot_params_t *params) { - io32_t *base = boot_get_device_base(params); - - char region = ((io_read((uint32_t) (&base[15])) >> 8) & 0xFF); - - switch (region) { - case 'P': - case 'U': - params->tv_type = BOOT_TV_TYPE_PAL; - break; - - case 'E': - case 'J': - params->tv_type = BOOT_TV_TYPE_NTSC; - break; - - case 'B': - params->tv_type = BOOT_TV_TYPE_MPAL; - break; - - default: - return false; - } - - return true; -} - static bool boot_detect_cic_seed (boot_params_t *params) { io32_t *base = boot_get_device_base(params); @@ -92,10 +65,8 @@ bool boot_is_warm (void) { } void boot (boot_params_t *params) { - if (params->detect_tv_type) { - if (!boot_detect_tv_type(params)) { - params->tv_type = OS_INFO->tv_type; - } + if (params->tv_type == BOOT_TV_TYPE_PASSTHROUGH) { + params->tv_type = OS_INFO->tv_type; } if (params->detect_cic_seed) { @@ -104,6 +75,12 @@ void boot (boot_params_t *params) { } } + // asm volatile ( + // "li $t1, %[status] \n" + // "mtc0 $t1, $12 \n" :: + // [status] "i" (C0_SR_CU1 | C0_SR_CU0 | C0_SR_FR) + // ); + OS_INFO->mem_size_6105 = OS_INFO->mem_size; while (!(cpu_io_read(&SP->SR) & SP_SR_HALT)); @@ -119,8 +96,21 @@ void boot (boot_params_t *params) { cpu_io_write(&AI->MADDR, 0); cpu_io_write(&AI->LEN, 0); - io32_t *base = boot_get_device_base(params); + while (cpu_io_read(&SP->SR) & SP_SR_DMA_BUSY); + uint32_t *ipl2_src = &ipl2; + io32_t *ipl2_dst = SP_MEM->IMEM; + + for (int i = 0; i < 8; i++) { + cpu_io_write(&ipl2_dst[i], ipl2_src[i]); + } + + cpu_io_write(&PI->DOM[0].LAT, 0xFF); + cpu_io_write(&PI->DOM[0].PWD, 0xFF); + cpu_io_write(&PI->DOM[0].PGS, 0x0F); + cpu_io_write(&PI->DOM[0].RLS, 0x03); + + io32_t *base = boot_get_device_base(params); uint32_t pi_config = io_read((uint32_t) (base)); cpu_io_write(&PI->DOM[0].LAT, pi_config & 0xFF); @@ -132,13 +122,6 @@ void boot (boot_params_t *params) { while (cpu_io_read(&DPC->SR) & DPC_SR_PIPE_BUSY); } - uint32_t *ipl2_src = &ipl2; - io32_t *ipl2_dst = SP_MEM->IMEM; - - for (int i = 0; i < 8; i++) { - cpu_io_write(&ipl2_dst[i], ipl2_src[i]); - } - io32_t *ipl3_src = base; io32_t *ipl3_dst = SP_MEM->DMEM; @@ -159,7 +142,7 @@ void boot (boot_params_t *params) { tv_type = (params->tv_type & 0x03); reset_type = (params->reset_type & 0x01); cic_seed = (params->cic_seed & 0xFF); - version = 1; + version = (params->tv_type == BOOT_TV_TYPE_PAL) ? 6 : 1; stack_pointer = (void *) UNCACHED(&SP_MEM->IMEM[1020]); asm volatile ( diff --git a/src/boot/boot.h b/src/boot/boot.h index 4328f411..4abd082a 100644 --- a/src/boot/boot.h +++ b/src/boot/boot.h @@ -20,6 +20,7 @@ typedef enum { BOOT_TV_TYPE_PAL = 0, BOOT_TV_TYPE_NTSC = 1, BOOT_TV_TYPE_MPAL = 2, + BOOT_TV_TYPE_PASSTHROUGH = 3, } boot_tv_type_t; @@ -28,7 +29,6 @@ typedef struct { boot_reset_type_t reset_type; boot_tv_type_t tv_type; uint8_t cic_seed; - bool detect_tv_type; bool detect_cic_seed; } boot_params_t; diff --git a/src/flashcart/sc64/sc64.c b/src/flashcart/sc64/sc64.c index 41b6e38e..f18b231d 100644 --- a/src/flashcart/sc64/sc64.c +++ b/src/flashcart/sc64/sc64.c @@ -87,7 +87,12 @@ static flashcart_error_t sc64_load_rom (char *rom_path) { return FLASHCART_ERROR_LOAD; } - size_t rom_size = ALIGN(f_size(&fil), FS_SECTOR_SIZE); + // HACK: Align file size to the SD sector size to prevent FatFs from doing partial sector load. + // We are relying on direct transfer from SD to SDRAM without CPU intervention. + // Sending some extra bytes isn't an issue here. + fil.obj.objsize = ALIGN(f_size(&fil), FS_SECTOR_SIZE); + + size_t rom_size = f_size(&fil); if (rom_size > MiB(78)) { f_close(&fil); diff --git a/src/main.c b/src/main.c index 5d438566..7f50559d 100644 --- a/src/main.c +++ b/src/main.c @@ -5,8 +5,8 @@ #include "boot/boot.h" #include "flashcart/flashcart.h" +#include "menu/menu.h" #include "menu/settings.h" -#include "menu/menu_main.h" static void init (void) { @@ -19,15 +19,12 @@ static void init (void) { assertf(error == FLASHCART_OK, "Unknown error while initializing flashcart"); controller_init(); - - display_close(); - display_init(RESOLUTION_640x240, DEPTH_16_BPP, 3, GAMMA_NONE, ANTIALIAS_RESAMPLE); + display_init(RESOLUTION_640x240, DEPTH_16_BPP, 2, GAMMA_NONE, ANTIALIAS_RESAMPLE); graphics_set_color(0xFFFFFFFF, 0x00000000); graphics_set_default_font(); } static void deinit (void) { - display_close(); flashcart_deinit(); rdpq_close(); rspq_close(); @@ -38,7 +35,6 @@ static void deinit (void) { int main (void) { - init(); settings_t settings; @@ -49,7 +45,7 @@ int main (void) { // menu_restore(&settings); // } - menu_main_init(&settings); + menu_run(&settings); deinit(); diff --git a/src/menu/actions.c b/src/menu/actions.c new file mode 100644 index 00000000..2e509cd0 --- /dev/null +++ b/src/menu/actions.c @@ -0,0 +1,66 @@ +#include + +#include "actions.h" + + +#define ACTIONS_REPEAT_DELAY 20 +#define ACTIONS_REPEAT_RATE 2 + + +void actions_update (menu_t *menu) { + menu->actions.go_up = false; + menu->actions.go_down = false; + menu->actions.fast = false; + menu->actions.enter = false; + menu->actions.back = false; + menu->actions.info = false; + menu->actions.settings = false; + + controller_scan(); + struct controller_data down = get_keys_down(); + struct controller_data held = get_keys_held(); + + if (down.c[0].err != 0) { + return; + } + + if (down.c[0].up || down.c[0].C_up) { + menu->actions.go_up = true; + menu->actions.held_counter = 0; + if (down.c[0].C_up) { + menu->actions.fast = true; + } + } else if (down.c[0].down || down.c[0].C_down) { + menu->actions.go_down = true; + menu->actions.held_counter = 0; + if (down.c[0].C_down) { + menu->actions.fast = true; + } + } else if (held.c[0].up || held.c[0].C_up) { + menu->actions.held_counter += 1; + if ((menu->actions.held_counter >= ACTIONS_REPEAT_DELAY) && (menu->actions.held_counter % ACTIONS_REPEAT_RATE)) { + menu->actions.go_up = true; + if (held.c[0].C_up) { + menu->actions.fast = true; + } + } + } else if (held.c[0].down || held.c[0].C_down) { + menu->actions.held_counter += 1; + if ((menu->actions.held_counter >= ACTIONS_REPEAT_DELAY) && (menu->actions.held_counter % ACTIONS_REPEAT_RATE)) { + menu->actions.go_down = true; + if (held.c[0].C_down) { + menu->actions.fast = true; + } + } + } + + if (down.c[0].A) { + menu->actions.enter = true; + } else if (down.c[0].B) { + menu->actions.back = true; + } else if (down.c[0].Z) { + menu->actions.info = true; + } else if (down.c[0].start) { + menu->actions.settings = true; + } +} diff --git a/src/menu/actions.h b/src/menu/actions.h new file mode 100644 index 00000000..3f96be46 --- /dev/null +++ b/src/menu/actions.h @@ -0,0 +1,11 @@ +#ifndef ACTIONS_H__ +#define ACTIONS_H__ + + +#include "menu.h" + + +void actions_update (menu_t *menu); + + +#endif diff --git a/src/menu/menu.c b/src/menu/menu.c new file mode 100644 index 00000000..82d77439 --- /dev/null +++ b/src/menu/menu.c @@ -0,0 +1,104 @@ +#include + +#include + +#include "actions.h" +#include "menu.h" +#include "views.h" + + +static menu_t *menu_init (settings_t *settings) { + menu_t *menu = calloc(1, sizeof(menu_t)); + + menu->mode = MENU_MODE_INIT; + menu->next_mode = MENU_MODE_BROWSER; + + menu->browser.valid = false; + menu->browser.directory = path_init(NULL); // TODO: load starting directory from settings + + return menu; +} + +static void menu_deinit (menu_t *menu) { + path_free(menu->browser.directory); + free(menu); +} + + +void menu_run (settings_t *settings) { + menu_t *menu = menu_init(settings); + + bool running = true; + + while (running) { + surface_t *display = display_try_get(); + + if (display != NULL) { + actions_update(menu); + + switch (menu->mode) { + case MENU_MODE_INIT: + view_init_display(menu, display); + break; + + case MENU_MODE_BROWSER: + view_browser_display(menu, display); + break; + + case MENU_MODE_FILE_INFO: + view_file_info_display(menu, display); + break; + + case MENU_MODE_CREDITS: + view_credits_display(menu, display); + break; + + case MENU_MODE_LOAD: + view_load_display(menu, display); + break; + + case MENU_MODE_ERROR: + view_error_display(menu, display); + break; + + default: + break; + } + + while (menu->mode != menu->next_mode) { + menu->mode = menu->next_mode; + + switch (menu->next_mode) { + case MENU_MODE_BROWSER: + view_browser_init(menu); + break; + + case MENU_MODE_FILE_INFO: + view_file_info_init(menu); + break; + + case MENU_MODE_CREDITS: + view_credits_init(menu); + break; + + case MENU_MODE_LOAD: + view_load_init(menu); + break; + + case MENU_MODE_ERROR: + view_error_init(menu); + break; + + case MENU_MODE_BOOT: + running = false; + break; + + default: + break; + } + } + } + } + + menu_deinit(menu); +} diff --git a/src/menu/menu.h b/src/menu/menu.h new file mode 100644 index 00000000..2b33727a --- /dev/null +++ b/src/menu/menu.h @@ -0,0 +1,62 @@ +#ifndef MENU_H__ +#define MENU_H__ + + +#include "path.h" +#include "settings.h" + + +#define BROWSER_LIST_SIZE 4096 + + +typedef enum { + MENU_MODE_INIT, + MENU_MODE_BROWSER, + MENU_MODE_FILE_INFO, + MENU_MODE_CREDITS, + MENU_MODE_LOAD, + MENU_MODE_ERROR, + MENU_MODE_BOOT, +} menu_mode_t; + +typedef enum { + ENTRY_TYPE_DIR, + ENTRY_TYPE_ROM, + ENTRY_TYPE_SAVE, + ENTRY_TYPE_UNKNOWN, +} entry_type_t; + +typedef struct { + char *name; + entry_type_t type; +} entry_t; + +typedef struct { + menu_mode_t mode; + menu_mode_t next_mode; + + struct { + bool go_up; + bool go_down; + bool fast; + bool enter; + bool back; + bool info; + bool settings; + int held_counter; + } actions; + + struct { + bool valid; + path_t *directory; + entry_t list[BROWSER_LIST_SIZE]; + int entries; + int selected; + } browser; +} menu_t; + + +void menu_run (settings_t *settings); + + +#endif diff --git a/src/menu/menu_fileinfo.c b/src/menu/menu_fileinfo.c deleted file mode 100644 index 644d8072..00000000 --- a/src/menu/menu_fileinfo.c +++ /dev/null @@ -1,114 +0,0 @@ -#include -#include "menu_res_setup.h" -#include "menu_fileinfo.h" -#include "../utils/str_utils.h" - - -static char *get_file_type(FILINFO current_fileinfo) { - // TODO: should be at least a switch statement! - if (str_endswith(current_fileinfo.fname, ".z64") || str_endswith(current_fileinfo.fname, ".n64") || str_endswith(current_fileinfo.fname, ".v64") || str_endswith(current_fileinfo.fname, ".rom")) { - // TODO: check the necessary bytes in the header to ensure! - return "N64 ROM"; - } - else if (str_endswith(current_fileinfo.fname, ".txt")) { - return "Text File"; - } - else if (str_endswith(current_fileinfo.fname, ".ini")) { - return "INI File"; - } - else if (str_endswith(current_fileinfo.fname, ".yml") || str_endswith(current_fileinfo.fname, ".yaml")) { - return "YAML File"; - } - else if (str_endswith(current_fileinfo.fname, ".toml")) { - return "TOML File"; - } - else if (str_endswith(current_fileinfo.fname, ".sav")) { - return "Save File"; - } - else if (str_endswith(current_fileinfo.fname, ".emu")) { - return "Emulator File"; - } - else { - return "Unknown File"; - } -} - -void menu_fileinfo_draw_n64_rom_info(surface_t *disp) { - // rom_header_t temp_header = file_read_rom_header(tmp_buffer); - - // sprintf(buff, "ROM checksum: %llu\n", temp_header.checksum); - // sprintf(buff, "ROM title: %s\n", temp_header.title); - // sprintf(buff, "ROM media type: %c\n", temp_header.metadata.media_type); - // sprintf(buff, "ROM unique id: %.2s\n", (char*)&(temp_header.metadata.unique_identifier)); - // sprintf(buff, "ROM dest market: %c\n", temp_header.metadata.destination_market); - // sprintf(buff, "ROM version: %hhu\n", temp_header.version); -} - -void menu_fileinfo_draw_header(surface_t *disp) { - - graphics_draw_text(disp, (disp->width / 2) - 64, vertical_start_position, "FILE INFORMATION"); // centre = numchars * font_horizontal_pixels / 2 - graphics_draw_line(disp, 0, 30, disp->width, 30, 0xff); - -} - -void menu_fileinfo_draw_footer(surface_t *disp) { - - graphics_draw_line(disp, 0, disp->height - overscan_vertical_pixels - font_vertical_pixels, disp->width,disp->height - overscan_vertical_pixels - font_vertical_pixels, 0xff); - graphics_draw_text(disp, (disp->width / 2) - 80,disp->height - overscan_vertical_pixels, "Press (B) to return!"); // centre = numchars * font_horizontal_pixels / 2 - -} - -void menu_fileinfo(FILINFO current_fileinfo) { - - char str_buffer[1024]; - - surface_t *disp = display_try_get(); - graphics_fill_screen(disp, 0x00); - menu_fileinfo_draw_header(disp); - - int16_t vertical_position = 40; - - graphics_draw_text(disp, horizontal_start_position, vertical_position, "Name:"); - graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, current_fileinfo.fname); - vertical_position += (font_vertical_pixels * 2); - - graphics_draw_text(disp, horizontal_start_position, vertical_position, "Size:"); - sprintf(str_buffer, "%d %s", (int)current_fileinfo.fsize, "Bytes"); - graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, str_buffer); - vertical_position += (font_vertical_pixels * 2); - - graphics_draw_text(disp, horizontal_start_position, vertical_position, "Attributes:"); - sprintf(str_buffer, "%s%s%s%s%s\n", - ((current_fileinfo.fattrib & AM_DIR) ? "Directory" : "File"), - ((current_fileinfo.fattrib & AM_RDO) ? " | ReadOnly" : ""), - ((current_fileinfo.fattrib & AM_SYS) ? " | System" : ""), - ((current_fileinfo.fattrib & AM_ARC) ? " | Archive" : ""), - ((current_fileinfo.fattrib & AM_HID) ? " | Hidden" : "") - ); - - graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, str_buffer); - vertical_position += (font_vertical_pixels * 2); - - graphics_draw_text(disp, horizontal_start_position, vertical_position, "Modified Timestamp:"); - sprintf(str_buffer, "%u-%02u-%02u, %02u:%02u", (current_fileinfo.fdate >> 9) + 1980, current_fileinfo.fdate >> 5 & 15, current_fileinfo.fdate & 31, current_fileinfo.ftime >> 11, current_fileinfo.ftime >> 5 & 63); - graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, str_buffer); - vertical_position += (font_vertical_pixels * 2); - - graphics_draw_text(disp, horizontal_start_position, vertical_position, "Type:"); - graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, get_file_type(current_fileinfo)); - - //menu_fileinfo_draw_n64_rom_info(disp); - - menu_fileinfo_draw_footer(disp); - - display_show(disp); - - for (;;) { - controller_scan(); - struct controller_data ckeys = get_keys_down(); - - if (ckeys.c[0].B) { - break; - } - } -} \ No newline at end of file diff --git a/src/menu/menu_fileinfo.h b/src/menu/menu_fileinfo.h deleted file mode 100644 index 06b4fe0e..00000000 --- a/src/menu/menu_fileinfo.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef MENU_FILEINFO_H__ -#define MENU_FILEINFO_H__ - -#include - -void menu_fileinfo(FILINFO current_fileinfo); - -#endif diff --git a/src/menu/menu_info.c b/src/menu/menu_info.c deleted file mode 100644 index 68d47023..00000000 --- a/src/menu/menu_info.c +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include "menu_info.h" -#include "menu_res_setup.h" - -void menu_info_draw_header(surface_t *disp) { - - graphics_draw_text(disp, (disp->width / 2) - 64, vertical_start_position, "MENU INFORMATION"); // centre = numchars * font_horizontal_pixels / 2 - graphics_draw_line(disp, 0, 30, disp->width, 30, 0xff); - -} - -void menu_info_draw_footer(surface_t *disp) { - - graphics_draw_line(disp, 0, disp->height - overscan_vertical_pixels - font_vertical_pixels, disp->width,disp->height - overscan_vertical_pixels - font_vertical_pixels, 0xff); - graphics_draw_text(disp, (disp->width / 2) - 80,disp->height - overscan_vertical_pixels, "Press (B) to return!"); // centre = numchars * font_horizontal_pixels / 2 - -} - -void menu_info(void) { - - surface_t *disp = display_try_get(); - graphics_fill_screen(disp, 0x00); - menu_info_draw_header(disp); - - int16_t vertical_position = 40; - - graphics_draw_text(disp, horizontal_start_position, vertical_position, "Menu Version:"); - graphics_draw_text(disp, horizontal_indent,vertical_position += font_vertical_pixels, MENU_VERSION); - vertical_position += (font_vertical_pixels * 2); - graphics_draw_text(disp, horizontal_start_position, vertical_position, "Authors:"); - graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, "JonesAlmighty / NetworkFusion"); - graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, "korgeaux / Polprzewodnikowy"); - vertical_position += (font_vertical_pixels * 2); - graphics_draw_text(disp, horizontal_start_position, vertical_position += font_vertical_pixels, "Github:"); - // graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, "https://github.com/Polprzewodnikowy/SummerCart64"); - graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, "https://github.com/Polprzewodnikowy/N64FlashcartMenu"); - graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, "https://github.com/NetworkFusion/N64FlashcartMenu"); - vertical_position += (font_vertical_pixels * 2); - graphics_draw_text(disp, horizontal_start_position, vertical_position, "OSS licenses used:"); - graphics_draw_text(disp, horizontal_indent,vertical_position += font_vertical_pixels, "UNLICENSE"); - graphics_draw_text(disp, horizontal_indent,vertical_position += font_vertical_pixels, "MIT"); - - menu_info_draw_footer(disp); - - display_show(disp); - - for (;;) { - controller_scan(); - struct controller_data ckeys = get_keys_down(); - - if (ckeys.c[0].B) { - break; - } - } -} \ No newline at end of file diff --git a/src/menu/menu_info.h b/src/menu/menu_info.h deleted file mode 100644 index 4fb6d5d4..00000000 --- a/src/menu/menu_info.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef MENU_INFO_H__ -#define MENU_INFO_H__ - -#define MENU_VERSION "V0.0.0.3" - -void menu_info(void); - -#endif diff --git a/src/menu/menu_main.c b/src/menu/menu_main.c deleted file mode 100644 index c8846c9a..00000000 --- a/src/menu/menu_main.c +++ /dev/null @@ -1,265 +0,0 @@ -#include -#include // TODO: does this work... will unlock qsort! -#include - -#include -#include - -#include "flashcart/flashcart.h" - -#include "settings.h" -#include "menu_main.h" -#include "menu_info.h" -#include "menu_fileinfo.h" -#include "rom_database.h" -#include "menu_res_setup.h" - -#include "../utils/str_utils.h" - -//const int max_files_on_screen = 16; -static int scroll_menu_position = 1; -static int items_in_dir = 1; - -static FILINFO current_fileinfo; - - -void load_n64_rom() { - - console_init(); - console_clear(); - - char sd_path_buffer[1024]; - sprintf(sd_path_buffer, "sd:/%s", current_fileinfo.fname); - - rom_header_t temp_header = file_read_rom_header(sd_path_buffer); - - printf("Loading N64 ROM type...\n"); - printf("%s\n\n", current_fileinfo.fname); - - printf("ROM title: %s\n\n", temp_header.title); - - printf("ROM media type: %c\n", temp_header.metadata.media_type); - printf("ROM unique id: %.2s\n", (char*)&(temp_header.metadata.unique_identifier)); - printf("uid as int: %d\n\n", temp_header.metadata.unique_identifier); - - printf("ROM destination market: %c\n\n", temp_header.metadata.destination_market); - - printf("ROM version: %hhu\n", temp_header.version); - printf("ROM checksum: %llu\n\n", temp_header.checksum); - - // FIXME: if the ROM header does not make sense, it is an invalid ROM. - wait_ms(5000); // wait used for debugging. Can be removed later. - - - uint8_t save_type = rom_db_match_save_type(temp_header); - - printf("save type: %d\n", save_type); - - wait_ms(5000); // wait used for debugging. Can be removed later. - - sprintf(sd_path_buffer, "%s.%llu.sav", current_fileinfo.fname, temp_header.checksum); - wait_ms(5000); // wait used for debugging. Can be removed later. - - assertf(flashcart_load_save(sd_path_buffer, (flashcart_save_type_t)save_type, true) == FLASHCART_OK, "ROM load save error"); - - assertf(flashcart_load_rom(current_fileinfo.fname) == FLASHCART_OK, "ROM load error"); - -} - -// FIXME: use newlib rather than fatfs to do this! -FRESULT scan_file_path (surface_t *disp, char *path) { - - FRESULT res; - DIR dir; - char sfno[1024]; - int counter = 0; //FIXME: we dont account for an empty dir or only one valid file! - int16_t vertical_position = 56; - char str_buffer[1036]; - - res = f_opendir(&dir, path); - - if (res == FR_OK) { - for (;;) { - FILINFO file_info; - - res = f_readdir(&dir, &file_info); - - if ((res != FR_OK) || (file_info.fname[0] == 0)) { - break; - } - - if (file_info.fattrib & AM_SYS) { - continue; // we do not want to show system files ever... - } - - counter ++; - - // TODO: convert these to icons... - sprintf(sfno, "| %c%c%c | %10d | %s", - ((file_info.fattrib & AM_DIR) ? 'D' : '-'), - ((file_info.fattrib & AM_RDO) ? 'R' : '-'), - ((file_info.fattrib & AM_HID) ? 'H' : '-'), - (int)file_info.fsize, file_info.fname); - - if (scroll_menu_position == counter) { - sprintf(str_buffer, "-> %s\n", sfno); - graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, str_buffer); - current_fileinfo = file_info; - } - else { - sprintf(str_buffer, " %s\n", sfno); - graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, str_buffer); - } - } - } - items_in_dir = counter; - f_closedir(&dir); - return res; -} - -void menu_main_draw_header(surface_t *disp) { - - graphics_draw_text(disp, (disp->width / 2) - 36, vertical_start_position, "FILE MENU"); // centre = numchars * font_horizontal_pixels / 2 - graphics_draw_line(disp,0,30,disp->width,30, 0xff); -} - -void menu_main_draw_footer(char *dir_path, surface_t *disp) { - - graphics_draw_line(disp,0,disp->height - overscan_vertical_pixels - font_vertical_pixels, disp->width,disp->height - overscan_vertical_pixels - font_vertical_pixels, 0xff); - - char str_buffer[1024]; - sprintf(str_buffer, "Current Directory: SD:%s\nFile: %d of %d\n\n", dir_path, scroll_menu_position, items_in_dir); - - graphics_draw_text(disp, (disp->width / 2) - 160,disp->height - overscan_vertical_pixels, str_buffer); // centre = numchars * font_horizontal_pixels / 2 - -} - -void menu_main_refresh (char *dir_path) { - - surface_t *disp = display_get(); - graphics_fill_screen(disp, 0); - - menu_main_draw_header(disp); - - int16_t vertical_position = 40; - - char str_buffer[1024]; - sprintf(str_buffer, " | DRH | FILE SIZE | FILE NAME\n"); - graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, str_buffer); - sprintf(str_buffer, " |-----|------------|----------\n"); - graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, str_buffer); - - scan_file_path(disp, dir_path); - - menu_main_draw_footer(dir_path, disp); - - display_show(disp); - -} - -void menu_main_init (settings_t *settings) { - - - - char *current_dir = settings->last_state.current_directory; - char *last_dir = current_dir; - struct controller_data joypad = get_keys_down(); - - if ((settings->last_state.auto_load_last_rom) && !(joypad.c[0].B)) { // FIXME: the B button on any controller! - - console_init(); - console_clear(); - - printf("Loading last ROM: %s\n", settings->last_rom.rom_path); - assertf(flashcart_load_rom(settings->last_rom.rom_path) == FLASHCART_OK, "ROM load error"); - - printf("Loading save: %s, type: %d, writeback: %d\n", settings->last_rom.save_path, settings->last_rom.save_type, settings->last_rom.save_writeback); - assertf(flashcart_load_save(settings->last_rom.save_path, settings->last_rom.save_type, settings->last_rom.save_writeback) == FLASHCART_OK, "Save load error"); - } - else { - settings->last_state.auto_load_last_rom = false; - menu_main_refresh(current_dir); - } - - for (;;) { - controller_scan(); - joypad = get_keys_down(); - - if (joypad.c[0].up) { - if (scroll_menu_position > 1 && scroll_menu_position <= items_in_dir) { - scroll_menu_position --; - } - else { - scroll_menu_position = items_in_dir; - } - menu_main_refresh(current_dir); - } - - if (joypad.c[0].down) { - if (scroll_menu_position < items_in_dir) { - scroll_menu_position ++; - } - else { - scroll_menu_position = 1; - } - menu_main_refresh(current_dir); - } - - if (joypad.c[0].A) { - // TODO: move this to a function and check that the ROM is valid by checking the header... - if (str_endswith(current_fileinfo.fname, ".z64")) { - - load_n64_rom(); - - break; //required! - } - else if (str_endswith(current_fileinfo.fname, ".n64") || str_endswith(current_fileinfo.fname, ".v64") || str_endswith(current_fileinfo.fname, ".rom")) { - console_init(); - console_clear(); - - printf("ROM : %s\n", current_fileinfo.fname); - printf("Not loading due to potential conversion issue.\n"); - wait_ms(10000); // wait used for debugging. Can be removed later. - menu_main_refresh(current_dir); - } - else if (str_endswith(current_fileinfo.fname, ".zip")) { - console_init(); - console_clear(); - - printf("ZIP : %s\n", current_fileinfo.fname); - printf("Not loading due to potential conversion issue.\n"); - wait_ms(10000); // wait used for debugging. Can be removed later. - menu_main_refresh(current_dir); - } - else { - if (current_fileinfo.fattrib & AM_DIR) { - // if this is a directory we need to transverse to it! - items_in_dir = 1; - scroll_menu_position = 1; - last_dir = current_dir; - current_dir = current_fileinfo.fname; - menu_main_refresh(current_dir); - } - else { - - menu_fileinfo(current_fileinfo); - menu_main_refresh(current_dir); - } - } - } - if (joypad.c[0].B) { - menu_main_refresh(current_dir); - current_dir = last_dir; - } - if (joypad.c[0].start) { // FIXME: the START button on any controller! - menu_info(); - menu_main_refresh(current_dir); - } - if (joypad.c[0].Z) { - menu_fileinfo(current_fileinfo); - menu_main_refresh(current_dir); - } - } - // TODO: write menu state to SD card - -} diff --git a/src/menu/menu_main.h b/src/menu/menu_main.h deleted file mode 100644 index f8f8332c..00000000 --- a/src/menu/menu_main.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef MENU_MAIN_H__ -#define MENU_MAIN_H__ - -void menu_main_init (settings_t *settings); - -#endif diff --git a/src/menu/path.c b/src/menu/path.c new file mode 100644 index 00000000..65c3e460 --- /dev/null +++ b/src/menu/path.c @@ -0,0 +1,102 @@ +#include + +#include +#include +#include "path.h" + + +#define PATH_CAPACITY_INITIAL 255 +#define PATH_CAPACITY_ALIGNMENT 32 + + +static void path_resize (path_t *path, size_t min_length) { + path->capacity = min_length > PATH_CAPACITY_INITIAL ? min_length : PATH_CAPACITY_INITIAL; + size_t alignment = path->capacity % PATH_CAPACITY_ALIGNMENT; + if (alignment != (PATH_CAPACITY_ALIGNMENT - 1)) { + path->capacity += PATH_CAPACITY_ALIGNMENT - alignment; + } + path->buffer = realloc(path->buffer, (path->capacity + 1) * sizeof(char)); +} + +path_t *path_init (char *string) { + if (string == NULL) { + string = ""; + } + path_t *path = calloc(1, sizeof(path_t)); + path_resize(path, strlen(string)); + memset(path->buffer, 0, path->capacity + 1); + strcpy(path->buffer, string); + return path; +} + +void path_free (path_t *path) { + free(path->buffer); + free(path); +} + +path_t *path_clone (path_t *path) { + return path_init(path->buffer); +} + +char *path_get (path_t *path) { + return path->buffer; +} + +char *path_last_get (path_t *path) { + char *last_slash = strrchr(path->buffer, '/'); + return (last_slash == NULL) ? path->buffer : (last_slash + 1); +} + +void path_append (path_t *path, char *string) { + size_t buffer_length = strlen(path->buffer); + size_t string_length = strlen(string); + size_t new_path_length = buffer_length + string_length; + if (new_path_length > path->capacity) { + path_resize(path, new_path_length); + } + strcat(path->buffer, string); +} + +void path_concat (path_t *dst, path_t *src) { + path_append(dst, src->buffer); +} + +void path_push (path_t *path, char *string) { + if (path->buffer[strlen(path->buffer) - 1] != '/') { + path_append(path, "/"); + } + if (string[0] == '/') { + string += 1; + } + path_append(path, string); +} + +void path_pop (path_t *path) { + char *last_slash = strrchr(path->buffer, '/'); + if (last_slash != NULL) { + *last_slash = '\0'; + } +} + +char *path_ext_get (path_t *path) { + char *buffer = path_last_get(path); + char *last_dot = strrchr(buffer, '.'); + if (last_dot != NULL) { + return last_dot + 1; + } + return NULL; +} + +void path_ext_remove (path_t *path) { + char *buffer = path_last_get(path); + char *last_dot = strrchr(buffer, '.'); + if (last_dot != NULL) { + *last_dot = '\0'; + } +} + +void path_ext_replace (path_t *path, char *ext) { + path_ext_remove(path); + path_append(path, "."); + path_append(path, ext); +} diff --git a/src/menu/path.h b/src/menu/path.h new file mode 100644 index 00000000..196bbe19 --- /dev/null +++ b/src/menu/path.h @@ -0,0 +1,25 @@ +#ifndef PAHT_H__ +#define PATH_H__ + + +typedef struct { + char *buffer; + size_t capacity; +} path_t; + + +path_t *path_init (char *string); +void path_free (path_t *path); +path_t *path_clone (path_t *string); +char *path_get (path_t *path); +char *path_last_get (path_t *path); +void path_append (path_t *path, char *string); +void path_concat (path_t *dst, path_t *str); +void path_push (path_t *path, char *string); +void path_pop (path_t *path); +char *path_ext_get (path_t *path); +void path_ext_remove (path_t *path); +void path_ext_replace (path_t *path, char *ext); + + +#endif diff --git a/src/menu/rom_database.c b/src/menu/rom_database.c index 7cd57a5d..5c7176cb 100644 --- a/src/menu/rom_database.c +++ b/src/menu/rom_database.c @@ -1,7 +1,9 @@ +#include #include "rom_database.h" #include #include #include +#include uint8_t extract_homebrew_setting(uint8_t setting, uint8_t bit_position) { return (setting & (1 << bit_position)) ? 1 : 0; @@ -29,10 +31,14 @@ uint8_t extract_homebrew_save_type(uint8_t save_type) { } rom_header_t file_read_rom_header(char *path) { - FILE *fp = fopen(path, "rb"); - printf("loading path: %s\n", path); + char *sd_path = calloc(4 + strlen(path) + 1, sizeof(char)); + sprintf(sd_path, "sd:/%s", path); + + FILE *fp = fopen(sd_path, "rb"); + + debugf("loading path: %s\n", sd_path); if (!fp) { - printf("Error loading rom file header\n"); + debugf("Error loading rom file header\n"); } rom_header_t *rom_header = malloc(sizeof(rom_header_t)); @@ -53,6 +59,8 @@ rom_header_t file_read_rom_header(char *path) { fclose(fp); + free(sd_path); + return *rom_header; } diff --git a/src/menu/settings.c b/src/menu/settings.c index f7e6ec80..1666509c 100644 --- a/src/menu/settings.c +++ b/src/menu/settings.c @@ -162,7 +162,7 @@ void settings_load_default_state(settings_t *settings) { settings->boot_params.device_type = BOOT_DEVICE_TYPE_ROM; settings->boot_params.reset_type = BOOT_RESET_TYPE_NMI; - settings->boot_params.detect_tv_type = true; + settings->boot_params.tv_type = BOOT_TV_TYPE_PASSTHROUGH; settings->boot_params.detect_cic_seed = true; // Initialize other default settings... diff --git a/src/menu/views.h b/src/menu/views.h new file mode 100644 index 00000000..f7308d22 --- /dev/null +++ b/src/menu/views.h @@ -0,0 +1,28 @@ +#ifndef VIEWS_H__ +#define VIEWS_H__ + + +#include + +#include "menu.h" + + +void view_init_display (menu_t *menu, surface_t *display); + +void view_browser_init (menu_t *menu); +void view_browser_display (menu_t *menu, surface_t *display); + +void view_file_info_init (menu_t *menu); +void view_file_info_display (menu_t *menu, surface_t *display); + +void view_credits_init (menu_t *menu); +void view_credits_display (menu_t *menu, surface_t *display); + +void view_load_init (menu_t *menu); +void view_load_display (menu_t *menu, surface_t *display); + +void view_error_init (menu_t *menu); +void view_error_display (menu_t *menu, surface_t *display); + + +#endif diff --git a/src/menu/views/browser.c b/src/menu/views/browser.c new file mode 100644 index 00000000..ae4bd60c --- /dev/null +++ b/src/menu/views/browser.c @@ -0,0 +1,222 @@ +#include +#include +#include +#include "../menu.h" +#include "../menu_res_setup.h" +#include "../../utils/str_utils.h" + + +#define BROWSER_LIST_ROWS 21 + + +static int compare_entry (const void *pa, const void *pb) { + entry_t *a = (entry_t *) (pa); + entry_t *b = (entry_t *) (pb); + + if (a->type != b->type) { + if (a->type == ENTRY_TYPE_DIR) { + return -1; + } else if (b->type == ENTRY_TYPE_DIR) { + return 1; + } else if (a->type == ENTRY_TYPE_ROM) { + return -1; + } else if (b->type == ENTRY_TYPE_ROM) { + return 1; + } else if (a->type == ENTRY_TYPE_SAVE) { + return -1; + } else if (b->type == ENTRY_TYPE_SAVE) { + return 1; + } + } + + return strcasecmp((const char *) (a->name), (const char *) (b->name)); +} + +static void load_directory (menu_t *menu) { + DIR dir; + FILINFO info; + + for (int i = 0; i < menu->browser.entries; i++) { + free(menu->browser.list[i].name); + } + menu->browser.entries = 0; + menu->browser.selected = -1; + + if (f_opendir(&dir, path_get(menu->browser.directory)) != FR_OK) { + menu->next_mode = MENU_MODE_ERROR; + return; + } + + while (true) { + if (f_readdir(&dir, &info) != FR_OK) { + menu->next_mode = MENU_MODE_ERROR; + return; + } + + size_t length = strlen(info.fname); + if (length == 0) { + break; + } + + if (info.fattrib & AM_SYS) { + continue; + } + + entry_t *entry = &menu->browser.list[menu->browser.entries]; + + entry->name = malloc((length + 1) * sizeof(char)); + strcpy(entry->name, info.fname); + + if (info.fattrib & AM_DIR) { + entry->type = ENTRY_TYPE_DIR; + // TODO: use something like `ext_is_n64_rom(info.fname)` instead of `str_endswith(info.fname, ".xxx")` + } else if (str_endswith(info.fname, ".n64") || str_endswith(info.fname, ".z64") || str_endswith(info.fname, ".v64") || str_endswith(info.fname, ".N64")) { + entry->type = ENTRY_TYPE_ROM; + } else if (str_endswith(info.fname, ".sav")) { + entry->type = ENTRY_TYPE_SAVE; + } else { + entry->type = ENTRY_TYPE_UNKNOWN; + } + + menu->browser.entries += 1; + if (menu->browser.entries == BROWSER_LIST_SIZE) { + break; + } + } + + f_closedir(&dir); + + if (menu->browser.entries > 0) { + menu->browser.selected = 0; + } + + qsort(menu->browser.list, menu->browser.entries, sizeof(entry_t), compare_entry); +} + +void push_directory (menu_t *menu, char *directory) { + path_push(menu->browser.directory, directory); + load_directory(menu); +} + +void pop_directory (menu_t *menu) { + path_t *current_directory = path_clone(menu->browser.directory); + path_pop(menu->browser.directory); + load_directory(menu); + for (int i = 0; i < menu->browser.entries; i++) { + if (strcmp(menu->browser.list[i].name, path_last_get(current_directory)) == 0) { + menu->browser.selected = i; + break; + } + } + path_free(current_directory); +} + + +static void process (menu_t *menu) { + int scroll_speed = menu->actions.fast ? BROWSER_LIST_ROWS : 1; + + if (menu->browser.entries > 1) { + if (menu->actions.go_up) { + menu->browser.selected -= scroll_speed; + if (menu->browser.selected < 0) { + menu->browser.selected = 0; + } + } else if (menu->actions.go_down) { + menu->browser.selected += scroll_speed; + if (menu->browser.selected >= menu->browser.entries) { + menu->browser.selected = menu->browser.entries - 1; + } + } + } + + if (menu->actions.enter) { + entry_t *entry = &menu->browser.list[menu->browser.selected]; + + switch (entry->type) { + case ENTRY_TYPE_DIR: + push_directory(menu, entry->name); + break; + + case ENTRY_TYPE_ROM: + menu->next_mode = MENU_MODE_LOAD; + break; + + default: + menu->next_mode = MENU_MODE_FILE_INFO; + break; + } + } else if (menu->actions.back) { + pop_directory(menu); + } else if (menu->actions.info) { + menu->next_mode = MENU_MODE_FILE_INFO; + } else if (menu->actions.settings) { + menu->next_mode = MENU_MODE_CREDITS; + } +} + +static void draw (menu_t *menu, surface_t *d) { + int x = 24; + int y = 35; + + int starting_position = 0; + int entries_drawn = 0; + + if (menu->browser.entries > BROWSER_LIST_ROWS && menu->browser.selected >= (BROWSER_LIST_ROWS / 2)) { + starting_position = menu->browser.selected - (BROWSER_LIST_ROWS / 2); + if (starting_position >= menu->browser.entries - BROWSER_LIST_ROWS) { + starting_position = menu->browser.entries - BROWSER_LIST_ROWS; + } + } + + graphics_fill_screen(d, graphics_make_color(0, 0, 0, 255)); + + graphics_draw_text(d, (d->width / 2) - 36, vertical_start_position, "FILE MENU"); + graphics_draw_line(d, 0, 30, d->width, 30, 0xff); + + char str_buffer[1024]; + + for (int i = starting_position; i < menu->browser.entries; i++) { + if (i == menu->browser.selected) { + uint32_t color; + switch (menu->browser.list[i].type) { + case ENTRY_TYPE_ROM: + color = graphics_make_color(0, 64, 0, 0); + break; + default: + color = graphics_make_color(64, 64, 64, 0); + break; + } + graphics_draw_box(d, x, y, (640 - x * 2), font_vertical_pixels, color); + } + snprintf(str_buffer, 1024, "%.74s", menu->browser.list[i].name); + graphics_draw_text(d, x, y, str_buffer); + + y += font_vertical_pixels; + + entries_drawn += 1; + if (entries_drawn == BROWSER_LIST_ROWS) { + break; + } + } + + graphics_draw_line(d, 0, d->height - overscan_vertical_pixels - font_vertical_pixels, d->width, d->height - overscan_vertical_pixels - font_vertical_pixels, 0xff); + + sprintf(str_buffer, "Current Directory: SD:%s\nFile: %d of %d\n\n", path_get(menu->browser.directory), menu->browser.selected + 1, menu->browser.entries); + + graphics_draw_text(d, (d->width / 2) - 160, d->height - overscan_vertical_pixels, str_buffer); + + display_show(d); +} + + +void view_browser_init (menu_t *menu) { + if (!menu->browser.valid) { + menu->browser.valid = true; + load_directory(menu); + } +} + +void view_browser_display (menu_t *menu, surface_t *display) { + process(menu); + draw(menu, display); +} diff --git a/src/menu/views/credits.c b/src/menu/views/credits.c new file mode 100644 index 00000000..fdba385c --- /dev/null +++ b/src/menu/views/credits.c @@ -0,0 +1,53 @@ +#include +#include "../menu.h" +#include "../menu_res_setup.h" + + +#define MENU_VERSION "V0.0.0.3" + + +static void process (menu_t *menu) { + if (menu->actions.back) { + menu->next_mode = MENU_MODE_BROWSER; + } +} + +static void draw (menu_t *menu, surface_t *d) { + graphics_fill_screen(d, 0x00); + + graphics_draw_text(d, (d->width / 2) - 64, vertical_start_position, "MENU INFORMATION"); // centre = numchars * font_horizontal_pixels / 2 + graphics_draw_line(d, 0, 30, d->width, 30, 0xff); + + int16_t vertical_position = 40; + + graphics_draw_text(d, horizontal_start_position, vertical_position, "Menu Version:"); + graphics_draw_text(d, horizontal_indent,vertical_position += font_vertical_pixels, MENU_VERSION); + vertical_position += (font_vertical_pixels * 2); + graphics_draw_text(d, horizontal_start_position, vertical_position, "Authors:"); + graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "JonesAlmighty / NetworkFusion"); + graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "korgeaux / Polprzewodnikowy"); + vertical_position += (font_vertical_pixels * 2); + graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, "Github:"); + // graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "https://github.com/Polprzewodnikowy/SummerCart64"); + graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "https://github.com/Polprzewodnikowy/N64FlashcartMenu"); + graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "https://github.com/NetworkFusion/N64FlashcartMenu"); + vertical_position += (font_vertical_pixels * 2); + graphics_draw_text(d, horizontal_start_position, vertical_position, "OSS licenses used:"); + graphics_draw_text(d, horizontal_indent,vertical_position += font_vertical_pixels, "UNLICENSE"); + graphics_draw_text(d, horizontal_indent,vertical_position += font_vertical_pixels, "MIT"); + + graphics_draw_line(d, 0, d->height - overscan_vertical_pixels - font_vertical_pixels, d->width,d->height - overscan_vertical_pixels - font_vertical_pixels, 0xff); + graphics_draw_text(d, (d->width / 2) - 80,d->height - overscan_vertical_pixels, "Press (B) to return!"); // centre = numchars * font_horizontal_pixels / 2 + + display_show(d); +} + + +void view_credits_init (menu_t *menu) { + // Nothing to initialize (yet) +} + +void view_credits_display (menu_t *menu, surface_t *display) { + process(menu); + draw(menu, display); +} diff --git a/src/menu/views/error.c b/src/menu/views/error.c new file mode 100644 index 00000000..b884decc --- /dev/null +++ b/src/menu/views/error.c @@ -0,0 +1,27 @@ +#include +#include "../menu.h" + + +static void process (menu_t *menu) { + if (menu->actions.back) { + menu->next_mode = MENU_MODE_BROWSER; + } +} + +static void draw (menu_t *menu, surface_t *d) { + graphics_fill_screen(d, graphics_make_color(0, 0, 0, 255)); + + graphics_draw_text(d, 24, 36, "ERROR!"); + + display_show(d); +} + + +void view_error_init (menu_t *menu) { + // Nothing to initialize (yet) +} + +void view_error_display (menu_t *menu, surface_t *display) { + process(menu); + draw(menu, display); +} diff --git a/src/menu/views/file_info.c b/src/menu/views/file_info.c new file mode 100644 index 00000000..bd04a5e7 --- /dev/null +++ b/src/menu/views/file_info.c @@ -0,0 +1,106 @@ +#include +#include +#include "../menu.h" +#include "../menu_res_setup.h" +#include "../../utils/str_utils.h" + + +static FILINFO info; + + +static char *get_file_type (void) { + // TODO: should be at least a switch statement! + if (str_endswith(info.fname, ".z64") || str_endswith(info.fname, ".n64") || str_endswith(info.fname, ".v64") || str_endswith(info.fname, ".rom")) { + // TODO: check the necessary bytes in the header to ensure! + return "N64 ROM"; + } + else if (str_endswith(info.fname, ".txt")) { + return "Text File"; + } + else if (str_endswith(info.fname, ".ini")) { + return "INI File"; + } + else if (str_endswith(info.fname, ".yml") || str_endswith(info.fname, ".yaml")) { + return "YAML File"; + } + else if (str_endswith(info.fname, ".toml")) { + return "TOML File"; + } + else if (str_endswith(info.fname, ".sav")) { + return "Save File"; + } + else if (str_endswith(info.fname, ".emu")) { + return "Emulator File"; + } + else { + return "Unknown File"; + } +} + +static void process (menu_t *menu) { + if (menu->actions.back) { + menu->next_mode = MENU_MODE_BROWSER; + } +} + +static void draw (menu_t *menu, surface_t *d) { + char str_buffer[1024]; + + graphics_fill_screen(d, 0x00); + + graphics_draw_text(d, (d->width / 2) - 64, vertical_start_position, "FILE INFORMATION"); // centre = numchars * font_horizontal_pixels / 2 + graphics_draw_line(d, 0, 30, d->width, 30, 0xff); + + int16_t vertical_position = 40; + + graphics_draw_text(d, horizontal_start_position, vertical_position, "Name:"); + graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, info.fname); + vertical_position += (font_vertical_pixels * 2); + + graphics_draw_text(d, horizontal_start_position, vertical_position, "Size:"); + sprintf(str_buffer, "%d %s", (int)info.fsize, "Bytes"); + graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, str_buffer); + vertical_position += (font_vertical_pixels * 2); + + graphics_draw_text(d, horizontal_start_position, vertical_position, "Attributes:"); + sprintf(str_buffer, "%s%s%s%s%s\n", + ((info.fattrib & AM_DIR) ? "Directory" : "File"), + ((info.fattrib & AM_RDO) ? " | ReadOnly" : ""), + ((info.fattrib & AM_SYS) ? " | System" : ""), + ((info.fattrib & AM_ARC) ? " | Archive" : ""), + ((info.fattrib & AM_HID) ? " | Hidden" : "") + ); + + graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, str_buffer); + vertical_position += (font_vertical_pixels * 2); + + graphics_draw_text(d, horizontal_start_position, vertical_position, "Modified Timestamp:"); + sprintf(str_buffer, "%u-%02u-%02u, %02u:%02u", (info.fdate >> 9) + 1980, info.fdate >> 5 & 15, info.fdate & 31, info.ftime >> 11, info.ftime >> 5 & 63); + graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, str_buffer); + vertical_position += (font_vertical_pixels * 2); + + graphics_draw_text(d, horizontal_start_position, vertical_position, "Type:"); + graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, get_file_type()); + + //menu_fileinfo_draw_n64_rom_info(d); + + graphics_draw_line(d, 0, d->height - overscan_vertical_pixels - font_vertical_pixels, d->width,d->height - overscan_vertical_pixels - font_vertical_pixels, 0xff); + graphics_draw_text(d, (d->width / 2) - 80,d->height - overscan_vertical_pixels, "Press (B) to return!"); // centre = numchars * font_horizontal_pixels / 2 + + display_show(d); +} + + +void view_file_info_init (menu_t *menu) { + path_t *file = path_clone(menu->browser.directory); + path_push(file, menu->browser.list[menu->browser.selected].name); + if (f_stat(path_get(file), &info) != FR_OK) { + menu->next_mode = MENU_MODE_ERROR; + } + path_free(file); +} + +void view_file_info_display (menu_t *menu, surface_t *display) { + process(menu); + draw(menu, display); +} diff --git a/src/menu/views/init.c b/src/menu/views/init.c new file mode 100644 index 00000000..fcb95089 --- /dev/null +++ b/src/menu/views/init.c @@ -0,0 +1,13 @@ +#include +#include "../menu.h" + + +static void draw (menu_t *menu, surface_t *d) { + graphics_fill_screen(d, graphics_make_color(0, 0, 0, 255)); + + display_show(d); +} + +void view_init_display (menu_t *menu, surface_t *display) { + draw(menu, display); +} diff --git a/src/menu/views/load.c b/src/menu/views/load.c new file mode 100644 index 00000000..75e25583 --- /dev/null +++ b/src/menu/views/load.c @@ -0,0 +1,53 @@ +#include +#include "../menu.h" +#include "../rom_database.h" +#include "../../flashcart/flashcart.h" + + +static void draw (menu_t *menu, surface_t *d) { + int x = 24; + int y = 36; + + graphics_fill_screen(d, graphics_make_color(0, 0, 0, 255)); + + graphics_draw_text(d, x, y, "booting..."); + + display_show(d); +} + +static void load (menu_t *menu) { + menu->next_mode = MENU_MODE_BOOT; + + path_t *path = path_clone(menu->browser.directory); + + path_push(path, menu->browser.list[menu->browser.selected].name); + + rom_header_t temp_header = file_read_rom_header(path_get(path)); + + uint8_t save_type = rom_db_match_save_type(temp_header); + + if (flashcart_load_rom(path_get(path)) != FLASHCART_OK) { + menu->next_mode = MENU_MODE_ERROR; + path_free(path); + return; + } + + path_ext_replace(path, "sav"); + if (flashcart_load_save(path_get(path), (flashcart_save_type_t) (save_type), true) != FLASHCART_OK) { + menu->next_mode = MENU_MODE_ERROR; + path_free(path); + return; + } + + path_free(path); +} + + +void view_load_init (menu_t *menu) { + // Nothing to initialize (yet) +} + +void view_load_display (menu_t *menu, surface_t *display) { + draw(menu, display); + load(menu); +}