Load and fault screens added + code cleanup

This commit is contained in:
Mateusz Faderewski 2023-07-11 02:22:58 +02:00
parent d61a1a1cc7
commit da49393d6f
19 changed files with 389 additions and 159 deletions

View File

@ -9,7 +9,7 @@ OUTPUT_DIR = output
include $(N64_INST)/include/n64.mk include $(N64_INST)/include/n64.mk
N64_CFLAGS += -iquote $(SOURCE_DIR) N64_CFLAGS += -iquote $(SOURCE_DIR) $(FLAGS)
N64_LDFLAGS += --wrap asset_load N64_LDFLAGS += --wrap asset_load
SRCS = \ SRCS = \
@ -31,6 +31,7 @@ SRCS = \
menu/views/browser.c \ menu/views/browser.c \
menu/views/credits.c \ menu/views/credits.c \
menu/views/error.c \ menu/views/error.c \
menu/views/fault.c \
menu/views/file_info.c \ menu/views/file_info.c \
menu/views/fragments/fragments.c \ menu/views/fragments/fragments.c \
menu/views/fragments/widgets.c \ menu/views/fragments/widgets.c \

View File

@ -1,5 +1,6 @@
#include <stddef.h> #include <stddef.h>
#include <libdragon.h>
#include <usb.h> #include <usb.h>
#include "utils/fs.h" #include "utils/fs.h"
@ -22,11 +23,38 @@ static const size_t SAVE_SIZE[__FLASHCART_SAVE_TYPE_END] = {
KiB(128), 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) { 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()) { switch (usb_getcart()) {
case CART_64DRIVE:
case CART_EVERDRIVE:
break;
case CART_SC64: case CART_SC64:
flashcart = sc64_get_flashcart(); flashcart = sc64_get_flashcart();
break; break;
@ -39,8 +67,11 @@ flashcart_error_t flashcart_init (void) {
} }
flashcart_error_t flashcart_deinit (void) { flashcart_error_t flashcart_deinit (void) {
if (flashcart->deinit) {
return flashcart->deinit(); return flashcart->deinit();
} }
return FLASHCART_OK;
}
flashcart_error_t flashcart_load_rom (char *rom_path, bool byte_swap) { flashcart_error_t flashcart_load_rom (char *rom_path, bool byte_swap) {
if ((rom_path == NULL) || (!file_exists(rom_path)) || (file_get_size(rom_path) < KiB(4))) { if ((rom_path == NULL) || (!file_exists(rom_path)) || (file_get_size(rom_path) < KiB(4))) {

View File

@ -8,6 +8,8 @@
typedef enum { typedef enum {
FLASHCART_OK, FLASHCART_OK,
FLASHCART_ERROR_NOT_DETECTED,
FLASHCART_ERROR_SD_CARD_ERROR,
FLASHCART_ERROR_UNSUPPORTED, FLASHCART_ERROR_UNSUPPORTED,
FLASHCART_ERROR_OUTDATED, FLASHCART_ERROR_OUTDATED,
FLASHCART_ERROR_ARGS, FLASHCART_ERROR_ARGS,

View File

@ -1,48 +1,24 @@
#include <stdio.h>
#include <libdragon.h> #include <libdragon.h>
#include <usb.h>
#include "boot/boot.h" #include "boot/boot.h"
#include "flashcart/flashcart.h"
#include "menu/menu.h" #include "menu/menu.h"
#include "menu/settings.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) { int main (void) {
settings_t settings; settings_t settings;
hw_init();
settings_load_default_state(&settings); settings_load_default_state(&settings);
settings_load_from_file(&settings);
menu_run(&settings); menu_run(&settings);
hw_deinit(); disable_interrupts();
boot(&settings.boot_params); boot(&settings.boot_params);
return 1; assertf(false, "Unexpected return from 'boot' function");
while (true) {
// Shouldn't get here
}
} }

View File

@ -19,7 +19,6 @@ static void actions_clear (menu_t *menu) {
menu->actions.file_info = false; menu->actions.file_info = false;
menu->actions.system_info = false; menu->actions.system_info = false;
menu->actions.settings = 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) { } else if (down.c[0].start) {
menu->actions.settings = true; menu->actions.settings = true;
} }
if (down.c[0].B || held.c[0].B) {
menu->actions.override = true;
}
} }

View File

@ -1,6 +1,10 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <libdragon.h>
#include "assets.h"
typedef struct { typedef struct {
char *name; char *name;
@ -17,7 +21,7 @@ typedef struct {
ASSET_IMPORT(FiraMono_Bold_font64); ASSET_IMPORT(FiraMono_Bold_font64);
static asset_t assets[] = { static asset_t assets_list[] = {
ASSET("assets:/font", FiraMono_Bold_font64), ASSET("assets:/font", FiraMono_Bold_font64),
}; };
@ -25,8 +29,8 @@ static asset_t assets[] = {
extern void *__real_asset_load (char *fn, int *sz); extern void *__real_asset_load (char *fn, int *sz);
void *__wrap_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++) { for (int i = 0; i < sizeof(assets_list) / sizeof(assets_list[0]); i++) {
asset_t *asset = &assets[i]; asset_t *asset = &assets_list[i];
if (strcmp(asset->name, fn) == 0) { if (strcmp(asset->name, fn) == 0) {
*sz = asset->size; *sz = asset->size;
return asset->data; return asset->data;
@ -35,3 +39,16 @@ void *__wrap_asset_load (char *fn, int *sz) {
return __real_asset_load(fn, 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;
}

18
src/menu/assets.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef ASSETS_H__
#define ASSETS_H__
#include <rdpq_font.h>
typedef struct {
rdpq_font_t *font;
int font_height;
} assets_t;
void assets_init (void);
assets_t *assets_get (void);
#endif

View File

@ -3,6 +3,8 @@
#include <libdragon.h> #include <libdragon.h>
#include "actions.h" #include "actions.h"
#include "assets.h"
#include "flashcart/flashcart.h"
#include "menu_state.h" #include "menu_state.h"
#include "menu.h" #include "menu.h"
#include "mp3player.h" #include "mp3player.h"
@ -25,6 +27,7 @@ static void menu_init (settings_t *settings) {
rspq_init(); rspq_init();
rdpq_init(); rdpq_init();
assets_init();
mp3player_mixer_init(); mp3player_mixer_init();
boot_pending = false; boot_pending = false;
@ -35,8 +38,12 @@ static void menu_init (settings_t *settings) {
menu->mode = MENU_MODE_NONE; menu->mode = MENU_MODE_NONE;
menu->next_mode = MENU_MODE_STARTUP; menu->next_mode = MENU_MODE_STARTUP;
menu->assets.font = rdpq_font_load("assets:/font"); menu->flashcart_error = flashcart_init();
menu->assets.font_height = 16; if (menu->flashcart_error != FLASHCART_OK) {
menu->next_mode = MENU_MODE_FAULT;
} else {
// settings_load_from_file(settings);
}
menu->browser.valid = false; menu->browser.valid = false;
if (file_exists(settings->last_state.directory)) { 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) { static void menu_deinit (menu_t *menu) {
flashcart_deinit();
path_free(menu->browser.directory); 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); free(menu);
rdpq_close(); rdpq_close();
@ -107,6 +114,10 @@ void menu_run (settings_t *settings) {
view_error_display(menu, display); view_error_display(menu, display);
break; break;
case MENU_MODE_FAULT:
view_fault_display(menu, display);
break;
default: default:
rdpq_attach_clear(display, NULL); rdpq_attach_clear(display, NULL);
rdpq_detach_show(); rdpq_detach_show();
@ -149,6 +160,10 @@ void menu_run (settings_t *settings) {
view_error_init(menu); view_error_init(menu);
break; break;
case MENU_MODE_FAULT:
view_fault_init(menu);
break;
case MENU_MODE_BOOT: case MENU_MODE_BOOT:
boot_pending = true; boot_pending = true;
break; break;

View File

@ -2,8 +2,7 @@
#define MENU_STRUCT_H__ #define MENU_STRUCT_H__
#include <rdpq_font.h> #include "flashcart/flashcart.h"
#include "path.h" #include "path.h"
@ -20,6 +19,7 @@ typedef enum {
MENU_MODE_CREDITS, MENU_MODE_CREDITS,
MENU_MODE_LOAD, MENU_MODE_LOAD,
MENU_MODE_ERROR, MENU_MODE_ERROR,
MENU_MODE_FAULT,
MENU_MODE_BOOT, MENU_MODE_BOOT,
} menu_mode_t; } menu_mode_t;
@ -41,10 +41,7 @@ typedef struct {
menu_mode_t mode; menu_mode_t mode;
menu_mode_t next_mode; menu_mode_t next_mode;
struct { flashcart_error_t flashcart_error;
rdpq_font_t *font;
int font_height;
} assets;
struct { struct {
bool go_up; bool go_up;
@ -60,7 +57,6 @@ typedef struct {
bool file_info; bool file_info;
bool system_info; bool system_info;
bool settings; bool settings;
bool override;
} actions; } actions;
struct { struct {
@ -71,10 +67,6 @@ typedef struct {
int selected; int selected;
bool show_hidden; bool show_hidden;
} browser; } browser;
struct {
path_t *path;
} player;
} menu_t; } menu_t;

View File

@ -112,6 +112,7 @@ static void mp3player_calculate_duration (int samples) {
void mp3player_mixer_init (void) { void mp3player_mixer_init (void) {
// NOTE: Deliberately setting max_frequency to twice of actual maximum samplerate of mp3 file. // 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. // 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); mixer_ch_set_limits(MIXER_CHANNEL, 16, 96000, 0);
} }

View File

@ -32,9 +32,11 @@ path_t *path_init (char *string) {
} }
void path_free (path_t *path) { void path_free (path_t *path) {
if (path != NULL) {
free(path->buffer); free(path->buffer);
free(path); free(path);
} }
}
path_t *path_clone (path_t *path) { path_t *path_clone (path_t *path) {
return path_init(path->buffer); return path_init(path->buffer);

View File

@ -13,7 +13,6 @@
void settings_load_from_file(settings_t *settings) { void settings_load_from_file(settings_t *settings) {
return;
FILE *fp = fopen(SC64_SETTINGS_FILEPATH, "r"); FILE *fp = fopen(SC64_SETTINGS_FILEPATH, "r");
if (!fp) { if (!fp) {
printf("Error loading config file %s\n", SC64_SETTINGS_FILEPATH); printf("Error loading config file %s\n", SC64_SETTINGS_FILEPATH);

View File

@ -229,7 +229,7 @@ static void process (menu_t *menu) {
static void draw (menu_t *menu, surface_t *d) { static void draw (menu_t *menu, surface_t *d) {
char buffer[64]; char buffer[64];
layout_t *layout = get_layout(); layout_t *layout = layout_get();
const int text_x = layout->offset_x + layout->offset_text_x; const int text_x = layout->offset_x + layout->offset_text_x;
int text_y = layout->offset_y + layout->offset_text_y; 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_borders(d);
fragment_scrollbar(d, menu->browser.selected, menu->browser.entries); 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 // Main screen
rdpq_font_begin(text_color);
for (int i = starting_position; i < menu->browser.entries; i++) { for (int i = starting_position; i < menu->browser.entries; i++) {
if (i == (starting_position + layout->main_lines)) { if (i == (starting_position + layout->main_lines)) {
break; break;
} }
entry_t *entry = &menu->browser.list[i]; 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) { switch (entry->type) {
case ENTRY_TYPE_DIR: case ENTRY_TYPE_DIR: fragment_text_set_color(directory_color); break;
rdpq_set_prim_color(directory_color); case ENTRY_TYPE_SAVE: fragment_text_set_color(save_color); break;
break; case ENTRY_TYPE_OTHER: fragment_text_set_color(other_color); break;
case ENTRY_TYPE_SAVE: case ENTRY_TYPE_MUSIC: fragment_text_set_color(music_color); break;
rdpq_set_prim_color(save_color); default: fragment_text_set_color(text_color); break;
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;
} }
rdpq_font_position(text_x, text_y + menu->assets.font_height); format_entry(buffer, entry, i == menu->browser.selected);
format_entry(buffer, entry, selected); fragment_textf(text_x, text_y, buffer);
rdpq_font_print(menu->assets.font, buffer);
if (entry->type != ENTRY_TYPE_DIR) { if (entry->type != ENTRY_TYPE_DIR) {
rdpq_font_position(text_file_size_x, text_y + menu->assets.font_height);
format_size(buffer, entry->size); 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; text_y += layout->line_height;
} }
if (menu->browser.entries == 0) { if (menu->browser.entries == 0) {
rdpq_set_prim_color(other_color); fragment_text_set_color(other_color);
rdpq_font_position(text_x, text_y + menu->assets.font_height); fragment_textf(text_x, text_y, "** empty directory **");
rdpq_font_print(menu->assets.font, "** empty directory **");
} }
// Actions bar // Actions bar
fragment_text_set_color(text_color);
text_y = layout->actions_y + layout->offset_text_y; text_y = layout->actions_y + layout->offset_text_y;
rdpq_set_prim_color(text_color);
if (menu->browser.entries > 0) { if (menu->browser.entries > 0) {
rdpq_font_position(text_x, text_y + menu->assets.font_height);
switch (menu->browser.list[menu->browser.selected].type) { switch (menu->browser.list[menu->browser.selected].type) {
case ENTRY_TYPE_DIR: case ENTRY_TYPE_DIR:
rdpq_font_print(menu->assets.font, "A: Enter"); fragment_textf(text_x, text_y, "A: Enter");
break; break;
case ENTRY_TYPE_ROM: case ENTRY_TYPE_ROM:
rdpq_font_print(menu->assets.font, "A: Load"); fragment_textf(text_x, text_y, "A: Load");
break; break;
case ENTRY_TYPE_MUSIC: case ENTRY_TYPE_MUSIC:
rdpq_font_print(menu->assets.font, "A: Play"); fragment_textf(text_x, text_y, "A: Play");
break; break;
default: default:
rdpq_font_print(menu->assets.font, "A: Info"); fragment_textf(text_x, text_y, "A: Info");
break; break;
} }
rdpq_font_position(text_other_actions_x, text_y + menu->assets.font_height); fragment_textf(text_other_actions_x, text_y, "R: Info");
rdpq_font_print(menu->assets.font, "Z: Info");
} }
text_y += layout->line_height; text_y += layout->line_height;
if (!path_is_root(menu->browser.directory)) { if (!path_is_root(menu->browser.directory)) {
rdpq_font_position(text_x, text_y + menu->assets.font_height); fragment_textf(text_x, text_y, "B: Back");
rdpq_font_print(menu->assets.font, "B: Back");
} }
rdpq_font_position(text_other_actions_x, text_y + menu->assets.font_height); fragment_textf(text_other_actions_x, text_y, "L: Settings");
rdpq_font_print(menu->assets.font, "R: Settings");
rdpq_font_end();
rdpq_detach_show(); rdpq_detach_show();
} }

64
src/menu/views/fault.c Normal file
View File

@ -0,0 +1,64 @@
#include <libdragon.h>
#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);
}

View File

@ -1,4 +1,9 @@
#include <stdarg.h>
#include <libdragon.h>
#include "fragments.h" #include "fragments.h"
#include "../../assets.h"
// TODO: Prepare layout for PAL display // TODO: Prepare layout for PAL display
@ -13,17 +18,17 @@ static layout_t layout = {
.scrollbar_width = 10, .scrollbar_width = 10,
.progressbar_height = 16, .progressbar_height = 16,
.border_thickness = 2, .border_thickness = 5,
.main_lines = 20, .main_lines = 20,
.actions_x = 20, .actions_x = 20,
.actions_y = 404, .actions_y = 405,
.actions_lines = 2, .actions_lines = 2,
}; };
layout_t *get_layout(void) { layout_t *layout_get(void) {
return &layout; return &layout;
} }
@ -58,9 +63,34 @@ void fragment_scrollbar (surface_t *d, int position, int items) {
void fragment_progressbar (surface_t *d, float progress) { void fragment_progressbar (surface_t *d, float progress) {
widget_progressbar ( widget_progressbar (
layout.offset_x, 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), d->width - (layout.offset_x * 2),
layout.progressbar_height, layout.progressbar_height,
progress 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;
}

View File

@ -32,10 +32,13 @@ typedef struct {
} layout_t; } layout_t;
layout_t *get_layout(void); layout_t *layout_get(void);
void fragment_borders (surface_t *d); void fragment_borders (surface_t *d);
void fragment_scrollbar (surface_t *d, int position, int items); void fragment_scrollbar (surface_t *d, int position, int items);
void fragment_progressbar (surface_t *d, float progress); 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 #endif

View File

@ -8,28 +8,102 @@
static bool load_pending; 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) { static void load (menu_t *menu) {
menu->next_mode = MENU_MODE_BOOT; menu->next_mode = MENU_MODE_BOOT;
path_t *path = path_clone(menu->browser.directory); path_t *path = path_clone(menu->browser.directory);
path_push(path, menu->browser.list[menu->browser.selected].name); path_push(path, menu->browser.list[menu->browser.selected].name);
rom_header_t temp_header = file_read_rom_header(path_get(path)); bool byte_swap = (rom_header.endian == ROM_MID_BIG_ENDIAN);
menu->flashcart_error = flashcart_load_rom(path_get(path), byte_swap);
uint8_t save_type = rom_db_match_save_type(temp_header); if (menu->flashcart_error != FLASHCART_OK) {
menu->next_mode = MENU_MODE_FAULT;
if (flashcart_load_rom(path_get(path), temp_header.endian == ROM_MID_BIG_ENDIAN) != FLASHCART_OK) {
menu->next_mode = MENU_MODE_ERROR;
path_free(path); path_free(path);
return; return;
} }
uint8_t save_type = rom_db_match_save_type(rom_header);
path_ext_replace(path, "sav"); path_ext_replace(path, "sav");
if (flashcart_load_save(path_get(path), (flashcart_save_type_t) (save_type), true) != FLASHCART_OK) { menu->flashcart_error = flashcart_load_save(path_get(path), convert_save_type(save_type), true);
menu->next_mode = MENU_MODE_ERROR; if (menu->flashcart_error != FLASHCART_OK) {
menu->next_mode = MENU_MODE_FAULT;
path_free(path); path_free(path);
return; return;
} }
@ -47,17 +121,48 @@ static void process (menu_t *menu) {
} }
static void draw (menu_t *menu, surface_t *d) { 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 bg_color = RGBA32(0x00, 0x00, 0x00, 0xFF);
const color_t text_color = RGBA32(0xFF, 0xFF, 0xFF, 0xFF);
rdpq_attach(d, NULL); rdpq_attach(d, NULL);
rdpq_clear(bg_color); rdpq_clear(bg_color);
if (load_pending) {
const int offset_x = 248;
const int offset_y = 212;
const int text_offset_x = -39;
// 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 // Layout
fragment_borders(d); fragment_borders(d);
// TODO: Display ROM information here // 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(); rdpq_detach_show();
} }
@ -65,6 +170,13 @@ static void draw (menu_t *menu, surface_t *d) {
void view_load_init (menu_t *menu) { void view_load_init (menu_t *menu) {
load_pending = false; 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) { void view_load_display (menu_t *menu, surface_t *display) {

View File

@ -71,7 +71,7 @@ static void process (menu_t *menu) {
static void draw (menu_t *menu, surface_t *d) { static void draw (menu_t *menu, surface_t *d) {
char buffer[64]; char buffer[64];
layout_t *layout = get_layout(); layout_t *layout = layout_get();
const int text_x = layout->offset_x + layout->offset_text_x; const int text_x = layout->offset_x + layout->offset_text_x;
int text_y = layout->offset_y + layout->offset_text_y; int text_y = layout->offset_y + layout->offset_text_y;
@ -88,54 +88,38 @@ static void draw (menu_t *menu, surface_t *d) {
// Progressbar // Progressbar
fragment_progressbar(d, mp3player_get_progress()); fragment_progressbar(d, mp3player_get_progress());
// Text start
fragment_text_start(text_color);
// Main screen // Main screen
rdpq_font_begin(text_color); text_y += fragment_textf(text_x, text_y, "Now playing:");
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);
format_name(buffer, menu->browser.list[menu->browser.selected].name); 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; 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()); 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; text_y += layout->line_height;
rdpq_font_position(text_x, text_y + menu->assets.font_height); text_y += fragment_textf(text_x, text_y, "Average bitrate:");
rdpq_font_printf(menu->assets.font, " %.0f kbps", mp3player_get_bitrate() / 1000); 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; text_y += layout->line_height;
rdpq_font_position(text_x, text_y + menu->assets.font_height); text_y += fragment_textf(text_x, text_y, "Samplerate:");
rdpq_font_printf(menu->assets.font, " %d Hz", mp3player_get_samplerate()); text_y += fragment_textf(text_x, text_y, " %d Hz", mp3player_get_samplerate());
// Actions bar // Actions bar
text_y = layout->actions_y + layout->offset_text_y; text_y = layout->actions_y + layout->offset_text_y;
rdpq_font_position(text_x, text_y + menu->assets.font_height);
if (mp3player_is_playing()) { 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()) { } else if (mp3player_is_finished()) {
rdpq_font_print(menu->assets.font, "A: Play again"); fragment_textf(text_x, text_y, "A: Play again");
} else { } else {
rdpq_font_print(menu->assets.font, "A: Play"); fragment_textf(text_x, text_y, "A: Play");
} }
text_y += layout->line_height; text_y += layout->line_height;
rdpq_font_position(text_x, text_y + menu->assets.font_height); fragment_textf(text_x, text_y, "B: Exit | Left / Right: Rewind / Fast forward");
rdpq_font_print(menu->assets.font, "B: Exit | Left / Right: Rewind / Fast forward");
rdpq_font_end();
rdpq_detach_show(); rdpq_detach_show();
} }

View File

@ -31,5 +31,8 @@ void view_load_display (menu_t *menu, surface_t *display);
void view_error_init (menu_t *menu); void view_error_init (menu_t *menu);
void view_error_display (menu_t *menu, surface_t *display); 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 #endif