From 01ae2cef37d83cc609940dceec0daa9c76ca925d Mon Sep 17 00:00:00 2001 From: Mateusz Faderewski Date: Fri, 28 Jul 2023 21:36:51 +0200 Subject: [PATCH] Added background image and ability to set it from the image viewer --- Makefile | 1 + src/menu/components/background.c | 202 +++++++++++++++++++++++++++++++ src/menu/components/components.h | 32 +++++ src/menu/menu_state.h | 5 + src/menu/views/browser.c | 6 +- src/menu/views/credits.c | 6 +- src/menu/views/file_info.c | 6 +- src/menu/views/image_viewer.c | 24 +++- src/menu/views/load.c | 6 +- src/menu/views/music_player.c | 6 +- src/menu/views/startup.c | 16 ++- src/menu/views/system_info.c | 6 +- 12 files changed, 299 insertions(+), 17 deletions(-) create mode 100644 src/menu/components/background.c create mode 100644 src/menu/components/components.h diff --git a/Makefile b/Makefile index 890078eb..28fc2fa7 100644 --- a/Makefile +++ b/Makefile @@ -29,6 +29,7 @@ SRCS = \ libs/miniz/miniz.c \ menu/actions.c \ menu/assets.c \ + menu/components/background.c \ menu/menu.c \ menu/mp3_player.c \ menu/path.c \ diff --git a/src/menu/components/background.c b/src/menu/components/background.c new file mode 100644 index 00000000..9e82e97b --- /dev/null +++ b/src/menu/components/background.c @@ -0,0 +1,202 @@ +#include +#include + +#include "components.h" +#include "utils/fs.h" + + +#define CACHE_METADATA_MAGIC (0x424B4731) + + +typedef struct { + uint32_t magic; + uint32_t width; + uint32_t height; + uint32_t size; +} cache_metadata_t; + + +static void load_from_cache (component_background_t *c) { + if (!c->cache_location) { + return; + } + + FIL fil; + UINT bytes_read; + + if (f_open(&fil, strip_sd_prefix(c->cache_location), FA_READ) != FR_OK) { + return; + } + + cache_metadata_t cache_metadata; + + if ((f_read(&fil, &cache_metadata, sizeof(cache_metadata), &bytes_read) != FR_OK) || (bytes_read != sizeof(cache_metadata))) { + f_close(&fil); + return; + } + + uint32_t display_width = display_get_width(); + uint32_t display_height = display_get_height(); + + if (cache_metadata.magic != CACHE_METADATA_MAGIC || cache_metadata.width > display_width || cache_metadata.height > display_height) { + f_close(&fil); + return; + } + + c->image = calloc(1, sizeof(surface_t)); + *c->image = surface_alloc(FMT_RGBA16, cache_metadata.width, cache_metadata.height); + + if (cache_metadata.size != (c->image->height * c->image->stride)) { + surface_free(c->image); + free(c->image); + c->image = NULL; + f_close(&fil); + return; + } + + if ((f_read(&fil, c->image->buffer, cache_metadata.size, &bytes_read) != FR_OK) || (bytes_read != cache_metadata.size)) { + surface_free(c->image); + free(c->image); + c->image = NULL; + } + + f_close(&fil); +} + +static void save_to_cache (component_background_t *c) { + if (!c->cache_location || !c->image) { + return; + } + + FIL fil; + UINT bytes_written; + if (f_open(&fil, strip_sd_prefix(c->cache_location), FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) { + return; + } + + cache_metadata_t cache_metadata = { + .magic = CACHE_METADATA_MAGIC, + .width = c->image->width, + .height = c->image->height, + .size = (c->image->height * c->image->stride), + }; + + f_write(&fil, &cache_metadata, sizeof(cache_metadata), &bytes_written); + f_write(&fil, c->image->buffer, cache_metadata.size, &bytes_written); + + f_close(&fil); +} + +static void prepare_background (component_background_t *c) { + if (!c->image || c->image->width == 0 || c->image->height == 0) { + return; + } + + uint32_t display_width = display_get_width(); + uint32_t display_height = display_get_height(); + + int16_t display_center_x = (display_width / 2); + int16_t display_center_y = (display_height / 2); + + int16_t image_center_x = (c->image->width / 2); + int16_t image_center_y = (c->image->height / 2); + + // Darken the image + rdpq_attach(c->image, NULL); + rdpq_mode_push(); + rdpq_set_mode_standard(); + rdpq_set_prim_color(RGBA32(0x00, 0x00, 0x00, 0xA0)); + rdpq_mode_combiner(RDPQ_COMBINER_FLAT); + rdpq_mode_blender(RDPQ_BLENDER_MULTIPLY); + rdpq_fill_rectangle(0, 0, c->image->width, c->image->height); + rdpq_mode_pop(); + rdpq_detach(); + + // Prepare display list + rspq_block_begin(); + rdpq_mode_push(); + if ((c->image->width != display_width) || (c->image->height != display_height)) { + rdpq_set_mode_fill(RGBA32(0x00, 0x00, 0x00, 0xFF)); + } + if (c->image->width != display_width) { + rdpq_fill_rectangle( + 0, + display_center_y - image_center_y, + display_center_x - image_center_x, + display_center_y + image_center_y + ); + rdpq_fill_rectangle( + display_center_x + image_center_x - (c->image->width % 2), + display_center_y - image_center_y, + display_width, + display_center_y + image_center_y + ); + } + if (c->image->height != display_height) { + rdpq_fill_rectangle( + 0, + 0, + display_width, + display_center_y - image_center_y + ); + rdpq_fill_rectangle( + 0, + display_center_y + image_center_y - (c->image->height % 2), + display_width, + display_height + ); + } + rdpq_set_mode_copy(false); + rdpq_tex_blit(c->image, display_center_x - image_center_x, display_center_y - image_center_y, NULL); + rdpq_mode_pop(); + c->image_display_list = rspq_block_end(); +} + +static void display_list_free (void *arg) { + rspq_block_free((rspq_block_t *) (arg)); +} + + +component_background_t *component_background_create (char *cache_location) { + component_background_t *c = calloc(1, sizeof(component_background_t)); + + c->cache_location = cache_location; + + load_from_cache(c); + + prepare_background(c); + + return c; +} + +void component_background_replace_image (component_background_t *c, surface_t *image) { + if (!c) { + return; + } + + if (c->image) { + surface_free(c->image); + free(c->image); + c->image = NULL; + } + + if (c->image_display_list) { + rdpq_call_deferred(display_list_free, c->image_display_list); + c->image_display_list = NULL; + } + + c->image = image; + + save_to_cache(c); + + prepare_background(c); +} + +void component_background_draw (component_background_t *c) { + if (!c || !c->image_display_list) { + rdpq_clear(RGBA32(0x00, 0x00, 0x00, 0xFF)); + return; + } + + rspq_block_run(c->image_display_list); +} diff --git a/src/menu/components/components.h b/src/menu/components/components.h new file mode 100644 index 00000000..f8618827 --- /dev/null +++ b/src/menu/components/components.h @@ -0,0 +1,32 @@ +/** + * @file components.h + * @brief Menu Components + * @ingroup menu + */ + +#ifndef COMPONENTS_H__ +#define COMPONENTS_H__ + + +#include + + +/** + * @addtogroup + * @{ menu_components + */ + +typedef struct { + char *cache_location; + surface_t *image; + rspq_block_t *image_display_list; +} component_background_t; + +component_background_t *component_background_create (char *cache_location); +void component_background_replace_image (component_background_t *c, surface_t *image); +void component_background_draw (component_background_t *c); + +/** @} */ /* menu_components */ + + +#endif diff --git a/src/menu/menu_state.h b/src/menu/menu_state.h index 4592540a..2b48baa5 100644 --- a/src/menu/menu_state.h +++ b/src/menu/menu_state.h @@ -9,6 +9,7 @@ #include "boot/boot.h" +#include "components/components.h" #include "flashcart/flashcart.h" #include "path.h" #include "settings.h" @@ -82,6 +83,10 @@ typedef struct { int entries; int selected; } browser; + + struct { + component_background_t *background; + } components; } menu_t; diff --git a/src/menu/views/browser.c b/src/menu/views/browser.c index 960da592..e6ac5110 100644 --- a/src/menu/views/browser.c +++ b/src/menu/views/browser.c @@ -4,6 +4,7 @@ #include #include +#include "../components/components.h" #include "fragments/fragments.h" #include "utils/fs.h" #include "views.h" @@ -252,7 +253,6 @@ static void draw (menu_t *menu, surface_t *d) { const int text_other_actions_x = text_x + 450; const int highlight_offset = 2; - const color_t bg_color = RGBA32(0x00, 0x00, 0x00, 0xFF); const color_t highlight_color = RGBA32(0x3F, 0x3F, 0x3F, 0xFF); const color_t text_color = RGBA32(0xFF, 0xFF, 0xFF, 0xFF); const color_t directory_color = RGBA32(0xFF, 0xFF, 0x70, 0xFF); @@ -270,7 +270,9 @@ static void draw (menu_t *menu, surface_t *d) { } rdpq_attach(d, NULL); - rdpq_clear(bg_color); + + // Background + component_background_draw(menu->components.background); // Layout fragment_borders(d); diff --git a/src/menu/views/credits.c b/src/menu/views/credits.c index ac5eb26e..e91df1a5 100644 --- a/src/menu/views/credits.c +++ b/src/menu/views/credits.c @@ -1,5 +1,6 @@ #include +#include "../components/components.h" #include "fragments/fragments.h" #include "views.h" @@ -21,11 +22,12 @@ static void draw (menu_t *menu, surface_t *d) { 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); + + // Background + component_background_draw(menu->components.background); // Layout fragment_borders(d); diff --git a/src/menu/views/file_info.c b/src/menu/views/file_info.c index 3f7e44d3..e9a8f4aa 100644 --- a/src/menu/views/file_info.c +++ b/src/menu/views/file_info.c @@ -2,6 +2,7 @@ #include #include +#include "../components/components.h" #include "../png_decoder.h" #include "../rom_database.h" #include "fragments/fragments.h" @@ -282,11 +283,12 @@ static void draw (menu_t *menu, surface_t *d) { 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); + + // Background + component_background_draw(menu->components.background); // Layout fragment_borders(d); diff --git a/src/menu/views/image_viewer.c b/src/menu/views/image_viewer.c index c5de324b..932ee563 100644 --- a/src/menu/views/image_viewer.c +++ b/src/menu/views/image_viewer.c @@ -1,27 +1,38 @@ #include #include +#include "../components/components.h" #include "../png_decoder.h" #include "fragments/fragments.h" #include "views.h" static bool image_loading; +static bool image_set_as_background; static surface_t *image; static void process (menu_t *menu) { if (menu->actions.back) { menu->next_mode = MENU_MODE_BROWSER; + } else if (menu->actions.enter) { + if (image) { + menu->next_mode = MENU_MODE_BROWSER; + image_set_as_background = true; + } } } static void draw (menu_t *menu, surface_t *d) { - rdpq_attach_clear(d, NULL); - if (!image) { + rdpq_attach(d, NULL); + + component_background_draw(menu->components.background); + fragment_loader(d); } else { + rdpq_attach_clear(d, NULL); + uint16_t x = (d->width / 2) - (image->width / 2); uint16_t y = (d->height / 2) - (image->height / 2); @@ -48,14 +59,19 @@ static void deinit (menu_t *menu) { } if (image) { - surface_free(image); - free(image); + if (image_set_as_background) { + component_background_replace_image(menu->components.background, image); + } else { + surface_free(image); + free(image); + } } } void view_image_viewer_init (menu_t *menu) { image_loading = false; + image_set_as_background = false; image = NULL; path_t *path = path_clone(menu->browser.directory); diff --git a/src/menu/views/load.c b/src/menu/views/load.c index d5de8171..f4028ea8 100644 --- a/src/menu/views/load.c +++ b/src/menu/views/load.c @@ -1,5 +1,6 @@ #include +#include "../components/components.h" #include "../rom_database.h" #include "boot/boot.h" #include "flashcart/flashcart.h" @@ -200,11 +201,12 @@ static void draw (menu_t *menu, surface_t *d) { 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); + + // Background + component_background_draw(menu->components.background); if (load_pending) { fragment_loader(d); diff --git a/src/menu/views/music_player.c b/src/menu/views/music_player.c index 096ddfc6..114731a4 100644 --- a/src/menu/views/music_player.c +++ b/src/menu/views/music_player.c @@ -1,5 +1,6 @@ #include +#include "../components/components.h" #include "../mp3_player.h" #include "fragments/fragments.h" #include "views.h" @@ -75,11 +76,12 @@ static void draw (menu_t *menu, surface_t *d) { 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); + + // Background + component_background_draw(menu->components.background); // Layout fragment_borders(d); diff --git a/src/menu/views/startup.c b/src/menu/views/startup.c index e511cfab..0cddc40b 100644 --- a/src/menu/views/startup.c +++ b/src/menu/views/startup.c @@ -1,8 +1,15 @@ #include +#include "../components/components.h" +#include "utils/fs.h" #include "views.h" +#define CACHE_DIRECTORY "sd:/menu/cache" + +#define BACKGROUND_CACHE "sd:/menu/cache/background.data" + + static void process (menu_t *menu) { menu->next_mode = MENU_MODE_BROWSER; } @@ -12,12 +19,19 @@ static void draw (menu_t *menu, surface_t *d) { rdpq_detach_show(); } +static void load (menu_t *menu) { + menu->components.background = component_background_create(BACKGROUND_CACHE); +} + void view_startup_init (menu_t *menu) { - // Nothing to initialize (yet) + directory_create(CACHE_DIRECTORY); } void view_startup_display (menu_t *menu, surface_t *display) { process(menu); + draw(menu, display); + + load(menu); } diff --git a/src/menu/views/system_info.c b/src/menu/views/system_info.c index 536160c7..4bbcae91 100644 --- a/src/menu/views/system_info.c +++ b/src/menu/views/system_info.c @@ -1,6 +1,7 @@ #include #include +#include "../components/components.h" #include "fragments/fragments.h" #include "views.h" @@ -35,11 +36,12 @@ static void draw (menu_t *menu, surface_t *d) { 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); + + // Background + component_background_draw(menu->components.background); // Layout fragment_borders(d);