diff --git a/Makefile b/Makefile index 8bd8f4f0..1237059e 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ OUTPUT_DIR = output include $(N64_INST)/include/n64.mk -N64_CFLAGS += -iquote $(SOURCE_DIR) +N64_CFLAGS += -iquote $(SOURCE_DIR) $(FLAGS) N64_LDFLAGS += --wrap asset_load SRCS = \ @@ -31,6 +31,7 @@ SRCS = \ menu/views/browser.c \ menu/views/credits.c \ menu/views/error.c \ + menu/views/fault.c \ menu/views/file_info.c \ menu/views/fragments/fragments.c \ menu/views/fragments/widgets.c \ diff --git a/src/flashcart/flashcart.c b/src/flashcart/flashcart.c index a1fc68f9..10781fd4 100644 --- a/src/flashcart/flashcart.c +++ b/src/flashcart/flashcart.c @@ -1,5 +1,6 @@ #include +#include #include #include "utils/fs.h" @@ -22,11 +23,38 @@ static const size_t SAVE_SIZE[__FLASHCART_SAVE_TYPE_END] = { KiB(128), }; -static flashcart_t *flashcart; +static flashcart_error_t dummy_init (void) { + return FLASHCART_OK; +} + +static flashcart_t *flashcart = &((flashcart_t) { + .init = dummy_init, + .deinit = NULL, + .load_rom = NULL, + .load_save = NULL, + .set_save_type = NULL, + .set_save_writeback = NULL, +}); flashcart_error_t flashcart_init (void) { + if (usb_initialize() == CART_NONE) { + return FLASHCART_ERROR_NOT_DETECTED; + } + +#ifndef NDEBUG + assertf(debug_init_usblog(), "Couldn't initialize USB debugging"); +#endif + + if (!debug_init_sdfs("sd:/", -1)) { + return FLASHCART_ERROR_SD_CARD_ERROR; + } + switch (usb_getcart()) { + case CART_64DRIVE: + case CART_EVERDRIVE: + break; + case CART_SC64: flashcart = sc64_get_flashcart(); break; @@ -39,7 +67,10 @@ flashcart_error_t flashcart_init (void) { } flashcart_error_t flashcart_deinit (void) { - return flashcart->deinit(); + if (flashcart->deinit) { + return flashcart->deinit(); + } + return FLASHCART_OK; } flashcart_error_t flashcart_load_rom (char *rom_path, bool byte_swap) { diff --git a/src/flashcart/flashcart.h b/src/flashcart/flashcart.h index 6edc3e44..8cb68804 100644 --- a/src/flashcart/flashcart.h +++ b/src/flashcart/flashcart.h @@ -8,6 +8,8 @@ typedef enum { FLASHCART_OK, + FLASHCART_ERROR_NOT_DETECTED, + FLASHCART_ERROR_SD_CARD_ERROR, FLASHCART_ERROR_UNSUPPORTED, FLASHCART_ERROR_OUTDATED, FLASHCART_ERROR_ARGS, diff --git a/src/main.c b/src/main.c index c34515fb..25312d7b 100644 --- a/src/main.c +++ b/src/main.c @@ -1,48 +1,24 @@ -#include - #include -#include #include "boot/boot.h" -#include "flashcart/flashcart.h" #include "menu/menu.h" #include "menu/settings.h" -static void hw_init (void) { - assertf(usb_initialize() != CART_NONE, "No flashcart was detected"); - - flashcart_error_t error = flashcart_init(); - assertf(error != FLASHCART_ERROR_OUTDATED, "Outdated flashcart firmware"); - assertf(error != FLASHCART_ERROR_UNSUPPORTED, "Unsupported flashcart"); - assertf(error == FLASHCART_OK, "Unknown error while initializing flashcart"); - - assertf(debug_init_sdfs("sd:/", -1), "Couldn't initialize SD card"); - -#ifdef DEBUG - debug_init_usblog(); -#endif -} - -static void hw_deinit (void) { - flashcart_deinit(); - disable_interrupts(); -} - - int main (void) { settings_t settings; - hw_init(); - settings_load_default_state(&settings); - settings_load_from_file(&settings); menu_run(&settings); - hw_deinit(); + disable_interrupts(); boot(&settings.boot_params); - return 1; + assertf(false, "Unexpected return from 'boot' function"); + + while (true) { + // Shouldn't get here + } } diff --git a/src/menu/actions.c b/src/menu/actions.c index d54ef179..27bdc2cc 100644 --- a/src/menu/actions.c +++ b/src/menu/actions.c @@ -19,7 +19,6 @@ static void actions_clear (menu_t *menu) { menu->actions.file_info = false; menu->actions.system_info = false; menu->actions.settings = false; - menu->actions.override = false; } @@ -111,8 +110,4 @@ void actions_update (menu_t *menu) { } else if (down.c[0].start) { menu->actions.settings = true; } - - if (down.c[0].B || held.c[0].B) { - menu->actions.override = true; - } } diff --git a/src/menu/assets.c b/src/menu/assets.c index 44511a95..bb053c50 100644 --- a/src/menu/assets.c +++ b/src/menu/assets.c @@ -1,6 +1,10 @@ #include #include +#include + +#include "assets.h" + typedef struct { char *name; @@ -17,7 +21,7 @@ typedef struct { ASSET_IMPORT(FiraMono_Bold_font64); -static asset_t assets[] = { +static asset_t assets_list[] = { ASSET("assets:/font", FiraMono_Bold_font64), }; @@ -25,8 +29,8 @@ static asset_t assets[] = { extern void *__real_asset_load (char *fn, int *sz); void *__wrap_asset_load (char *fn, int *sz) { - for (int i = 0; i < sizeof(assets) / sizeof(assets[0]); i++) { - asset_t *asset = &assets[i]; + for (int i = 0; i < sizeof(assets_list) / sizeof(assets_list[0]); i++) { + asset_t *asset = &assets_list[i]; if (strcmp(asset->name, fn) == 0) { *sz = asset->size; return asset->data; @@ -35,3 +39,16 @@ void *__wrap_asset_load (char *fn, int *sz) { return __real_asset_load(fn, sz); } + + +static assets_t assets; + + +void assets_init (void) { + assets.font = rdpq_font_load("assets:/font"); + assets.font_height = 16; +} + +assets_t *assets_get (void) { + return &assets; +} diff --git a/src/menu/assets.h b/src/menu/assets.h new file mode 100644 index 00000000..67ea8ad2 --- /dev/null +++ b/src/menu/assets.h @@ -0,0 +1,18 @@ +#ifndef ASSETS_H__ +#define ASSETS_H__ + + +#include + + +typedef struct { + rdpq_font_t *font; + int font_height; +} assets_t; + + +void assets_init (void); +assets_t *assets_get (void); + + +#endif diff --git a/src/menu/menu.c b/src/menu/menu.c index 3e683056..cd40ff47 100644 --- a/src/menu/menu.c +++ b/src/menu/menu.c @@ -3,6 +3,8 @@ #include #include "actions.h" +#include "assets.h" +#include "flashcart/flashcart.h" #include "menu_state.h" #include "menu.h" #include "mp3player.h" @@ -25,6 +27,7 @@ static void menu_init (settings_t *settings) { rspq_init(); rdpq_init(); + assets_init(); mp3player_mixer_init(); boot_pending = false; @@ -35,8 +38,12 @@ static void menu_init (settings_t *settings) { menu->mode = MENU_MODE_NONE; menu->next_mode = MENU_MODE_STARTUP; - menu->assets.font = rdpq_font_load("assets:/font"); - menu->assets.font_height = 16; + menu->flashcart_error = flashcart_init(); + if (menu->flashcart_error != FLASHCART_OK) { + menu->next_mode = MENU_MODE_FAULT; + } else { + // settings_load_from_file(settings); + } menu->browser.valid = false; if (file_exists(settings->last_state.directory)) { @@ -48,9 +55,9 @@ static void menu_init (settings_t *settings) { } static void menu_deinit (menu_t *menu) { + flashcart_deinit(); + path_free(menu->browser.directory); - // NOTE: font is not loaded dynamically due to hack in assets.c, so there's no need to free it - // rdpq_font_free(menu->assets.font); free(menu); rdpq_close(); @@ -107,6 +114,10 @@ void menu_run (settings_t *settings) { view_error_display(menu, display); break; + case MENU_MODE_FAULT: + view_fault_display(menu, display); + break; + default: rdpq_attach_clear(display, NULL); rdpq_detach_show(); @@ -149,6 +160,10 @@ void menu_run (settings_t *settings) { view_error_init(menu); break; + case MENU_MODE_FAULT: + view_fault_init(menu); + break; + case MENU_MODE_BOOT: boot_pending = true; break; diff --git a/src/menu/menu_state.h b/src/menu/menu_state.h index 29416d50..95223b80 100644 --- a/src/menu/menu_state.h +++ b/src/menu/menu_state.h @@ -2,8 +2,7 @@ #define MENU_STRUCT_H__ -#include - +#include "flashcart/flashcart.h" #include "path.h" @@ -20,6 +19,7 @@ typedef enum { MENU_MODE_CREDITS, MENU_MODE_LOAD, MENU_MODE_ERROR, + MENU_MODE_FAULT, MENU_MODE_BOOT, } menu_mode_t; @@ -41,10 +41,7 @@ typedef struct { menu_mode_t mode; menu_mode_t next_mode; - struct { - rdpq_font_t *font; - int font_height; - } assets; + flashcart_error_t flashcart_error; struct { bool go_up; @@ -60,7 +57,6 @@ typedef struct { bool file_info; bool system_info; bool settings; - bool override; } actions; struct { @@ -71,10 +67,6 @@ typedef struct { int selected; bool show_hidden; } browser; - - struct { - path_t *path; - } player; } menu_t; diff --git a/src/menu/mp3player.c b/src/menu/mp3player.c index e4a57880..5e6e8c7a 100644 --- a/src/menu/mp3player.c +++ b/src/menu/mp3player.c @@ -112,6 +112,7 @@ static void mp3player_calculate_duration (int samples) { void mp3player_mixer_init (void) { // NOTE: Deliberately setting max_frequency to twice of actual maximum samplerate of mp3 file. // It's tricking mixer into creating buffer long enough for appending data created by mp3dec_decode_frame. + mixer_ch_set_limits(MIXER_CHANNEL, 16, 96000, 0); } diff --git a/src/menu/path.c b/src/menu/path.c index 108f04a7..55a2aa1e 100644 --- a/src/menu/path.c +++ b/src/menu/path.c @@ -32,8 +32,10 @@ path_t *path_init (char *string) { } void path_free (path_t *path) { - free(path->buffer); - free(path); + if (path != NULL) { + free(path->buffer); + free(path); + } } path_t *path_clone (path_t *path) { diff --git a/src/menu/settings.c b/src/menu/settings.c index 51aa2065..5b251a47 100644 --- a/src/menu/settings.c +++ b/src/menu/settings.c @@ -13,7 +13,6 @@ void settings_load_from_file(settings_t *settings) { - return; FILE *fp = fopen(SC64_SETTINGS_FILEPATH, "r"); if (!fp) { printf("Error loading config file %s\n", SC64_SETTINGS_FILEPATH); diff --git a/src/menu/views/browser.c b/src/menu/views/browser.c index ee03db59..7e24ae8f 100644 --- a/src/menu/views/browser.c +++ b/src/menu/views/browser.c @@ -229,7 +229,7 @@ static void process (menu_t *menu) { static void draw (menu_t *menu, surface_t *d) { char buffer[64]; - layout_t *layout = get_layout(); + layout_t *layout = layout_get(); const int text_x = layout->offset_x + layout->offset_text_x; int text_y = layout->offset_y + layout->offset_text_y; @@ -261,94 +261,79 @@ static void draw (menu_t *menu, surface_t *d) { fragment_borders(d); fragment_scrollbar(d, menu->browser.selected, menu->browser.entries); + // Highlight + if (menu->browser.entries > 0) { + rdpq_set_mode_fill(highlight_color); + rdpq_fill_rectangle( + layout->offset_x, + text_y + highlight_offset + ((menu->browser.selected - starting_position) * layout->line_height), + d->width - layout->offset_x - layout->scrollbar_width, + text_y + layout->line_height + highlight_offset + ((menu->browser.selected - starting_position) * layout->line_height) + ); + } + + // Text start + fragment_text_start(text_color); + // Main screen - rdpq_font_begin(text_color); for (int i = starting_position; i < menu->browser.entries; i++) { if (i == (starting_position + layout->main_lines)) { break; } entry_t *entry = &menu->browser.list[i]; - bool selected = (i == menu->browser.selected); - - if (selected) { - rdpq_set_mode_fill(highlight_color); - rdpq_fill_rectangle( - layout->offset_x, - text_y + highlight_offset, - d->width - layout->offset_x - layout->scrollbar_width, - text_y + layout->line_height + highlight_offset - ); - rdpq_font_begin(text_color); - } switch (entry->type) { - case ENTRY_TYPE_DIR: - rdpq_set_prim_color(directory_color); - break; - case ENTRY_TYPE_SAVE: - rdpq_set_prim_color(save_color); - break; - case ENTRY_TYPE_OTHER: - rdpq_set_prim_color(other_color); - break; - case ENTRY_TYPE_MUSIC: - rdpq_set_prim_color(music_color); - break; - default: - rdpq_set_prim_color(text_color); - break; + case ENTRY_TYPE_DIR: fragment_text_set_color(directory_color); break; + case ENTRY_TYPE_SAVE: fragment_text_set_color(save_color); break; + case ENTRY_TYPE_OTHER: fragment_text_set_color(other_color); break; + case ENTRY_TYPE_MUSIC: fragment_text_set_color(music_color); break; + default: fragment_text_set_color(text_color); break; } - rdpq_font_position(text_x, text_y + menu->assets.font_height); - format_entry(buffer, entry, selected); - rdpq_font_print(menu->assets.font, buffer); + format_entry(buffer, entry, i == menu->browser.selected); + fragment_textf(text_x, text_y, buffer); if (entry->type != ENTRY_TYPE_DIR) { - rdpq_font_position(text_file_size_x, text_y + menu->assets.font_height); format_size(buffer, entry->size); - rdpq_font_print(menu->assets.font, buffer); + fragment_text_set_color(text_color); + fragment_textf(text_file_size_x, text_y, buffer); } text_y += layout->line_height; } + if (menu->browser.entries == 0) { - rdpq_set_prim_color(other_color); - rdpq_font_position(text_x, text_y + menu->assets.font_height); - rdpq_font_print(menu->assets.font, "** empty directory **"); + fragment_text_set_color(other_color); + fragment_textf(text_x, text_y, "** empty directory **"); } // Actions bar + fragment_text_set_color(text_color); text_y = layout->actions_y + layout->offset_text_y; - rdpq_set_prim_color(text_color); if (menu->browser.entries > 0) { - rdpq_font_position(text_x, text_y + menu->assets.font_height); switch (menu->browser.list[menu->browser.selected].type) { case ENTRY_TYPE_DIR: - rdpq_font_print(menu->assets.font, "A: Enter"); + fragment_textf(text_x, text_y, "A: Enter"); break; case ENTRY_TYPE_ROM: - rdpq_font_print(menu->assets.font, "A: Load"); + fragment_textf(text_x, text_y, "A: Load"); break; case ENTRY_TYPE_MUSIC: - rdpq_font_print(menu->assets.font, "A: Play"); + fragment_textf(text_x, text_y, "A: Play"); break; default: - rdpq_font_print(menu->assets.font, "A: Info"); + fragment_textf(text_x, text_y, "A: Info"); break; } - rdpq_font_position(text_other_actions_x, text_y + menu->assets.font_height); - rdpq_font_print(menu->assets.font, "Z: Info"); + fragment_textf(text_other_actions_x, text_y, "R: Info"); } text_y += layout->line_height; if (!path_is_root(menu->browser.directory)) { - rdpq_font_position(text_x, text_y + menu->assets.font_height); - rdpq_font_print(menu->assets.font, "B: Back"); + fragment_textf(text_x, text_y, "B: Back"); } - rdpq_font_position(text_other_actions_x, text_y + menu->assets.font_height); - rdpq_font_print(menu->assets.font, "R: Settings"); - rdpq_font_end(); + fragment_textf(text_other_actions_x, text_y, "L: Settings"); rdpq_detach_show(); } diff --git a/src/menu/views/fault.c b/src/menu/views/fault.c new file mode 100644 index 00000000..cd7a2c7b --- /dev/null +++ b/src/menu/views/fault.c @@ -0,0 +1,64 @@ +#include + +#include "flashcart/flashcart.h" +#include "fragments/fragments.h" +#include "views.h" + + +static char *format_flashcart_error (flashcart_error_t error) { + switch (error) { + case FLASHCART_OK: + return "No error"; + case FLASHCART_ERROR_NOT_DETECTED: + return "No flashcart hardware was detected"; + case FLASHCART_ERROR_SD_CARD_ERROR: + return "Error during SD card initialization"; + case FLASHCART_ERROR_UNSUPPORTED: + return "Unsupported flashcart"; + case FLASHCART_ERROR_OUTDATED: + return "Outdated flashcart firmware"; + case FLASHCART_ERROR_ARGS: + return "Invalid argument passed to flashcart function"; + case FLASHCART_ERROR_LOAD: + return "Error during loading data into flashcart"; + case FLASHCART_ERROR_INT: + return "Internal flashcart error"; + default: + return "Unknown flashcart error"; + } +} + + +static void draw (menu_t *menu, surface_t *d) { + layout_t *layout = layout_get(); + + const int text_x = layout->offset_x + layout->offset_text_x; + int text_y = layout->offset_y + layout->offset_text_y; + + const color_t bg_color = RGBA32(0x7F, 0x00, 0x00, 0xFF); + const color_t text_color = RGBA32(0xFF, 0xFF, 0xFF, 0xFF); + + rdpq_attach(d, NULL); + rdpq_clear(bg_color); + + fragment_text_start(text_color); + text_y += fragment_textf(text_x, text_y, "Unrecoverable error:"); + text_y += fragment_textf(text_x, text_y, " %s", format_flashcart_error(menu->flashcart_error)); + if (menu->flashcart_error == FLASHCART_ERROR_OUTDATED) { + text_y += fragment_textf(text_x, text_y, " Minimum supported versions:"); + text_y += fragment_textf(text_x, text_y, " EverDrive-64: ?"); + text_y += fragment_textf(text_x, text_y, " 64drive: ?"); + text_y += fragment_textf(text_x, text_y, " SC64: 2.16.0"); + } + + rdpq_detach_show(); +} + + +void view_fault_init (menu_t *menu) { + // Nothing to initialize (yet) +} + +void view_fault_display (menu_t *menu, surface_t *display) { + draw(menu, display); +} diff --git a/src/menu/views/fragments/fragments.c b/src/menu/views/fragments/fragments.c index cef29829..e682b8fb 100644 --- a/src/menu/views/fragments/fragments.c +++ b/src/menu/views/fragments/fragments.c @@ -1,4 +1,9 @@ +#include + +#include + #include "fragments.h" +#include "../../assets.h" // TODO: Prepare layout for PAL display @@ -13,17 +18,17 @@ static layout_t layout = { .scrollbar_width = 10, .progressbar_height = 16, - .border_thickness = 2, + .border_thickness = 5, .main_lines = 20, .actions_x = 20, - .actions_y = 404, + .actions_y = 405, .actions_lines = 2, }; -layout_t *get_layout(void) { +layout_t *layout_get(void) { return &layout; } @@ -58,9 +63,34 @@ void fragment_scrollbar (surface_t *d, int position, int items) { void fragment_progressbar (surface_t *d, float progress) { widget_progressbar ( layout.offset_x, - layout.actions_y - layout.border_thickness - layout.progressbar_height, + layout.offset_y + ((layout.main_lines + 1) * layout.line_height) - layout.progressbar_height, d->width - (layout.offset_x * 2), layout.progressbar_height, progress ); } + +void fragment_text_start (color_t color) { + rdpq_font_begin(color); +} + +void fragment_text_set_color (color_t color) { + rdpq_set_prim_color(color); +} + +int fragment_textf (int x, int y, char *fmt, ...) { + char buffer[64]; + + assets_t *assets = assets_get(); + + rdpq_font_position(x, y + assets->font_height); + + va_list va; + va_start(va, fmt); + int n = vsnprintf(buffer, sizeof(buffer), fmt, va); + va_end(va); + + rdpq_font_printn(assets->font, buffer, n); + + return layout.line_height; +} diff --git a/src/menu/views/fragments/fragments.h b/src/menu/views/fragments/fragments.h index e87658a3..1fe444dc 100644 --- a/src/menu/views/fragments/fragments.h +++ b/src/menu/views/fragments/fragments.h @@ -32,10 +32,13 @@ typedef struct { } layout_t; -layout_t *get_layout(void); +layout_t *layout_get(void); void fragment_borders (surface_t *d); void fragment_scrollbar (surface_t *d, int position, int items); void fragment_progressbar (surface_t *d, float progress); +void fragment_text_start (color_t color); +void fragment_text_set_color (color_t color); +int fragment_textf (int x, int y, char *fmt, ...); #endif diff --git a/src/menu/views/load.c b/src/menu/views/load.c index b3156337..87dd23cf 100644 --- a/src/menu/views/load.c +++ b/src/menu/views/load.c @@ -8,28 +8,102 @@ static bool load_pending; +static rom_header_t rom_header; + + +static char *format_rom_endian (uint32_t endian) { + switch (endian) { + case ROM_BIG_ENDIAN: + return "Big (native)"; + case ROM_LITTLE_ENDIAN: + return "Little (unsupported)"; + case ROM_MID_BIG_ENDIAN: + return "Byte swapped"; + default: + return "Unknown"; + } +} + +static char *format_rom_media_type (uint8_t media_type) { + switch (media_type) { + case N64_CART: + return "N - Cartridge"; + case N64_DISK: + return "D - Disk"; + case N64_CART_EXPANDABLE: + return "C - Cart Expandable"; + case N64_DISK_EXPANDABLE: + return "E - Disk Expandable"; + case N64_ALECK64: + return "Z - Aleck64"; + default: + return "Unknown"; + } +} + +static char *format_rom_save_type (uint8_t save_type) { + switch (save_type) { + case DB_SAVE_TYPE_NONE: + return "None"; + case DB_SAVE_TYPE_EEPROM_4K: + return "EEPROM 4K"; + case DB_SAVE_TYPE_EEPROM_16K: + return "EEPROM 16K"; + case DB_SAVE_TYPE_SRAM: + return "SRAM"; + case DB_SAVE_TYPE_SRAM_BANKED: + return "SRAM Banked"; + case DB_SAVE_TYPE_SRAM_128K: + return "SRAM 128K"; + case DB_SAVE_TYPE_FLASHRAM: + return "FlashRAM"; + case DB_SAVE_TYPE_CPAK: + return "Controller PAK"; + default: + return "Unknown"; + } +} + +static flashcart_save_type_t convert_save_type (uint8_t save_type) { + switch (save_type) { + case DB_SAVE_TYPE_EEPROM_4K: + return FLASHCART_SAVE_TYPE_EEPROM_4K; + case DB_SAVE_TYPE_EEPROM_16K: + return FLASHCART_SAVE_TYPE_EEPROM_16K; + case DB_SAVE_TYPE_SRAM: + return FLASHCART_SAVE_TYPE_SRAM; + case DB_SAVE_TYPE_SRAM_BANKED: + return FLASHCART_SAVE_TYPE_SRAM_BANKED; + case DB_SAVE_TYPE_SRAM_128K: + return FLASHCART_SAVE_TYPE_SRAM_128K; + case DB_SAVE_TYPE_FLASHRAM: + return FLASHCART_SAVE_TYPE_FLASHRAM; + default: + return FLASHCART_SAVE_TYPE_NONE; + } +} 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), temp_header.endian == ROM_MID_BIG_ENDIAN) != FLASHCART_OK) { - menu->next_mode = MENU_MODE_ERROR; + bool byte_swap = (rom_header.endian == ROM_MID_BIG_ENDIAN); + menu->flashcart_error = flashcart_load_rom(path_get(path), byte_swap); + if (menu->flashcart_error != FLASHCART_OK) { + menu->next_mode = MENU_MODE_FAULT; path_free(path); return; } + uint8_t save_type = rom_db_match_save_type(rom_header); + 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; + menu->flashcart_error = flashcart_load_save(path_get(path), convert_save_type(save_type), true); + if (menu->flashcart_error != FLASHCART_OK) { + menu->next_mode = MENU_MODE_FAULT; path_free(path); return; } @@ -47,17 +121,48 @@ static void process (menu_t *menu) { } static void draw (menu_t *menu, surface_t *d) { - // layout_t *layout = get_layout(); + layout_t *layout = layout_get(); + + const int text_x = layout->offset_x + layout->offset_text_x; + int text_y = layout->offset_y + layout->offset_text_y; const color_t bg_color = RGBA32(0x00, 0x00, 0x00, 0xFF); + const color_t text_color = RGBA32(0xFF, 0xFF, 0xFF, 0xFF); rdpq_attach(d, NULL); rdpq_clear(bg_color); - // Layout - fragment_borders(d); + if (load_pending) { + const int offset_x = 248; + const int offset_y = 212; + const int text_offset_x = -39; - // TODO: Display ROM information here + // Loading screen + widget_border(offset_x, offset_y, d->width - offset_x, d->height - offset_y, layout->border_thickness); + fragment_text_start(text_color); + fragment_textf((d->width / 2) + text_offset_x, (d->height / 2) - (layout->line_height / 2), "Loading…"); + } else { + // Layout + fragment_borders(d); + + // Text start + fragment_text_start(text_color); + + // Main screen + text_y += fragment_textf(text_x, text_y, "Title: %.20s", rom_header.title); + text_y += fragment_textf(text_x, text_y, "Save type: %s", format_rom_save_type(rom_db_match_save_type(rom_header))); + text_y += fragment_textf(text_x, text_y, "Media type: %s", format_rom_media_type(rom_header.metadata.media_type)); + text_y += fragment_textf(text_x, text_y, "Unique ID: %.2s", (char*)&(rom_header.metadata.unique_identifier)); + text_y += fragment_textf(text_x, text_y, "Destination market: %c", rom_header.metadata.destination_market); + text_y += fragment_textf(text_x, text_y, "Version: %hhu", rom_header.version); + text_y += fragment_textf(text_x, text_y, "Checksum: 0x%016llX", rom_header.checksum); + text_y += fragment_textf(text_x, text_y, "ROM endian: %s", format_rom_endian(rom_header.endian)); + + // Actions bar + text_y = layout->actions_y + layout->offset_text_y; + text_y += fragment_textf(text_x, text_y, "A: Load and run ROM"); + text_y += fragment_textf(text_x, text_y, "B: Exit"); + } rdpq_detach_show(); } @@ -65,6 +170,13 @@ static void draw (menu_t *menu, surface_t *d) { void view_load_init (menu_t *menu) { load_pending = false; + + path_t *path = path_clone(menu->browser.directory); + path_push(path, menu->browser.list[menu->browser.selected].name); + + rom_header = file_read_rom_header(path_get(path)); + + path_free(path); } void view_load_display (menu_t *menu, surface_t *display) { diff --git a/src/menu/views/player.c b/src/menu/views/player.c index ddc7a22c..5f3f7c20 100644 --- a/src/menu/views/player.c +++ b/src/menu/views/player.c @@ -71,7 +71,7 @@ static void process (menu_t *menu) { static void draw (menu_t *menu, surface_t *d) { char buffer[64]; - layout_t *layout = get_layout(); + layout_t *layout = layout_get(); const int text_x = layout->offset_x + layout->offset_text_x; int text_y = layout->offset_y + layout->offset_text_y; @@ -88,54 +88,38 @@ static void draw (menu_t *menu, surface_t *d) { // Progressbar fragment_progressbar(d, mp3player_get_progress()); + // Text start + fragment_text_start(text_color); + // Main screen - rdpq_font_begin(text_color); - rdpq_font_position(text_x, text_y + menu->assets.font_height); - rdpq_font_print(menu->assets.font, "Now playing:"); - text_y += layout->line_height; - rdpq_font_position(text_x, text_y + menu->assets.font_height); + text_y += fragment_textf(text_x, text_y, "Now playing:"); format_name(buffer, menu->browser.list[menu->browser.selected].name); - rdpq_font_print(menu->assets.font, buffer); + text_y += fragment_textf(text_x, text_y, buffer); - text_y += layout->line_height * 2; - rdpq_font_begin(text_color); - rdpq_font_position(text_x, text_y + menu->assets.font_height); - rdpq_font_print(menu->assets.font, "Track elapsed / length:"); text_y += layout->line_height; - rdpq_font_position(text_x, text_y + menu->assets.font_height); + text_y += fragment_textf(text_x, text_y, "Track elapsed / length:"); format_elapsed_duration(buffer, mp3player_get_duration() * mp3player_get_progress(), mp3player_get_duration()); - rdpq_font_print(menu->assets.font, buffer); + text_y += fragment_textf(text_x, text_y, buffer); - text_y += layout->line_height * 2; - rdpq_font_begin(text_color); - rdpq_font_position(text_x, text_y + menu->assets.font_height); - rdpq_font_print(menu->assets.font, "Average bitrate:"); text_y += layout->line_height; - rdpq_font_position(text_x, text_y + menu->assets.font_height); - rdpq_font_printf(menu->assets.font, " %.0f kbps", mp3player_get_bitrate() / 1000); + text_y += fragment_textf(text_x, text_y, "Average bitrate:"); + text_y += fragment_textf(text_x, text_y, " %.0f kbps", mp3player_get_bitrate() / 1000); - text_y += layout->line_height * 2; - rdpq_font_begin(text_color); - rdpq_font_position(text_x, text_y + menu->assets.font_height); - rdpq_font_print(menu->assets.font, "Samplerate:"); text_y += layout->line_height; - rdpq_font_position(text_x, text_y + menu->assets.font_height); - rdpq_font_printf(menu->assets.font, " %d Hz", mp3player_get_samplerate()); + text_y += fragment_textf(text_x, text_y, "Samplerate:"); + text_y += fragment_textf(text_x, text_y, " %d Hz", mp3player_get_samplerate()); // Actions bar text_y = layout->actions_y + layout->offset_text_y; - rdpq_font_position(text_x, text_y + menu->assets.font_height); if (mp3player_is_playing()) { - rdpq_font_print(menu->assets.font, "A: Pause"); + fragment_textf(text_x, text_y, "A: Pause"); } else if (mp3player_is_finished()) { - rdpq_font_print(menu->assets.font, "A: Play again"); + fragment_textf(text_x, text_y, "A: Play again"); } else { - rdpq_font_print(menu->assets.font, "A: Play"); + fragment_textf(text_x, text_y, "A: Play"); } text_y += layout->line_height; - rdpq_font_position(text_x, text_y + menu->assets.font_height); - rdpq_font_print(menu->assets.font, "B: Exit | Left / Right: Rewind / Fast forward"); - rdpq_font_end(); + fragment_textf(text_x, text_y, "B: Exit | Left / Right: Rewind / Fast forward"); rdpq_detach_show(); } diff --git a/src/menu/views/views.h b/src/menu/views/views.h index b40a0a17..84e01317 100644 --- a/src/menu/views/views.h +++ b/src/menu/views/views.h @@ -31,5 +31,8 @@ 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); +void view_fault_init (menu_t *menu); +void view_fault_display (menu_t *menu, surface_t *display); + #endif