Added 30 FPS frame limiter, file list component fix, cleaned up view display/init code

This commit is contained in:
Mateusz Faderewski 2023-08-12 21:11:20 +02:00
parent 5d8ebf9200
commit 57dff16ec7
8 changed files with 115 additions and 141 deletions

View File

@ -34,7 +34,7 @@ jobs:
runCmd: | runCmd: |
make all -j make all -j
env: env:
FLAGS: -DMENU_RELEASE FLAGS: -DNDEBUG
- name: Upload artifact (Standard ROM) - name: Upload artifact (Standard ROM)
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3

@ -1 +1 @@
Subproject commit e37421e8e392e51470bb9dc6b5cd7a7419eeb10c Subproject commit e3b756ecdac6200ff8b6ed255d8f9959137fd325

View File

@ -38,12 +38,19 @@ static flashcart_t *flashcart = &((flashcart_t) {
.set_save_writeback = NULL, .set_save_writeback = NULL,
}); });
#ifdef NDEBUG
// HACK: libdragon mocks every debug function if NDEBUG flag is enabled.
// Code below reverts that and point to real function instead.
#undef debug_init_sdfs
bool debug_init_sdfs (const char *prefix, int npart);
#endif
flashcart_error_t flashcart_init (void) { flashcart_error_t flashcart_init (void) {
bool sd_initialized; bool sd_initialized;
flashcart_error_t error; flashcart_error_t error;
#ifndef MENU_RELEASE #ifndef NDEBUG
// NOTE: Some flashcarts doesn't have USB port, can't throw error here // NOTE: Some flashcarts doesn't have USB port, can't throw error here
debug_init_usblog(); debug_init_usblog();
#endif #endif
@ -116,6 +123,7 @@ flashcart_error_t flashcart_load_file (char *file_path, uint32_t start_offset_ad
if ((file_path == NULL) || (!file_exists(file_path))) { if ((file_path == NULL) || (!file_exists(file_path))) {
return FLASHCART_ERROR_ARGS; return FLASHCART_ERROR_ARGS;
} }
return flashcart->load_file(file_path, start_offset_address); return flashcart->load_file(file_path, start_offset_address);
} }

View File

@ -3,8 +3,7 @@
#include "actions.h" #include "actions.h"
#define ACTIONS_REPEAT_DELAY 16 #define ACTIONS_REPEAT_DELAY 10
#define ACTIONS_REPEAT_RATE 2
#define JOYSTICK_DEADZONE 32 #define JOYSTICK_DEADZONE 32
@ -49,7 +48,7 @@ void actions_update (menu_t *menu) {
} }
} else if (held.c[0].up || held.c[0].C_up) { } else if (held.c[0].up || held.c[0].C_up) {
menu->actions.vertical_held_counter += 1; menu->actions.vertical_held_counter += 1;
if ((menu->actions.vertical_held_counter >= ACTIONS_REPEAT_DELAY) && (menu->actions.vertical_held_counter % ACTIONS_REPEAT_RATE)) { if (menu->actions.vertical_held_counter >= ACTIONS_REPEAT_DELAY) {
menu->actions.go_up = true; menu->actions.go_up = true;
if (held.c[0].C_up) { if (held.c[0].C_up) {
menu->actions.fast = true; menu->actions.fast = true;
@ -57,7 +56,7 @@ void actions_update (menu_t *menu) {
} }
} else if (held.c[0].down || held.c[0].C_down) { } else if (held.c[0].down || held.c[0].C_down) {
menu->actions.vertical_held_counter += 1; menu->actions.vertical_held_counter += 1;
if ((menu->actions.vertical_held_counter >= ACTIONS_REPEAT_DELAY) && (menu->actions.vertical_held_counter % ACTIONS_REPEAT_RATE)) { if (menu->actions.vertical_held_counter >= ACTIONS_REPEAT_DELAY) {
menu->actions.go_down = true; menu->actions.go_down = true;
if (held.c[0].C_down) { if (held.c[0].C_down) {
menu->actions.fast = true; menu->actions.fast = true;
@ -65,7 +64,7 @@ void actions_update (menu_t *menu) {
} }
} else if (pressed.c[0].y > +JOYSTICK_DEADZONE) { // TODO: requires improvement for responsiveness } else if (pressed.c[0].y > +JOYSTICK_DEADZONE) { // TODO: requires improvement for responsiveness
menu->actions.vertical_held_counter += 1; menu->actions.vertical_held_counter += 1;
if ((menu->actions.vertical_held_counter >= ACTIONS_REPEAT_DELAY / 2) && (menu->actions.vertical_held_counter % ACTIONS_REPEAT_RATE)) { if (menu->actions.vertical_held_counter >= ACTIONS_REPEAT_DELAY / 2) {
menu->actions.go_up = true; menu->actions.go_up = true;
if (pressed.c[0].y < +75) { if (pressed.c[0].y < +75) {
menu->actions.vertical_held_counter = 0; menu->actions.vertical_held_counter = 0;
@ -73,7 +72,7 @@ void actions_update (menu_t *menu) {
} }
} else if (pressed.c[0].y < -JOYSTICK_DEADZONE) { // TODO: requires improvement for responsiveness } else if (pressed.c[0].y < -JOYSTICK_DEADZONE) { // TODO: requires improvement for responsiveness
menu->actions.vertical_held_counter += 1; menu->actions.vertical_held_counter += 1;
if ((menu->actions.vertical_held_counter >= ACTIONS_REPEAT_DELAY / 2) && (menu->actions.vertical_held_counter % ACTIONS_REPEAT_RATE)) { if (menu->actions.vertical_held_counter >= ACTIONS_REPEAT_DELAY / 2) {
menu->actions.go_down = true; menu->actions.go_down = true;
if (pressed.c[0].y > -75) { if (pressed.c[0].y > -75) {
menu->actions.vertical_held_counter = 0; menu->actions.vertical_held_counter = 0;
@ -89,12 +88,12 @@ void actions_update (menu_t *menu) {
menu->actions.horizontal_held_counter = 0; menu->actions.horizontal_held_counter = 0;
} else if (held.c[0].left) { } else if (held.c[0].left) {
menu->actions.horizontal_held_counter += 1; menu->actions.horizontal_held_counter += 1;
if ((menu->actions.horizontal_held_counter >= ACTIONS_REPEAT_DELAY) && (menu->actions.horizontal_held_counter % ACTIONS_REPEAT_RATE)) { if (menu->actions.horizontal_held_counter >= ACTIONS_REPEAT_DELAY) {
menu->actions.go_left = true; menu->actions.go_left = true;
} }
} else if (held.c[0].right) { } else if (held.c[0].right) {
menu->actions.horizontal_held_counter += 1; menu->actions.horizontal_held_counter += 1;
if ((menu->actions.horizontal_held_counter >= ACTIONS_REPEAT_DELAY) && (menu->actions.horizontal_held_counter % ACTIONS_REPEAT_RATE)) { if (menu->actions.horizontal_held_counter >= ACTIONS_REPEAT_DELAY) {
menu->actions.go_right = true; menu->actions.go_right = true;
} }
} }

View File

@ -8,15 +8,15 @@
static const char *dir_prefix = "/"; static const char *dir_prefix = "/";
static void format_file_size (char *buffer, int size) { static int format_file_size (char *buffer, int size) {
if (size < 8 * 1024) { if (size < 8 * 1024) {
sprintf(buffer, "%d B", size); return sprintf(buffer, "%d B", size);
} else if (size < 8 * 1024 * 1024) { } else if (size < 8 * 1024 * 1024) {
sprintf(buffer, "%d kB", size / 1024); return sprintf(buffer, "%d kB", size / 1024);
} else if (size < 1 * 1024 * 1024 * 1024) { } else if (size < 1 * 1024 * 1024 * 1024) {
sprintf(buffer, "%d MB", size / 1024 / 1024); return sprintf(buffer, "%d MB", size / 1024 / 1024);
} else { } else {
sprintf(buffer, "%d GB", size / 1024 / 1024 / 1024); return sprintf(buffer, "%d GB", size / 1024 / 1024 / 1024);
} }
} }
@ -40,11 +40,27 @@ void component_file_list_draw (entry_t *list, int entries, int selected) {
STL_UNKNOWN STL_UNKNOWN
); );
} else { } else {
const int list_max_characters = (256 + strlen(dir_prefix)) * FILE_LIST_ENTRIES; rdpq_paragraph_t *file_list_layout;
const int paragraph_size = sizeof(rdpq_paragraph_t) + sizeof(rdpq_paragraph_char_t) * list_max_characters; rdpq_paragraph_t *layout;
rdpq_paragraph_t *paragraph = calloc(1, paragraph_size); size_t name_lengths[FILE_LIST_ENTRIES];
paragraph->capacity = list_max_characters; size_t total_length = 1;
for (int i = 0; i < FILE_LIST_ENTRIES; i++) {
int entry_index = starting_position + i;
if (entry_index >= entries) {
name_lengths[i] = 0;
} else {
size_t length = strlen(list[entry_index].name);
name_lengths[i] = length;
total_length += length + (list[entry_index].type == ENTRY_TYPE_DIR ? strlen(dir_prefix) : 0);
}
}
file_list_layout = malloc(sizeof(rdpq_paragraph_t) + (sizeof(rdpq_paragraph_char_t) * total_length));
memset(file_list_layout, 0, sizeof(rdpq_paragraph_t));
file_list_layout->capacity = total_length;
rdpq_paragraph_builder_begin( rdpq_paragraph_builder_begin(
&(rdpq_textparms_t) { &(rdpq_textparms_t) {
@ -53,15 +69,13 @@ void component_file_list_draw (entry_t *list, int entries, int selected) {
.wrap = WRAP_ELLIPSES, .wrap = WRAP_ELLIPSES,
}, },
FNT_DEFAULT, FNT_DEFAULT,
paragraph file_list_layout
); );
for (int i = starting_position; i < entries; i++) { for (int i = 0; i < FILE_LIST_ENTRIES; i++) {
if (i == (starting_position + FILE_LIST_ENTRIES)) { int entry_index = starting_position + i;
break;
}
entry_t *entry = &list[i]; entry_t *entry = &list[entry_index];
menu_font_style_t style; menu_font_style_t style;
@ -80,14 +94,18 @@ void component_file_list_draw (entry_t *list, int entries, int selected) {
rdpq_paragraph_builder_span(dir_prefix, strlen(dir_prefix)); rdpq_paragraph_builder_span(dir_prefix, strlen(dir_prefix));
} }
rdpq_paragraph_builder_span(entry->name, strlen(entry->name)); rdpq_paragraph_builder_span(entry->name, name_lengths[i]);
if ((entry_index + 1) >= entries) {
break;
}
rdpq_paragraph_builder_newline(); rdpq_paragraph_builder_newline();
} }
rdpq_paragraph_builder_end(); layout = rdpq_paragraph_builder_end();
int highlight_height = (paragraph->bbox[3] - paragraph->bbox[1]) / paragraph->nlines; int highlight_height = (layout->bbox[3] - layout->bbox[1]) / layout->nlines;
int highlight_y = VISIBLE_AREA_Y0 + TEXT_MARGIN_VERTICAL + ((selected - starting_position) * highlight_height); int highlight_y = VISIBLE_AREA_Y0 + TEXT_MARGIN_VERTICAL + ((selected - starting_position) * highlight_height);
component_box_draw( component_box_draw(
@ -99,12 +117,12 @@ void component_file_list_draw (entry_t *list, int entries, int selected) {
); );
rdpq_paragraph_render( rdpq_paragraph_render(
paragraph, layout,
VISIBLE_AREA_X0 + TEXT_MARGIN_HORIZONTAL, VISIBLE_AREA_X0 + TEXT_MARGIN_HORIZONTAL,
VISIBLE_AREA_Y0 + TEXT_MARGIN_VERTICAL VISIBLE_AREA_Y0 + TEXT_MARGIN_VERTICAL
); );
memset(paragraph, 0, paragraph_size); rdpq_paragraph_free(layout);
rdpq_paragraph_builder_begin( rdpq_paragraph_builder_begin(
&(rdpq_textparms_t) { &(rdpq_textparms_t) {
@ -114,32 +132,33 @@ void component_file_list_draw (entry_t *list, int entries, int selected) {
.wrap = WRAP_ELLIPSES, .wrap = WRAP_ELLIPSES,
}, },
FNT_DEFAULT, FNT_DEFAULT,
paragraph NULL
); );
char file_size[16]; char file_size[8];
for (int i = starting_position; i < entries; i++) { for (int i = starting_position; i < entries; i++) {
if (i == (starting_position + FILE_LIST_ENTRIES)) {
break;
}
entry_t *entry = &list[i]; entry_t *entry = &list[i];
if (entry->type != ENTRY_TYPE_DIR) { if (entry->type != ENTRY_TYPE_DIR) {
format_file_size(file_size, entry->size); rdpq_paragraph_builder_span(file_size, format_file_size(file_size, entry->size));
rdpq_paragraph_builder_span(file_size, strlen(file_size)); }
if ((i + 1) == (starting_position + FILE_LIST_ENTRIES)) {
break;
} }
rdpq_paragraph_builder_newline(); rdpq_paragraph_builder_newline();
} }
layout = rdpq_paragraph_builder_end();
rdpq_paragraph_render( rdpq_paragraph_render(
paragraph, layout,
VISIBLE_AREA_X0 + TEXT_MARGIN_HORIZONTAL, VISIBLE_AREA_X0 + TEXT_MARGIN_HORIZONTAL,
VISIBLE_AREA_Y0 + TEXT_MARGIN_VERTICAL VISIBLE_AREA_Y0 + TEXT_MARGIN_VERTICAL
); );
rdpq_paragraph_free(paragraph); rdpq_paragraph_free(layout);
} }
} }

View File

@ -24,8 +24,17 @@
static menu_t *menu; static menu_t *menu;
static bool boot_pending; static bool boot_pending;
static tv_type_t tv_type; static tv_type_t tv_type;
static volatile int frame_counter = 0;
static void frame_counter_handler (void) {
frame_counter += 1;
}
static void frame_counter_reset (void) {
frame_counter = 0;
}
static void menu_init (boot_params_t *boot_params) { static void menu_init (boot_params_t *boot_params) {
controller_init(); controller_init();
timer_init(); timer_init();
@ -74,6 +83,8 @@ static void menu_init (boot_params_t *boot_params) {
} }
display_init(RESOLUTION_640x480, DEPTH_16_BPP, 2, GAMMA_NONE, ANTIALIAS_OFF); display_init(RESOLUTION_640x480, DEPTH_16_BPP, 2, GAMMA_NONE, ANTIALIAS_OFF);
register_VI_handler(frame_counter_handler);
} }
static void menu_deinit (menu_t *menu) { static void menu_deinit (menu_t *menu) {
@ -94,126 +105,61 @@ static void menu_deinit (menu_t *menu) {
rtc_close(); rtc_close();
timer_close(); timer_close();
unregister_VI_handler(frame_counter_handler);
display_close(); display_close();
} }
// NOTE: Keep this array in sync with menu_mode_t
static struct views_s {
void (*init) (menu_t *menu);
void (*show) (menu_t *menu, surface_t *display);
} views[__MENU_MODE_COUNT] = {
{ NULL, NULL }, // MENU_MODE_NONE
{ view_startup_init, view_startup_display }, // MENU_MODE_STARTUP
{ view_browser_init, view_browser_display }, // MENU_MODE_BROWSER
{ view_file_info_init, view_file_info_display }, // MENU_MODE_FILE_INFO
{ view_system_info_init, view_system_info_display }, // MENU_MODE_SYSTEM_INFO
{ view_image_viewer_init, view_image_viewer_display }, // MENU_MODE_IMAGE_VIEWER
{ view_music_player_init, view_music_player_display }, // MENU_MODE_MUSIC_PLAYER
{ view_credits_init, view_credits_display }, // MENU_MODE_CREDITS
{ view_load_init, view_load_display }, // MENU_MODE_LOAD
{ view_load_emulator_init, view_load_emulator_display }, // MENU_MODE_EMULATOR_LOAD
{ view_error_init, view_error_display }, // MENU_MODE_ERROR
{ view_fault_init, view_fault_display }, // MENU_MODE_FAULT
{ NULL, NULL }, // MENU_MODE_BOOT
};
void menu_run (boot_params_t *boot_params) { void menu_run (boot_params_t *boot_params) {
menu_init(boot_params); menu_init(boot_params);
int audio_buffer_length = audio_get_buffer_length(); int audio_buffer_length = audio_get_buffer_length();
while (!boot_pending && (exception_reset_time() < RESET_TIME_LENGTH)) { while (!boot_pending && (exception_reset_time() < RESET_TIME_LENGTH)) {
surface_t *display = display_try_get(); surface_t *display = (frame_counter >= 2) ? display_try_get() : NULL;
if (display != NULL) { if (display != NULL) {
frame_counter_reset();
actions_update(menu); actions_update(menu);
switch (menu->mode) { if (views[menu->mode].show) {
case MENU_MODE_STARTUP: views[menu->mode].show(menu, display);
view_startup_display(menu, display); } else {
break; rdpq_attach_clear(display, NULL);
rdpq_detach_show();
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_SYSTEM_INFO:
view_system_info_display(menu, display);
break;
case MENU_MODE_IMAGE_VIEWER:
view_image_viewer_display(menu, display);
break;
case MENU_MODE_MUSIC_PLAYER:
view_music_player_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_EMULATOR_LOAD:
view_load_emulator_display(menu, display);
break;
case MENU_MODE_ERROR:
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();
break;
} }
while (menu->mode != menu->next_mode) { while (menu->mode != menu->next_mode) {
menu->mode = menu->next_mode; menu->mode = menu->next_mode;
switch (menu->next_mode) { if (views[menu->mode].init) {
case MENU_MODE_STARTUP: views[menu->mode].init(menu);
view_startup_init(menu); }
break;
case MENU_MODE_BROWSER: if (menu->mode == MENU_MODE_BOOT) {
view_browser_init(menu); boot_pending = true;
break;
case MENU_MODE_FILE_INFO:
view_file_info_init(menu);
break;
case MENU_MODE_SYSTEM_INFO:
view_system_info_init(menu);
break;
case MENU_MODE_IMAGE_VIEWER:
view_image_viewer_init(menu);
break;
case MENU_MODE_MUSIC_PLAYER:
view_music_player_init(menu);
break;
case MENU_MODE_CREDITS:
view_credits_init(menu);
break;
case MENU_MODE_LOAD:
view_load_init(menu);
break;
case MENU_MODE_EMULATOR_LOAD:
view_load_emulator_init(menu);
break;
case MENU_MODE_ERROR:
view_error_init(menu);
break;
case MENU_MODE_FAULT:
view_fault_init(menu);
break;
case MENU_MODE_BOOT:
boot_pending = true;
break;
default:
break;
} }
} }
} }

View File

@ -32,6 +32,7 @@ typedef enum {
MENU_MODE_ERROR, MENU_MODE_ERROR,
MENU_MODE_FAULT, MENU_MODE_FAULT,
MENU_MODE_BOOT, MENU_MODE_BOOT,
__MENU_MODE_COUNT,
} menu_mode_t; } menu_mode_t;
/** @brief File entry type enumeration */ /** @brief File entry type enumeration */

View File

@ -67,6 +67,7 @@ static void draw (menu_t *menu, surface_t *d) {
component_actions_bar_text_draw( component_actions_bar_text_draw(
ALIGN_LEFT, VALIGN_TOP, ALIGN_LEFT, VALIGN_TOP,
"\n"
"B: Exit" "B: Exit"
); );