mirror of
https://github.com/Polprzewodnikowy/N64FlashcartMenu.git
synced 2024-11-22 02:29:19 +01:00
Added background image and ability to set it from the image viewer
This commit is contained in:
parent
213ef7f367
commit
01ae2cef37
1
Makefile
1
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 \
|
||||
|
202
src/menu/components/background.c
Normal file
202
src/menu/components/background.c
Normal file
@ -0,0 +1,202 @@
|
||||
#include <fatfs/ff.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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);
|
||||
}
|
32
src/menu/components/components.h
Normal file
32
src/menu/components/components.h
Normal file
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @file components.h
|
||||
* @brief Menu Components
|
||||
* @ingroup menu
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_H__
|
||||
#define COMPONENTS_H__
|
||||
|
||||
|
||||
#include <libdragon.h>
|
||||
|
||||
|
||||
/**
|
||||
* @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
|
@ -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;
|
||||
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <fatfs/ff.h>
|
||||
#include <libdragon.h>
|
||||
|
||||
#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);
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <libdragon.h>
|
||||
|
||||
#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);
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <libdragon.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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);
|
||||
|
@ -1,27 +1,38 @@
|
||||
#include <libdragon.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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) {
|
||||
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);
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <libdragon.h>
|
||||
|
||||
#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);
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <libdragon.h>
|
||||
|
||||
#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);
|
||||
|
@ -1,8 +1,15 @@
|
||||
#include <libdragon.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <time.h>
|
||||
#include <libdragon.h>
|
||||
|
||||
#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);
|
||||
|
Loading…
Reference in New Issue
Block a user