NINTV-DS/arm9/source/overlay.cpp

402 lines
16 KiB
C++

// =====================================================================================
// Copyright (c) 2021-2024 Dave Bernazzani (wavemotion-dave)
//
// Copying and distribution of this emulator, its source code and associated
// readme files, with or without modification, are permitted in any medium without
// royalty provided the this copyright notice is used and wavemotion-dave (NINTV-DS)
// and Kyle Davis (BLISS) are thanked profusely.
//
// The NINTV-DS emulator is offered as-is, without any warranty.
// =====================================================================================
#include <nds.h>
#include <nds/fifomessages.h>
#include<stdio.h>
#include <fat.h>
#include <dirent.h>
#include <unistd.h>
#include "nintv-ds.h"
#include "overlay.h"
#include "config.h"
#include "ECSKeyboard.h"
#include "bgBottom.h"
#include "bgBottom-ECS.h"
#include "bgBottom-disc.h"
#include "bgTop.h"
#include "Emulator.h"
#include "Rip.h"
// ------------------------------------------------
// Reuse the char buffer from the game load...
// we wouldn't need to use this at the same time.
// ------------------------------------------------
extern char szName[];
extern Rip *currentRip;
// ----------------------------------------------------------------------------------------
// This is the default overlay that matches the main non-custom overlay bottom screen.
// ----------------------------------------------------------------------------------------
struct Overlay_t defaultOverlay[OVL_MAX] =
{
{120, 155, 30, 60}, // KEY_1
{158, 192, 30, 60}, // KEY_2
{195, 230, 30, 60}, // KEY_3
{120, 155, 65, 95}, // KEY_4
{158, 192, 65, 95}, // KEY_5
{195, 230, 65, 95}, // KEY_6
{120, 155, 101, 135}, // KEY_7
{158, 192, 101, 135}, // KEY_8
{195, 230, 101, 135}, // KEY_9
{120, 155, 140, 175}, // KEY_CLEAR
{158, 192, 140, 175}, // KEY_0
{195, 230, 140, 175}, // KEY_ENTER
{255, 255, 255, 255}, // KEY_FIRE
{255, 255, 255, 255}, // KEY_L_ACT
{255, 255, 255, 255}, // KEY_R_ACT
{ 10, 87, 10, 40}, // META_RESET
{ 10, 87, 41, 70}, // META_LOAD
{ 10, 87, 71, 100}, // META_CONFIG
{255, 255, 255, 255}, // META_SCORE
{255, 255, 255, 255}, // META_QUIT
{ 10, 87, 101, 131}, // META_STATE
{ 10, 87, 131, 160}, // META_MENU
{255, 255, 255, 255}, // META_SWAP
{255, 255, 255, 255}, // META_MANUAL
{ 50, 86, 161, 191}, // META_DISC
{ 8, 49, 161, 191}, // META_KEYBOARD
};
// ----------------------------------------------------------------------------------------
// This is the ECS overlay with no menu options...
// ----------------------------------------------------------------------------------------
struct Overlay_t ecsOverlay[OVL_MAX] =
{
{255, 255, 255, 255}, // KEY_1
{255, 255, 255, 255}, // KEY_2
{255, 255, 255, 255}, // KEY_3
{255, 255, 255, 255}, // KEY_4
{255, 255, 255, 255}, // KEY_5
{255, 255, 255, 255}, // KEY_6
{255, 255, 255, 255}, // KEY_7
{255, 255, 255, 255}, // KEY_8
{255, 255, 255, 255}, // KEY_9
{255, 255, 255, 255}, // KEY_CLEAR
{255, 255, 255, 255}, // KEY_0
{255, 255, 255, 255}, // KEY_ENTER
{255, 255, 255, 255}, // KEY_FIRE
{255, 255, 255, 255}, // KEY_L_ACT
{255, 255, 255, 255}, // KEY_R_ACT
{255, 255, 255, 255}, // META_RESET
{255, 255, 255, 255}, // META_LOAD
{255, 255, 255, 255}, // META_CONFIG
{255, 255, 255, 255}, // META_SCORE
{255, 255, 255, 255}, // META_QUIT
{255, 255, 255, 255}, // META_STATE
{255, 255, 255, 255}, // META_MENU
{255, 255, 255, 255}, // META_SWAP
{255, 255, 255, 255}, // META_MANUAL
{255, 255, 255, 255}, // META_DISC
{255, 255, 255, 255}, // META_KEYBOARD
};
// ----------------------------------------------------------------------------------------
// This is the Disc overlay with no menu options...
// ----------------------------------------------------------------------------------------
struct Overlay_t discOverlay[OVL_MAX] =
{
{255, 255, 255, 255}, // KEY_1
{255, 255, 255, 255}, // KEY_2
{255, 255, 255, 255}, // KEY_3
{255, 255, 255, 255}, // KEY_4
{255, 255, 255, 255}, // KEY_5
{255, 255, 255, 255}, // KEY_6
{255, 255, 255, 255}, // KEY_7
{255, 255, 255, 255}, // KEY_8
{255, 255, 255, 255}, // KEY_9
{255, 255, 255, 255}, // KEY_CLEAR
{255, 255, 255, 255}, // KEY_0
{255, 255, 255, 255}, // KEY_ENTER
{255, 255, 255, 255}, // KEY_FIRE
{255, 255, 255, 255}, // KEY_L_ACT
{255, 255, 255, 255}, // KEY_R_ACT
{255, 255, 255, 255}, // META_RESET
{255, 255, 255, 255}, // META_LOAD
{255, 255, 255, 255}, // META_CONFIG
{255, 255, 255, 255}, // META_SCORE
{255, 255, 255, 255}, // META_QUIT
{255, 255, 255, 255}, // META_STATE
{255, 255, 255, 255}, // META_MENU
{255, 255, 255, 255}, // META_SWAP
{255, 255, 255, 255}, // META_MANUAL
{255, 255, 255, 255}, // META_DISC
{255, 255, 255, 255}, // META_KEYBOARD
};
struct Overlay_t myOverlay[OVL_MAX];
struct Overlay_t myDisc[DISC_MAX];
// -------------------------------------------------------------
// Rather than take up precious RAM, we use some video memory.
// -------------------------------------------------------------
unsigned int *customTiles = (unsigned int *) 0x06880000; //60K of video memory for the tiles (largest I've seen so far is ~48K)
unsigned short *customMap = (unsigned short *)0x0688F000; // 4K of video memory for the map (generally about 2.5K)
unsigned short customPal[512];
char directory[128];
char filename[128];
// -----------------------------------------------------------------------------------------------
// Custom overlays are read in and must be in a very strict format. See the documenatation
// for custom overlays for details on the format this must be in. We could probably use a
// bit more error checking here... but we expect customer overlay designers to know what's up.
// -----------------------------------------------------------------------------------------------
void load_custom_overlay(bool bCustomGeneric)
{
FILE *fp = NULL;
// -------------------------------------------------------
// Read the associated .ovl file and parse it... Start by
// getting the root folder where overlays are stored...
// -------------------------------------------------------
if (myGlobalConfig.ovl_dir == 1) // In: /ROMS/OVL
{
strcpy(directory, "/roms/ovl/");
}
else if (myGlobalConfig.ovl_dir == 2) // In: /ROMS/INTY/OVL
{
strcpy(directory, "/roms/intv/ovl/");
}
else if (myGlobalConfig.ovl_dir == 3) // In: /DATA/OVL/
{
strcpy(directory, "/data/ovl/");
}
else
{
strcpy(directory, "./"); // In: Same DIR as ROM files
}
u8 bFound = 0;
// If we have a game (RIP) loaded, try to find a matching overlay
if (currentRip != NULL)
{
strcpy(filename, directory);
strcat(filename, currentRip->GetFileName());
filename[strlen(filename)-4] = 0;
strcat(filename, ".ovl");
fp = fopen(filename, "rb");
if (fp != NULL) // If file found
{
bFound = 1;
}
}
if (bFound == 0)
{
strcpy(filename, directory);
strcat(filename, "generic.ovl");
fp = fopen(filename, "rb");
}
// Default these to unused...
bUseDiscOverlay = false;
for (UINT8 i=0; i < DISC_MAX; i++)
{
myDisc[i].x1 = 255;
myDisc[i].x2 = 255;
myDisc[i].y1 = 255;
myDisc[i].y2 = 255;
}
if (fp != NULL) // If overlay found, parse it and use it...
{
UINT8 ov_idx = 0;
UINT8 disc_idx=0;
UINT16 tiles_idx=0;
UINT16 map_idx=0;
UINT16 pal_idx=0;
char *token;
memset(customTiles, 0x00, 0x10000); // Clear the 64K of video memory to prep for custom tiles...
memcpy(&myOverlay, &discOverlay, sizeof(myOverlay)); // Start with a blank overlay...
do
{
fgets(szName, 255, fp);
// Handle Overlay Line
if (strstr(szName, ".ovl") != NULL)
{
if (ov_idx < OVL_MAX)
{
char *ptr = strstr(szName, ".ovl");
ptr += 5;
myOverlay[ov_idx].x1 = strtoul(ptr, &ptr, 10); while (*ptr == ',' || *ptr == ' ') ptr++;
myOverlay[ov_idx].x2 = strtoul(ptr, &ptr, 10); while (*ptr == ',' || *ptr == ' ') ptr++;
myOverlay[ov_idx].y1 = strtoul(ptr, &ptr, 10); while (*ptr == ',' || *ptr == ' ') ptr++;
myOverlay[ov_idx].y2 = strtoul(ptr, &ptr, 10); while (*ptr == ',' || *ptr == ' ') ptr++;
ov_idx++;
}
}
// Handle Disc Line
if (strstr(szName, ".disc") != NULL)
{
bUseDiscOverlay = true;
if (disc_idx < DISC_MAX)
{
char *ptr = strstr(szName, ".disc");
ptr += 6;
myDisc[disc_idx].x1 = strtoul(ptr, &ptr, 10); while (*ptr == ',' || *ptr == ' ') ptr++;
myDisc[disc_idx].x2 = strtoul(ptr, &ptr, 10); while (*ptr == ',' || *ptr == ' ') ptr++;
myDisc[disc_idx].y1 = strtoul(ptr, &ptr, 10); while (*ptr == ',' || *ptr == ' ') ptr++;
myDisc[disc_idx].y2 = strtoul(ptr, &ptr, 10); while (*ptr == ',' || *ptr == ' ') ptr++;
disc_idx++;
}
}
// Handle HUD_x Line
if (strstr(szName, ".hudx") != NULL)
{
char *ptr = strstr(szName, ".hudx");
ptr += 6;
hud_x = strtoul(ptr, &ptr, 10);
}
// Handle HUD_y Line
if (strstr(szName, ".hudy") != NULL)
{
char *ptr = strstr(szName, ".hudy");
ptr += 6;
hud_y = strtoul(ptr, &ptr, 10);
}
// Handle Tile Line
if (strstr(szName, ".tile") != NULL)
{
char *ptr = strstr(szName, ".tile");
ptr += 6;
customTiles[tiles_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
customTiles[tiles_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
customTiles[tiles_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
customTiles[tiles_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
customTiles[tiles_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
customTiles[tiles_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
customTiles[tiles_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
customTiles[tiles_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
}
// Handle Map Line
if (strstr(szName, ".map") != NULL)
{
char *ptr = strstr(szName, ".map");
ptr += 4;
customMap[map_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
customMap[map_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
customMap[map_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
customMap[map_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
customMap[map_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
customMap[map_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
customMap[map_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
customMap[map_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
}
// Handle Palette Line
if (strstr(szName, ".pal") != NULL)
{
char *ptr = strstr(szName, ".pal");
ptr += 4;
customPal[pal_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
customPal[pal_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
customPal[pal_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
customPal[pal_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
customPal[pal_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
customPal[pal_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
customPal[pal_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
customPal[pal_idx++] = strtoul(ptr, &ptr, 16); while (*ptr == ',' || *ptr == ' ') ptr++;
}
} while (!feof(fp));
fclose(fp);
decompress(customTiles, bgGetGfxPtr(bg0b), LZ77Vram);
decompress(customMap, (void*) bgGetMapPtr(bg0b), LZ77Vram);
dmaCopy((void *) customPal,(u16*) BG_PALETTE_SUB,256*2);
}
else // Otherwise, just use the built-in default/generic overlay...
{
decompress(bgBottomTiles, bgGetGfxPtr(bg0b), LZ77Vram);
decompress(bgBottomMap, (void*) bgGetMapPtr(bg0b), LZ77Vram);
dmaCopy((void *) bgBottomPal,(u16*) BG_PALETTE_SUB,256*2);
}
}
// ---------------------------------------------------------------------------
// This puts the overlay on the main screen. It can be one of the built-in
// overlays or it might be a custom overlay that will be rendered...
// ---------------------------------------------------------------------------
void show_overlay(u8 bShowKeyboard, u8 bShowDisc)
{
// Assume default overlay... custom can change it below...
memcpy(&myOverlay, &defaultOverlay, sizeof(myOverlay));
swiWaitForVBlank();
if (bShowKeyboard) // ECS keyboard overlay
{
decompress(bgBottom_ECSTiles, bgGetGfxPtr(bg0b), LZ77Vram);
decompress(bgBottom_ECSMap, (void*) bgGetMapPtr(bg0b), LZ77Vram);
dmaCopy((void *) bgBottom_ECSPal,(u16*) BG_PALETTE_SUB,256*2);
// ECS Overlay...
memcpy(&myOverlay, &ecsOverlay, sizeof(myOverlay));
}
else // Default Overlay... which might be custom!!
{
if (bShowDisc)
{
decompress(bgBottom_discTiles, bgGetGfxPtr(bg0b), LZ77Vram);
decompress(bgBottom_discMap, (void*) bgGetMapPtr(bg0b), LZ77Vram);
dmaCopy((void *) bgBottom_discPal,(u16*) BG_PALETTE_SUB,256*2);
// Disc Overlay...
memcpy(&myOverlay, &discOverlay, sizeof(myOverlay));
}
else
{
load_custom_overlay(true); // This will try to load nintv-ds.ovl or else default to the generic background
}
}
unsigned short dmaVal = *(bgGetMapPtr(bg1b) +31*32);
dmaFillWords(dmaVal | (dmaVal<<16),(void*) bgGetMapPtr(bg1b),32*24*2);
REG_BLDCNT=0; REG_BLDCNT_SUB=0; REG_BLDY=0; REG_BLDY_SUB=0;
swiWaitForVBlank();
if (bShowKeyboard) // ECS keyboard overlay
{
dsPrintValue(1,22,ecs_ctrl_key?1:0,ecs_ctrl_key ? (char*)"@": (char*)" ");
dsPrintValue(5,22,0,ecs_shift_key ? (char*)"@": (char*)" ");
}
}
// End of Line