mirror of
https://github.com/Polprzewodnikowy/N64FlashcartMenu.git
synced 2024-11-25 03:56:54 +01:00
Load and fault screens added + code cleanup
This commit is contained in:
parent
d61a1a1cc7
commit
da49393d6f
3
Makefile
3
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 \
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include <libdragon.h>
|
||||
#include <usb.h>
|
||||
|
||||
#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) {
|
||||
if (flashcart->deinit) {
|
||||
return flashcart->deinit();
|
||||
}
|
||||
return FLASHCART_OK;
|
||||
}
|
||||
|
||||
flashcart_error_t flashcart_load_rom (char *rom_path, bool byte_swap) {
|
||||
|
@ -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,
|
||||
|
36
src/main.c
36
src/main.c
@ -1,48 +1,24 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include <libdragon.h>
|
||||
#include <usb.h>
|
||||
|
||||
#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
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libdragon.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
18
src/menu/assets.h
Normal file
18
src/menu/assets.h
Normal 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
|
@ -3,6 +3,8 @@
|
||||
#include <libdragon.h>
|
||||
|
||||
#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;
|
||||
|
@ -2,8 +2,7 @@
|
||||
#define MENU_STRUCT_H__
|
||||
|
||||
|
||||
#include <rdpq_font.h>
|
||||
|
||||
#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;
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -32,8 +32,10 @@ path_t *path_init (char *string) {
|
||||
}
|
||||
|
||||
void path_free (path_t *path) {
|
||||
if (path != NULL) {
|
||||
free(path->buffer);
|
||||
free(path);
|
||||
}
|
||||
}
|
||||
|
||||
path_t *path_clone (path_t *path) {
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
64
src/menu/views/fault.c
Normal file
64
src/menu/views/fault.c
Normal 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);
|
||||
}
|
@ -1,4 +1,9 @@
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <libdragon.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
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
|
||||
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();
|
||||
}
|
||||
@ -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) {
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user