mirror of
https://github.com/wavemotion-dave/NINTV-DS.git
synced 2025-06-19 06:15:40 -04:00
336 lines
14 KiB
C++
336 lines
14 KiB
C++
// =====================================================================================
|
|
// Copyright (c) 2021 Dave Bernazzani (wavemotion-dave)
|
|
//
|
|
// Copying and distribution of this emulator, it's 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 "ds_tools.h"
|
|
#include "overlay.h"
|
|
#include "config.h"
|
|
#include "bgBottom.h"
|
|
#include "bgBottom-treasure.h"
|
|
#include "bgBottom-cloudy.h"
|
|
#include "bgBottom-astro.h"
|
|
#include "bgBottom-spartans.h"
|
|
#include "bgBottom-b17.h"
|
|
#include "bgBottom-atlantis.h"
|
|
#include "bgBottom-bombsquad.h"
|
|
#include "bgBottom-utopia.h"
|
|
#include "bgBottom-swords.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
|
|
|
|
{ 23, 82, 16, 36}, // META_RESET
|
|
{ 23, 82, 45, 65}, // META_LOAD
|
|
{ 23, 82, 74, 94}, // META_CONFIG
|
|
{ 23, 82, 103, 123}, // META_SCORE
|
|
{255, 255, 255, 255}, // META_QUIT
|
|
{ 23, 82, 132, 152}, // META_STATE
|
|
{ 23, 82, 161, 181}, // META_MENU
|
|
{255, 255, 255, 255}, // META_SWAP
|
|
{255, 255, 255, 255}, // META_MANUAL
|
|
{255, 255, 255, 255}, // META_STRETCH
|
|
{255, 255, 255, 255}, // META_GCONFIG
|
|
};
|
|
|
|
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 *) 0x06860000; //128K of video memory
|
|
unsigned short *customMap = (unsigned short *)0x068A0000; //16K of video memory
|
|
unsigned short customPal[512];
|
|
|
|
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...
|
|
if (myGlobalConfig.ovl_dir == 1) // In: /ROMS/OVL
|
|
{
|
|
strcpy(filename, "/roms/ovl/");
|
|
}
|
|
else if (myGlobalConfig.ovl_dir == 2) // In: /ROMS/INTY/OVL
|
|
{
|
|
strcpy(filename, "/roms/intv/ovl/");
|
|
}
|
|
else if (myGlobalConfig.ovl_dir == 3) // In: /DATA/OVL/
|
|
{
|
|
strcpy(filename, "/data/ovl/");
|
|
}
|
|
else
|
|
{
|
|
strcpy(filename, "./"); // In: Same DIR as ROM files
|
|
}
|
|
|
|
// If we have a game (RIP) loaded, try to find a matching overlay
|
|
if ((currentRip != NULL) && !bCustomGeneric)
|
|
{
|
|
strcat(filename, currentRip->GetFileName());
|
|
filename[strlen(filename)-4] = 0;
|
|
strcat(filename, ".ovl");
|
|
}
|
|
else
|
|
{
|
|
strcat(filename, "nintv-ds.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)
|
|
{
|
|
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, 24*1024*sizeof(UINT32));
|
|
memset(customMap, 0x00, 16*1024*sizeof(UINT16));
|
|
memset(customPal, 0x00, 512*sizeof(UINT16));
|
|
|
|
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 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 // Just use the default 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(void)
|
|
{
|
|
// Assume default overlay... custom can change it below...
|
|
memcpy(&myOverlay, &defaultOverlay, sizeof(myOverlay));
|
|
|
|
swiWaitForVBlank();
|
|
|
|
if (myConfig.overlay_selected == 1) // Custom Overlay!
|
|
{
|
|
load_custom_overlay(false);
|
|
}
|
|
else if (myConfig.overlay_selected == 2) // Treasure of Tarmin
|
|
{
|
|
decompress(bgBottom_treasureTiles, bgGetGfxPtr(bg0b), LZ77Vram);
|
|
decompress(bgBottom_treasureMap, (void*) bgGetMapPtr(bg0b), LZ77Vram);
|
|
dmaCopy((void *) bgBottom_treasurePal,(u16*) BG_PALETTE_SUB,256*2);
|
|
}
|
|
else if (myConfig.overlay_selected == 3) // Cloudy Mountain
|
|
{
|
|
decompress(bgBottom_cloudyTiles, bgGetGfxPtr(bg0b), LZ77Vram);
|
|
decompress(bgBottom_cloudyMap, (void*) bgGetMapPtr(bg0b), LZ77Vram);
|
|
dmaCopy((void *) bgBottom_cloudyPal,(u16*) BG_PALETTE_SUB,256*2);
|
|
}
|
|
else if (myConfig.overlay_selected == 4) // Astrosmash
|
|
{
|
|
decompress(bgBottom_astroTiles, bgGetGfxPtr(bg0b), LZ77Vram);
|
|
decompress(bgBottom_astroMap, (void*) bgGetMapPtr(bg0b), LZ77Vram);
|
|
dmaCopy((void *) bgBottom_astroPal,(u16*) BG_PALETTE_SUB,256*2);
|
|
}
|
|
else if (myConfig.overlay_selected == 5) // Space Spartans
|
|
{
|
|
decompress(bgBottom_spartansTiles, bgGetGfxPtr(bg0b), LZ77Vram);
|
|
decompress(bgBottom_spartansMap, (void*) bgGetMapPtr(bg0b), LZ77Vram);
|
|
dmaCopy((void *) bgBottom_spartansPal,(u16*) BG_PALETTE_SUB,256*2);
|
|
}
|
|
else if (myConfig.overlay_selected == 6) // B17 Bomber
|
|
{
|
|
decompress(bgBottom_b17Tiles, bgGetGfxPtr(bg0b), LZ77Vram);
|
|
decompress(bgBottom_b17Map, (void*) bgGetMapPtr(bg0b), LZ77Vram);
|
|
dmaCopy((void *) bgBottom_b17Pal,(u16*) BG_PALETTE_SUB,256*2);
|
|
}
|
|
else if (myConfig.overlay_selected == 7) // Atlantis
|
|
{
|
|
decompress(bgBottom_atlantisTiles, bgGetGfxPtr(bg0b), LZ77Vram);
|
|
decompress(bgBottom_atlantisMap, (void*) bgGetMapPtr(bg0b), LZ77Vram);
|
|
dmaCopy((void *) bgBottom_atlantisPal,(u16*) BG_PALETTE_SUB,256*2);
|
|
}
|
|
else if (myConfig.overlay_selected == 8) // Bomb Squad
|
|
{
|
|
decompress(bgBottom_bombsquadTiles, bgGetGfxPtr(bg0b), LZ77Vram);
|
|
decompress(bgBottom_bombsquadMap, (void*) bgGetMapPtr(bg0b), LZ77Vram);
|
|
dmaCopy((void *) bgBottom_bombsquadPal,(u16*) BG_PALETTE_SUB,256*2);
|
|
}
|
|
else if (myConfig.overlay_selected == 9) // Utopia
|
|
{
|
|
decompress(bgBottom_utopiaTiles, bgGetGfxPtr(bg0b), LZ77Vram);
|
|
decompress(bgBottom_utopiaMap, (void*) bgGetMapPtr(bg0b), LZ77Vram);
|
|
dmaCopy((void *) bgBottom_utopiaPal,(u16*) BG_PALETTE_SUB,256*2);
|
|
}
|
|
else if (myConfig.overlay_selected == 10) // Swords & Serpents
|
|
{
|
|
decompress(bgBottom_swordsTiles, bgGetGfxPtr(bg0b), LZ77Vram);
|
|
decompress(bgBottom_swordsMap, (void*) bgGetMapPtr(bg0b), LZ77Vram);
|
|
dmaCopy((void *) bgBottom_swordsPal,(u16*) BG_PALETTE_SUB,256*2);
|
|
}
|
|
else // Default Overlay...
|
|
{
|
|
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();
|
|
}
|
|
|
|
// End of Line
|