diff --git a/README.md b/README.md index 703804cc..26af0067 100644 --- a/README.md +++ b/README.md @@ -49,22 +49,44 @@ An open source menu for N64 flashcarts. ## Experimental features These features are subject to change: -### ROM Boxart -To use boxart, place PNG files in the `/menu/boxart` folder on the SD card with the following dimensions: -* Standard covers: 158x112 -* 64DD covers: 129x112 -* Japanese covers: 112x158 - -Each file must be named according to the 2 letter ROM ID, or 3 letter ROM ID including media type. -i.e. for GoldenEye 2 letters, this would be `GE.png`. -i.e. for GoldenEye 3 letters, this would be `NGE.png`. -You can download these boxart packs: -[American Boxart](https://mega.nz/file/6cNGwSqI#8X5ukb65n3YMlGaUtSOGXkKo9HxVnnMOgqn94Epcr7w) +### GamePak sprites +To use N64 `GamePak` sprites, place `PNG` files within the `sd:/menu/boxart/` folder. -[European Boxart](https://mega.nz/file/O7AjDbRJ#VnVU10dq8HQvBUQptppI6PAcQMb8-Zembqav8WtAQ_M) -[64DD Boxart](https://mega.nz/file/O3JzwD7B#BYl1aV-pbrJ-MxWUbM_K0yGVIRbmSoxJJZqQInRzZyM) +#### Supported sprites +These must be `PNG` files that use the following dimensions: +* Standard N64 GamePak boxart sprites: 158x112 +* Japanese N64 GamePak boxart sprites: 112x158 +* 64DD boxart sprites: 129x112 + +They will be loaded by directories using each character of the full 4 character Game Code (as identified in the menus ROM information). +i.e. for GoldenEye NTSC USA (NGEE), this would be `sd:/menu/boxart/N/G/E/E/boxart_front.png`. +i.e. for GoldenEye PAL (NGEP), this would be `sd:/menu/boxart/N/G/E/P/boxart_front.png`. + +To improve compatibility between regions (as a fallback), you may exclude the region ID (last matched directory) for GamePaks to match with 3 letter IDs instead: +i.e. for GoldenEye, this would be `sd:/menu/boxart/N/G/E/boxart_front.png`. + +**Note1:** Excluding the region ID may show the wrong boxart. +**Note2:** For future support, boxart sprites should also include: `boxart_back.png`, `boxart_top.png`, `boxart_bottom.png`, `boxart_left.png`, `boxart_right.png`. + + +#### Compatibilty mode +If you cannot yet satisfy the correct boxart layout, The menu still has **deprecated** support for filenames containing the Game ID. + +**Note:** This will add a noticeable delay for displaying parts of the menu. + +Each file must be named according to the 2,3 or 4 letter GamePak ID (matched in this order). +i.e. +* for GoldenEye 4 letters, this would be `sd:/menu/boxart/NGEE.png` and/or `sd:/menu/boxart/NGEP.png`. +* for GoldenEye 3 letters, this would be `sd:/menu/boxart/NGE.png`. +* for GoldenEye 2 letters, this would be `sd:/menu/boxart/GE.png`. + + +As a starting point, here are some links to boxart packs: +* [American GamePak Boxart](https://mega.nz/file/6cNGwSqI#8X5ukb65n3YMlGaUtSOGXkKo9HxVnnMOgqn94Epcr7w) +* [European GamePak Boxart](https://mega.nz/file/O7AjDbRJ#VnVU10dq8HQvBUQptppI6PAcQMb8-Zembqav8WtAQ_M) +* [64DD Boxart](https://mega.nz/file/O3JzwD7B#BYl1aV-pbrJ-MxWUbM_K0yGVIRbmSoxJJZqQInRzZyM) ### Menu Settings diff --git a/src/menu/components.h b/src/menu/components.h index 4925ee5b..67fde2d3 100644 --- a/src/menu/components.h +++ b/src/menu/components.h @@ -11,6 +11,41 @@ #include #include "menu_state.h" +/** @brief File image Enumeration. */ +typedef enum { + + /** @brief Boxart image from the front */ + IMAGE_BOXART_FRONT, + + /** @brief Boxart image from the back */ + IMAGE_BOXART_BACK, + + /** @brief Boxart image from the top */ + IMAGE_BOXART_TOP, + + /** @brief Boxart image from the bottom */ + IMAGE_BOXART_BOTTOM, + + /** @brief Boxart image from the left side */ + IMAGE_BOXART_LEFT, + + /** @brief Boxart image from the right side */ + IMAGE_BOXART_RIGHT, + + /** @brief GamePak image from the front */ + IMAGE_GAMEPAK_FRONT, + + /** @brief GamePak image from the back */ + IMAGE_GAMEPAK_BACK, + + /** @brief File image thumbnail */ + IMAGE_THUMBNAIL, + + /** @brief List end marker */ + IMAGE_TYPE_END + +} file_image_type_t; + /** * @addtogroup @@ -64,7 +99,7 @@ typedef struct { surface_t *image; } component_boxart_t; -component_boxart_t *component_boxart_init (const char *storage_prefix, char *game_code); +component_boxart_t *component_boxart_init (const char *storage_prefix, char *game_code, file_image_type_t current_image_view); void component_boxart_free (component_boxart_t *b); void component_boxart_draw (component_boxart_t *b); diff --git a/src/menu/components/boxart.c b/src/menu/components/boxart.c index f50294ee..2535068c 100644 --- a/src/menu/components/boxart.c +++ b/src/menu/components/boxart.c @@ -17,9 +17,9 @@ static void png_decoder_callback (png_err_t err, surface_t *decoded_image, void } -component_boxart_t *component_boxart_init (const char *storage_prefix, char *game_code) { +component_boxart_t *component_boxart_init (const char *storage_prefix, char *game_code, file_image_type_t current_image_view) { component_boxart_t *b; - char file_name[8]; + char boxart_id_path[8]; if ((b = calloc(1, sizeof(component_boxart_t))) == NULL) { return NULL; @@ -29,22 +29,84 @@ component_boxart_t *component_boxart_init (const char *storage_prefix, char *gam path_t *path = path_init(storage_prefix, BOXART_DIRECTORY); - sprintf(file_name, "%.3s.png", game_code); - path_push(path, file_name); - if (png_decoder_start(path_get(path), BOXART_WIDTH_MAX, BOXART_HEIGHT_MAX, png_decoder_callback, b) == PNG_OK) { - path_free(path); - return b; - } - path_pop(path); + sprintf(boxart_id_path, "%c/%c/%c/%c", game_code[0], game_code[1], game_code[2], game_code[3]); + path_push(path, boxart_id_path); - // TODO: This is bad, we should only check for 3 letter codes - sprintf(file_name, "%.2s.png", game_code + 1); - path_push(path, file_name); - if (png_decoder_start(path_get(path), BOXART_WIDTH_MAX, BOXART_HEIGHT_MAX, png_decoder_callback, b) == PNG_OK) { - path_free(path); - return b; + if (!directory_exists(path_get(path))) { // Allow boxart to not specify the region code. + path_pop(path); } + if (directory_exists(path_get(path))) { + switch (current_image_view) { + case IMAGE_GAMEPAK_FRONT: + path_push(path, "gamepak_front.png"); + case IMAGE_GAMEPAK_BACK: + path_push(path, "gamepak_back.png"); + case IMAGE_BOXART_BACK: + path_push(path, "boxart_back.png"); + case IMAGE_BOXART_LEFT: + path_push(path, "boxart_left.png"); + case IMAGE_BOXART_RIGHT: + path_push(path, "boxart_right.png"); + case IMAGE_BOXART_BOTTOM: + path_push(path, "boxart_bottom.png"); + case IMAGE_BOXART_TOP: + path_push(path, "boxart_top.png"); + default: + path_push(path, "boxart_front.png"); + } + + if (file_exists(path_get(path))) { + if (png_decoder_start(path_get(path), BOXART_WIDTH_MAX, BOXART_HEIGHT_MAX, png_decoder_callback, b) == PNG_OK) { + path_free(path); + return b; + } + } + } + else { // compatibility mode + + char file_name[8]; + + // reset the directory path used for boxart. + path = path_init(storage_prefix, BOXART_DIRECTORY); + + sprintf(file_name, "%c%c%c%c.png", game_code[0], game_code[1], game_code[2], game_code[3]); + path_push(path, file_name); + + if (file_exists(path_get(path))) { + if (png_decoder_start(path_get(path), BOXART_WIDTH_MAX, BOXART_HEIGHT_MAX, png_decoder_callback, b) == PNG_OK) { + path_free(path); + return b; + } + } + + path_pop(path); + sprintf(file_name, "%c%c%c.png", game_code[0], game_code[1], game_code[2]); + path_push(path, file_name); + + if (file_exists(path_get(path))) { + if (file_exists(path_get(path))) { + if (png_decoder_start(path_get(path), BOXART_WIDTH_MAX, BOXART_HEIGHT_MAX, png_decoder_callback, b) == PNG_OK) { + path_free(path); + return b; + } + } + } + else { + path_pop(path); + + sprintf(file_name, "%c%c.png", game_code[1], game_code[2]); + path_push(path, file_name); + if (file_exists(path_get(path))) { + if (png_decoder_start(path_get(path), BOXART_WIDTH_MAX, BOXART_HEIGHT_MAX, png_decoder_callback, b) == PNG_OK) { + path_free(path); + return b; + } + } + } + } + // TODO: return default image. + path_free(path); free(b); @@ -89,4 +151,4 @@ void component_boxart_draw (component_boxart_t *b) { BOXART_LOADING_COLOR ); } -} \ No newline at end of file +} diff --git a/src/menu/views/load_disk.c b/src/menu/views/load_disk.c index 0165bdc9..39957fcf 100644 --- a/src/menu/views/load_disk.c +++ b/src/menu/views/load_disk.c @@ -170,7 +170,7 @@ void view_load_disk_init (menu_t *menu) { menu_show_error(menu, convert_error_message(err)); } - boxart = component_boxart_init(menu->storage_prefix, menu->load.disk_info.id); + boxart = component_boxart_init(menu->storage_prefix, menu->load.disk_info.id, IMAGE_BOXART_FRONT); } void view_load_disk_display (menu_t *menu, surface_t *display) { diff --git a/src/menu/views/load_rom.c b/src/menu/views/load_rom.c index c408b47c..36933b92 100644 --- a/src/menu/views/load_rom.c +++ b/src/menu/views/load_rom.c @@ -355,7 +355,7 @@ void view_load_rom_init (menu_t *menu) { return; } - boxart = component_boxart_init(menu->storage_prefix, menu->load.rom_info.game_code); + boxart = component_boxart_init(menu->storage_prefix, menu->load.rom_info.game_code, IMAGE_BOXART_FRONT); component_context_menu_init(&options_context_menu); }