mirror of
https://github.com/wavemotion-dave/NINTV-DS.git
synced 2025-06-18 22:05:37 -04:00
1869 lines
58 KiB
C++
1869 lines
58 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 "savestate.h"
|
|
#include "config.h"
|
|
#include "manual.h"
|
|
#include "bgBottom.h"
|
|
#include "bgTop.h"
|
|
#include "bgFileSel.h"
|
|
#include "bgHighScore.h"
|
|
#include "bgOptions.h"
|
|
#include "Emulator.h"
|
|
#include "Rip.h"
|
|
#include "highscore.h"
|
|
#include "overlay.h"
|
|
#include "debugger.h"
|
|
#include "AudioMixer.h"
|
|
|
|
char line[256];
|
|
|
|
#define SOUND_VOLUME 127 /* Max volume */
|
|
|
|
BOOL InitializeEmulator(void);
|
|
|
|
typedef enum _RunState
|
|
{
|
|
Stopped,
|
|
Paused,
|
|
Running,
|
|
Quit
|
|
} RunState;
|
|
|
|
bool bStartSoundFifo = false;
|
|
bool bUseJLP = false;
|
|
bool bForceIvoice=false;
|
|
bool bInitEmulator=false;
|
|
bool bUseDiscOverlay=false;
|
|
|
|
RunState runState = Stopped;
|
|
Emulator *currentEmu = NULL;
|
|
Rip *currentRip = NULL;
|
|
VideoBus *videoBus = NULL;
|
|
AudioMixer *audioMixer = NULL;
|
|
|
|
UINT16 emu_frames=0;
|
|
UINT16 frames_per_sec_calc=0;
|
|
UINT8 oneSecTick=FALSE;
|
|
|
|
void dsInitPalette(void);
|
|
|
|
int bg0, bg0b, bg1b;
|
|
bool bFirstGameLoaded = false;
|
|
|
|
|
|
void reset_emu_frames(void)
|
|
{
|
|
TIMER0_CR=0;
|
|
TIMER0_DATA=0;
|
|
TIMER0_CR=TIMER_ENABLE | TIMER_DIV_1024;
|
|
emu_frames=0;
|
|
}
|
|
|
|
void dsPrintValue(int x, int y, unsigned int isSelect, char *pchStr)
|
|
{
|
|
u16 *pusEcran,*pusMap;
|
|
u16 usCharac;
|
|
char *pTrTxt=pchStr;
|
|
char ch;
|
|
|
|
pusEcran=(u16*) (bgGetMapPtr(bg1b))+x+(y<<5);
|
|
pusMap=(u16*) (bgGetMapPtr(bg0b)+(2*isSelect+24)*32);
|
|
|
|
while((*pTrTxt)!='\0' )
|
|
{
|
|
ch = *pTrTxt;
|
|
if (ch >= 'a' && ch <= 'z') ch -= 32; // Faster than strcpy/strtoupper
|
|
usCharac=0x0000;
|
|
if ((ch) == '|')
|
|
usCharac=*(pusMap);
|
|
else if (((ch)<' ') || ((ch)>'_'))
|
|
usCharac=*(pusMap);
|
|
else if((ch)<'@')
|
|
usCharac=*(pusMap+(ch)-' ');
|
|
else
|
|
usCharac=*(pusMap+32+(ch)-'@');
|
|
*pusEcran++=usCharac;
|
|
pTrTxt++;
|
|
}
|
|
}
|
|
|
|
class AudioMixerDS : public AudioMixer
|
|
{
|
|
public:
|
|
AudioMixerDS();
|
|
void resetProcessor();
|
|
void flushAudio();
|
|
void init(UINT32 sampleRate);
|
|
void release();
|
|
|
|
UINT16* outputBuffer;
|
|
UINT16 outputBufferSize;
|
|
UINT16 outputBufferWritePosition;
|
|
};
|
|
|
|
AudioMixerDS::AudioMixerDS()
|
|
: outputBuffer(NULL),
|
|
outputBufferSize(0),
|
|
outputBufferWritePosition(0)
|
|
{
|
|
this->outputBufferWritePosition = 0;
|
|
this->outputBufferSize = SOUND_SIZE;
|
|
}
|
|
|
|
void AudioMixerDS::resetProcessor()
|
|
{
|
|
if (outputBuffer)
|
|
{
|
|
outputBufferWritePosition = 0;
|
|
}
|
|
|
|
fifoSendValue32(FIFO_USER_01,(1<<16) | SOUND_KILL);
|
|
|
|
// clears the emulator side of the audio mixer
|
|
AudioMixer::resetProcessor();
|
|
|
|
// restarts the ARM7 side of the audio...
|
|
bStartSoundFifo = true;
|
|
|
|
// Set the emulation back to the start...
|
|
reset_emu_frames();
|
|
}
|
|
|
|
|
|
void AudioMixerDS::init(UINT32 sampleRate)
|
|
{
|
|
release();
|
|
|
|
outputBufferWritePosition = 0;
|
|
|
|
AudioMixer::init(sampleRate);
|
|
}
|
|
|
|
void AudioMixerDS::release()
|
|
{
|
|
AudioMixer::release();
|
|
}
|
|
|
|
|
|
void AudioMixerDS::flushAudio()
|
|
{
|
|
AudioMixer::flushAudio();
|
|
}
|
|
|
|
class VideoBusDS : public VideoBus
|
|
{
|
|
public:
|
|
VideoBusDS();
|
|
void init(UINT32 width, UINT32 height);
|
|
void release();
|
|
void render();
|
|
};
|
|
|
|
VideoBusDS::VideoBusDS() { }
|
|
|
|
void VideoBusDS::init(UINT32 width, UINT32 height)
|
|
{
|
|
release();
|
|
|
|
// initialize the pixelBuffer
|
|
VideoBus::init(width, height);
|
|
}
|
|
|
|
void VideoBusDS::release()
|
|
{
|
|
VideoBus::release();
|
|
}
|
|
|
|
ITCM_CODE void VideoBusDS::render()
|
|
{
|
|
extern UINT16 global_frames;
|
|
|
|
frames_per_sec_calc++;
|
|
global_frames++;
|
|
VideoBus::render();
|
|
|
|
// Any level of frame skip will skip the render()
|
|
if (myConfig.frame_skip_opt)
|
|
{
|
|
if ((global_frames & 1) == (myConfig.frame_skip_opt==1 ? 1:0)) return; // Skip ODD or EVEN Frames as configured
|
|
}
|
|
UINT32 *ds_video=(UINT32*)0x06000000;
|
|
UINT32 *source_video = (UINT32*)pixelBuffer;
|
|
|
|
for (int j=0; j<192; j++)
|
|
{
|
|
for (int x=0; x<160/4; x++)
|
|
{
|
|
*ds_video++ = *source_video++;
|
|
}
|
|
//*ds_video++ = *source_video++ & 0x00FFFFFF; // The Intellivision STIC does NOT render the final column of pixels at 160 (so the last column drawn is 159)
|
|
ds_video += 24;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL LoadCart(const CHAR* filename)
|
|
{
|
|
if (strlen(filename) < 5)
|
|
return FALSE;
|
|
|
|
//convert .bin and .rom to .rip, since our emulation only knows how to run .rip
|
|
const CHAR* extStart = filename + strlen(filename) - 4;
|
|
if (strcmpi(extStart, ".int") == 0 || strcmpi(extStart, ".bin") == 0)
|
|
{
|
|
//load the bin file as a Rip - use internal database or maybe <filename>.cfg exists... LoadBin() handles all that.
|
|
currentRip = Rip::LoadBin(filename);
|
|
if (currentRip == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else if (strcmpi(extStart, ".rom") == 0) // .rom files contain the loading info...
|
|
{
|
|
//load the bin file as a Rip
|
|
currentRip = Rip::LoadRom(filename);
|
|
if (currentRip == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
// New game is loaded... (would have returned FALSE above otherwise)
|
|
// ---------------------------------------------------------------------
|
|
extern UINT16 fudge_timing;
|
|
extern UINT8 bLatched;
|
|
fudge_timing = 0;
|
|
bLatched = false;
|
|
if (currentRip->GetCRC() == 0x5F6E1AF6) fudge_timing = 1000; // Motocross needs some fudge timing to run... known race condition...
|
|
if (currentRip->GetCRC() == 0x2DEACD15) bLatched = true; // Stampede must have latched backtab access
|
|
if (currentRip->GetCRC() == 0x573B9B6D) bLatched = true; // Masters of the Universe must have latched backtab access
|
|
|
|
FindAndLoadConfig();
|
|
dsShowScreenEmu();
|
|
dsShowScreenMain(false);
|
|
|
|
bFirstGameLoaded = TRUE;
|
|
bInitEmulator = true;
|
|
|
|
bStartSoundFifo = true;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL LoadPeripheralRoms(Peripheral* peripheral)
|
|
{
|
|
UINT16 count = peripheral->GetROMCount();
|
|
for (UINT16 i = 0; i < count; i++) {
|
|
ROM* r = peripheral->GetROM(i);
|
|
if (r->isLoaded())
|
|
continue;
|
|
|
|
CHAR nextFile[MAX_PATH];
|
|
|
|
if (myGlobalConfig.bios_dir == 1) // In: /ROMS/BIOS
|
|
{
|
|
strcpy(nextFile, "/roms/bios/");
|
|
}
|
|
else if (myGlobalConfig.bios_dir == 2) // In: /ROMS/INTV/BIOS
|
|
{
|
|
strcpy(nextFile, "/roms/intv/bios/");
|
|
}
|
|
else if (myGlobalConfig.bios_dir == 3) // In: /DATA/BIOS/
|
|
{
|
|
strcpy(nextFile, "/data/bios/");
|
|
}
|
|
else
|
|
{
|
|
strcpy(nextFile, "./"); // In: Same DIR as ROM files
|
|
}
|
|
|
|
strcat(nextFile, r->getDefaultFileName());
|
|
if (!r->load(nextFile, r->getDefaultFileOffset()))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL InitializeEmulator(void)
|
|
{
|
|
//find the currentEmulator required to run this RIP
|
|
if (currentRip == NULL) return FALSE;
|
|
|
|
currentEmu = Emulator::GetEmulator();
|
|
if (currentEmu == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//load the BIOS files required for this currentEmulator
|
|
if (!LoadPeripheralRoms(currentEmu))
|
|
{
|
|
dsPrintValue(0,1,0, (char*) "NO BIOS FILES");
|
|
return FALSE;
|
|
}
|
|
|
|
//load peripheral roms
|
|
INT32 count = currentEmu->GetPeripheralCount();
|
|
for (INT32 i = 0; i < count; i++)
|
|
{
|
|
Peripheral* p = currentEmu->GetPeripheral(i);
|
|
PeripheralCompatibility usage = currentRip->GetPeripheralUsage(p->GetShortName());
|
|
if (usage == PERIPH_INCOMPATIBLE || usage == PERIPH_COMPATIBLE) {
|
|
currentEmu->UsePeripheral(i, FALSE);
|
|
continue;
|
|
}
|
|
|
|
BOOL loaded = LoadPeripheralRoms(p);
|
|
if (loaded) {
|
|
//peripheral loaded, might as well use it.
|
|
currentEmu->UsePeripheral(i, TRUE);
|
|
}
|
|
else if (usage == PERIPH_OPTIONAL) {
|
|
//didn't load, but the peripheral is optional, so just skip it
|
|
currentEmu->UsePeripheral(i, FALSE);
|
|
}
|
|
else //usage == PERIPH_REQUIRED, but it didn't load
|
|
{
|
|
dsPrintValue(0,1,0, (char*) "NO IVOICE.BIN");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// No audio to start... it will turn on 1 frame in...
|
|
TIMER2_CR=0; irqDisable(IRQ_TIMER2);
|
|
|
|
//hook the audio and video up to the currentEmulator
|
|
currentEmu->InitVideo(videoBus,currentEmu->GetVideoWidth(),currentEmu->GetVideoHeight());
|
|
currentEmu->InitAudio(audioMixer, mySoundFrequency);
|
|
|
|
// Clear the audio mixer...
|
|
audioMixer->resetProcessor();
|
|
|
|
//put the RIP in the currentEmulator
|
|
currentEmu->SetRip(currentRip);
|
|
|
|
// Load up the fast ROM memory for quick fetches
|
|
currentEmu->LoadFastMemory();
|
|
|
|
//Reset everything
|
|
currentEmu->Reset();
|
|
|
|
// Make sure we're starting fresh...
|
|
reset_emu_frames();
|
|
|
|
// And put the sound engine back to the start...
|
|
bStartSoundFifo = true;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void HandleScreenStretch(void)
|
|
{
|
|
char tmpStr[33];
|
|
decompress(bgHighScoreTiles, bgGetGfxPtr(bg0b), LZ77Vram);
|
|
decompress(bgHighScoreMap, (void*) bgGetMapPtr(bg0b), LZ77Vram);
|
|
dmaCopy((void *) bgHighScorePal,(u16*) BG_PALETTE_SUB,256*2);
|
|
unsigned short dmaVal = *(bgGetMapPtr(bg1b) +31*32);
|
|
dmaFillWords(dmaVal | (dmaVal<<16),(void*) bgGetMapPtr(bg1b),32*24*2);
|
|
swiWaitForVBlank();
|
|
|
|
dsPrintValue(2, 5, 0, (char*)"PRESS UP/DN TO STRETCH SCREEN");
|
|
dsPrintValue(2, 7, 0, (char*)"LEFT/RIGHT TO SHIFT SCREEN");
|
|
dsPrintValue(2, 15, 0, (char*)"PRESS X TO RESET TO DEFAULTS");
|
|
dsPrintValue(1, 16,0, (char*)"START to SAVE, PRESS B TO EXIT");
|
|
|
|
bool bDone = false;
|
|
int last_stretch_x = -99;
|
|
int last_offset_x = -99;
|
|
while (!bDone)
|
|
{
|
|
int keys_pressed = keysCurrent();
|
|
if (keys_pressed & KEY_UP)
|
|
{
|
|
if (myConfig.stretch_x > 0x0080) REG_BG3PA = --myConfig.stretch_x;
|
|
}
|
|
else if (keys_pressed & KEY_DOWN)
|
|
{
|
|
if (myConfig.stretch_x < 0x0100) REG_BG3PA = ++myConfig.stretch_x;
|
|
}
|
|
else if (keys_pressed & KEY_RIGHT)
|
|
{
|
|
REG_BG3X = (++myConfig.offset_x) << 8;
|
|
}
|
|
else if (keys_pressed & KEY_LEFT)
|
|
{
|
|
REG_BG3X = (--myConfig.offset_x) << 8;
|
|
}
|
|
else if (keys_pressed & KEY_X)
|
|
{
|
|
myConfig.stretch_x = ((160 / 256) << 8) | (160 % 256);
|
|
myConfig.offset_x = 0;
|
|
REG_BG3PA = myConfig.stretch_x;
|
|
REG_BG3X = (myConfig.offset_x) << 8;
|
|
}
|
|
else if ((keys_pressed & KEY_B) || (keys_pressed & KEY_A))
|
|
{
|
|
bDone = true;
|
|
}
|
|
else if (keys_pressed & KEY_START)
|
|
{
|
|
extern void SaveConfig(bool bShow);
|
|
dsPrintValue(2,20,0, (char*)" SAVING CONFIGURATION ");
|
|
SaveConfig(FALSE);
|
|
WAITVBL;WAITVBL;WAITVBL;WAITVBL;
|
|
dsPrintValue(2,20,0, (char*)" ");
|
|
}
|
|
|
|
// If any values changed... output them.
|
|
if ((myConfig.stretch_x != last_stretch_x) || (myConfig.offset_x != last_offset_x))
|
|
{
|
|
last_stretch_x = myConfig.stretch_x;
|
|
last_offset_x = myConfig.offset_x;
|
|
sprintf(tmpStr, "STRETCH_X = 0x%04X", myConfig.stretch_x);
|
|
dsPrintValue(6, 11, 0, (char*)tmpStr);
|
|
sprintf(tmpStr, " OFFSET_X = %-5d", myConfig.offset_x);
|
|
dsPrintValue(6, 12, 0, (char*)tmpStr);
|
|
}
|
|
|
|
WAITVBL;WAITVBL;
|
|
}
|
|
}
|
|
|
|
#define MAIN_MENU_ITEMS 9
|
|
const char *main_menu[MAIN_MENU_ITEMS] =
|
|
{
|
|
"RESET EMULATOR",
|
|
"LOAD NEW GAME",
|
|
"GAME CONFIG",
|
|
"GAME SCORES",
|
|
"SAVE/RESTORE STATE",
|
|
"GAME MANUAL",
|
|
"SCREEN STRETCH",
|
|
"QUIT EMULATOR",
|
|
"EXIT THIS MENU",
|
|
};
|
|
|
|
|
|
int menu_entry(void)
|
|
{
|
|
UINT8 current_entry = 0;
|
|
extern int bg0, bg0b, bg1b;
|
|
char bDone = 0;
|
|
|
|
decompress(bgHighScoreTiles, bgGetGfxPtr(bg0b), LZ77Vram);
|
|
decompress(bgHighScoreMap, (void*) bgGetMapPtr(bg0b), LZ77Vram);
|
|
dmaCopy((void *) bgHighScorePal,(u16*) BG_PALETTE_SUB,256*2);
|
|
unsigned short dmaVal = *(bgGetMapPtr(bg1b) +31*32);
|
|
dmaFillWords(dmaVal | (dmaVal<<16),(void*) bgGetMapPtr(bg1b),32*24*2);
|
|
swiWaitForVBlank();
|
|
dsPrintValue(8,3,0, (char*)"MAIN MENU");
|
|
dsPrintValue(4,20,0, (char*)"PRESS UP/DOWN AND A=SELECT");
|
|
|
|
for (int i=0; i<MAIN_MENU_ITEMS; i++)
|
|
{
|
|
dsPrintValue(8,5+i, (i==0 ? 1:0), (char*)main_menu[i]);
|
|
}
|
|
|
|
int last_keys_pressed = -1;
|
|
while (!bDone)
|
|
{
|
|
int keys_pressed = keysCurrent();
|
|
|
|
if (keys_pressed != last_keys_pressed)
|
|
{
|
|
last_keys_pressed = keys_pressed;
|
|
if (keys_pressed & KEY_DOWN)
|
|
{
|
|
dsPrintValue(8,5+current_entry, 0, (char*)main_menu[current_entry]);
|
|
if (current_entry < (MAIN_MENU_ITEMS-1)) current_entry++; else current_entry=0;
|
|
dsPrintValue(8,5+current_entry, 1, (char*)main_menu[current_entry]);
|
|
}
|
|
if (keys_pressed & KEY_UP)
|
|
{
|
|
dsPrintValue(8,5+current_entry, 0, (char*)main_menu[current_entry]);
|
|
if (current_entry > 0) current_entry--; else current_entry=(MAIN_MENU_ITEMS-1);
|
|
dsPrintValue(8,5+current_entry, 1, (char*)main_menu[current_entry]);
|
|
}
|
|
if (keys_pressed & KEY_A)
|
|
{
|
|
switch (current_entry)
|
|
{
|
|
case 0:
|
|
return OVL_META_RESET;
|
|
break;
|
|
case 1:
|
|
return OVL_META_LOAD;
|
|
break;
|
|
case 2:
|
|
return OVL_META_CONFIG;
|
|
break;
|
|
case 3:
|
|
return OVL_META_SCORES;
|
|
break;
|
|
case 4:
|
|
return OVL_META_STATE;
|
|
break;
|
|
case 5:
|
|
return OVL_META_MANUAL;
|
|
break;
|
|
case 6:
|
|
return OVL_META_STRETCH;
|
|
break;
|
|
case 7:
|
|
return OVL_META_QUIT;
|
|
break;
|
|
case 8:
|
|
bDone=1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (keys_pressed & KEY_B)
|
|
{
|
|
bDone=1;
|
|
}
|
|
swiWaitForVBlank();
|
|
}
|
|
}
|
|
return OVL_MAX;
|
|
}
|
|
|
|
char newFile[256];
|
|
void ds_handle_meta(int meta_key)
|
|
{
|
|
if (meta_key == OVL_MAX) return;
|
|
|
|
// -------------------------------------------------------------------
|
|
// On the way in, make sure no keys are pressed before continuing...
|
|
// -------------------------------------------------------------------
|
|
while (keysCurrent())
|
|
{
|
|
WAITVBL;
|
|
}
|
|
switch (meta_key)
|
|
{
|
|
case OVL_META_RESET:
|
|
if (bFirstGameLoaded)
|
|
{
|
|
currentEmu->Reset();
|
|
// And put the Sound Fifo back at the start...
|
|
bStartSoundFifo = true;
|
|
|
|
// Make sure we're starting fresh...
|
|
reset_emu_frames();
|
|
}
|
|
break;
|
|
|
|
case OVL_META_LOAD:
|
|
fifoSendValue32(FIFO_USER_01,(1<<16) | (0) | SOUND_SET_VOLUME);
|
|
if (dsWaitForRom(newFile))
|
|
{
|
|
if (LoadCart(newFile))
|
|
{
|
|
dsInitPalette();
|
|
}
|
|
else
|
|
{
|
|
dsPrintValue(0,1,0, (char*) "UNKNOWN GAME ");
|
|
}
|
|
}
|
|
bStartSoundFifo = true;
|
|
break;
|
|
|
|
case OVL_META_CONFIG:
|
|
fifoSendValue32(FIFO_USER_01,(1<<16) | (0) | SOUND_SET_VOLUME);
|
|
dsChooseOptions();
|
|
bStartSoundFifo = true;
|
|
reset_emu_frames();
|
|
dsInitPalette();
|
|
WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;
|
|
break;
|
|
|
|
case OVL_META_SCORES:
|
|
fifoSendValue32(FIFO_USER_01,(1<<16) | (0) | SOUND_SET_VOLUME);
|
|
if (currentRip != NULL)
|
|
{
|
|
highscore_display(currentRip->GetCRC());
|
|
dsShowScreenMain(false);
|
|
WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;
|
|
}
|
|
bStartSoundFifo = true;
|
|
break;
|
|
|
|
case OVL_META_STATE:
|
|
fifoSendValue32(FIFO_USER_01,(1<<16) | (0) | SOUND_SET_VOLUME);
|
|
if (currentRip != NULL)
|
|
{
|
|
savestate_entry();
|
|
dsShowScreenMain(false);
|
|
WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;
|
|
}
|
|
bStartSoundFifo = true;
|
|
break;
|
|
|
|
case OVL_META_MENU:
|
|
fifoSendValue32(FIFO_USER_01,(1<<16) | (0) | SOUND_SET_VOLUME);
|
|
if (currentRip != NULL)
|
|
{
|
|
ds_handle_meta(menu_entry());
|
|
dsShowScreenMain(false);
|
|
WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;
|
|
}
|
|
bStartSoundFifo = true;
|
|
break;
|
|
|
|
case OVL_META_SWITCH:
|
|
myConfig.controller_type = 1-myConfig.controller_type;
|
|
break;
|
|
|
|
case OVL_META_MANUAL:
|
|
fifoSendValue32(FIFO_USER_01,(1<<16) | (0) | SOUND_SET_VOLUME);
|
|
if (currentRip != NULL)
|
|
{
|
|
dsShowManual();
|
|
dsShowScreenMain(false);
|
|
WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;
|
|
}
|
|
bStartSoundFifo = true;
|
|
break;
|
|
|
|
case OVL_META_STRETCH:
|
|
fifoSendValue32(FIFO_USER_01,(1<<16) | (0) | SOUND_SET_VOLUME);
|
|
if (currentRip != NULL)
|
|
{
|
|
HandleScreenStretch();
|
|
dsShowScreenMain(false);
|
|
WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;
|
|
}
|
|
bStartSoundFifo = true;
|
|
break;
|
|
|
|
case OVL_META_QUIT:
|
|
fifoSendValue32(FIFO_USER_01,(1<<16) | (0) | SOUND_SET_VOLUME);
|
|
if (dsWaitOnQuit()){ runState = Quit; }
|
|
bStartSoundFifo = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ITCM_CODE void pollInputs(void)
|
|
{
|
|
UINT16 ctrl_disc, ctrl_keys, ctrl_side;
|
|
extern int ds_key_input[3][16]; // Set to '1' if pressed... 0 if released
|
|
extern int ds_disc_input[3][16]; // Set to '1' if pressed... 0 if released.
|
|
unsigned short keys_pressed = keysCurrent();
|
|
static short last_pressed = -1;
|
|
|
|
for (int j=0; j<3; j++)
|
|
{
|
|
for (int i=0; i<15; i++) ds_key_input[j][i] = 0;
|
|
for (int i=0; i<16; i++) ds_disc_input[j][i] = 0;
|
|
}
|
|
|
|
// Check for Dual Action
|
|
if (myConfig.controller_type == 2) // Standard Dual-Action (disc and side buttons on controller #1... keypad from controller #2)
|
|
{
|
|
ctrl_disc = 0;
|
|
ctrl_side = 0;
|
|
ctrl_keys = 1;
|
|
}
|
|
else if (myConfig.controller_type == 3) // Same as #2 above except side-buttons use controller #2
|
|
{
|
|
ctrl_disc = 0;
|
|
ctrl_side = 1;
|
|
ctrl_keys = 1;
|
|
}
|
|
else
|
|
{
|
|
ctrl_disc = myConfig.controller_type;
|
|
ctrl_side = myConfig.controller_type;
|
|
ctrl_keys = myConfig.controller_type;
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// Handle 8 directions on keypad... best we can do with the d-pad
|
|
// unless there is a custom .ovl overlay file mapping the disc.
|
|
// ---------------------------------------------------------------
|
|
|
|
if (myConfig.dpad_config == 0) // Normal handling
|
|
{
|
|
if (keys_pressed & KEY_UP)
|
|
{
|
|
if (keys_pressed & KEY_RIGHT) ds_disc_input[ctrl_disc][2] = 1;
|
|
else if (keys_pressed & KEY_LEFT) ds_disc_input[ctrl_disc][14] = 1;
|
|
else ds_disc_input[ctrl_disc][0] = 1;
|
|
}
|
|
else if (keys_pressed & KEY_DOWN)
|
|
{
|
|
if (keys_pressed & KEY_RIGHT) ds_disc_input[ctrl_disc][6] = 1;
|
|
else if (keys_pressed & KEY_LEFT) ds_disc_input[ctrl_disc][10] = 1;
|
|
else ds_disc_input[ctrl_disc][8] = 1;
|
|
}
|
|
else if (keys_pressed & KEY_RIGHT)
|
|
{
|
|
ds_disc_input[ctrl_disc][4] = 1;
|
|
}
|
|
else if (keys_pressed & KEY_LEFT)
|
|
{
|
|
ds_disc_input[ctrl_disc][12] = 1;
|
|
}
|
|
}
|
|
else if (myConfig.dpad_config == 1) // Reverse Left/Right
|
|
{
|
|
if (keys_pressed & KEY_UP)
|
|
{
|
|
if (keys_pressed & KEY_RIGHT) ds_disc_input[ctrl_disc][14] = 1;
|
|
else if (keys_pressed & KEY_LEFT) ds_disc_input[ctrl_disc][2] = 1;
|
|
else ds_disc_input[ctrl_disc][0] = 1;
|
|
}
|
|
else if (keys_pressed & KEY_DOWN)
|
|
{
|
|
if (keys_pressed & KEY_RIGHT) ds_disc_input[ctrl_disc][10] = 1;
|
|
else if (keys_pressed & KEY_LEFT) ds_disc_input[ctrl_disc][6] = 1;
|
|
else ds_disc_input[ctrl_disc][8] = 1;
|
|
}
|
|
else if (keys_pressed & KEY_RIGHT)
|
|
{
|
|
ds_disc_input[ctrl_disc][12] = 1;
|
|
}
|
|
else if (keys_pressed & KEY_LEFT)
|
|
{
|
|
ds_disc_input[ctrl_disc][4] = 1;
|
|
}
|
|
}
|
|
else if (myConfig.dpad_config == 2) // Reverse Up/Down
|
|
{
|
|
if (keys_pressed & KEY_UP)
|
|
{
|
|
if (keys_pressed & KEY_RIGHT) ds_disc_input[ctrl_disc][6] = 1;
|
|
else if (keys_pressed & KEY_LEFT) ds_disc_input[ctrl_disc][10] = 1;
|
|
else ds_disc_input[ctrl_disc][8] = 1;
|
|
}
|
|
else if (keys_pressed & KEY_DOWN)
|
|
{
|
|
if (keys_pressed & KEY_RIGHT) ds_disc_input[ctrl_disc][2] = 1;
|
|
else if (keys_pressed & KEY_LEFT) ds_disc_input[ctrl_disc][14] = 1;
|
|
else ds_disc_input[ctrl_disc][0] = 1;
|
|
}
|
|
else if (keys_pressed & KEY_RIGHT)
|
|
{
|
|
ds_disc_input[ctrl_disc][4] = 1;
|
|
}
|
|
else if (keys_pressed & KEY_LEFT)
|
|
{
|
|
ds_disc_input[ctrl_disc][12] = 1;
|
|
}
|
|
}
|
|
else if (myConfig.dpad_config == 3) // Diagnoals
|
|
{
|
|
if (keys_pressed & KEY_UP)
|
|
{
|
|
ds_disc_input[ctrl_disc][2] = 1;
|
|
}
|
|
else if (keys_pressed & KEY_DOWN)
|
|
{
|
|
ds_disc_input[ctrl_disc][10] = 1;
|
|
}
|
|
else if (keys_pressed & KEY_RIGHT)
|
|
{
|
|
ds_disc_input[ctrl_disc][6] = 1;
|
|
}
|
|
else if (keys_pressed & KEY_LEFT)
|
|
{
|
|
ds_disc_input[ctrl_disc][14] = 1;
|
|
}
|
|
}
|
|
else if (myConfig.dpad_config == 4) // Strict 4-way
|
|
{
|
|
if (keys_pressed & KEY_UP)
|
|
{
|
|
ds_disc_input[ctrl_disc][0] = 1;
|
|
}
|
|
else if (keys_pressed & KEY_DOWN)
|
|
{
|
|
ds_disc_input[ctrl_disc][8] = 1;
|
|
}
|
|
else if (keys_pressed & KEY_RIGHT)
|
|
{
|
|
ds_disc_input[ctrl_disc][4] = 1;
|
|
}
|
|
else if (keys_pressed & KEY_LEFT)
|
|
{
|
|
ds_disc_input[ctrl_disc][12] = 1;
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
// Now handle the main DS keys... these can be re-mapped to any Intellivision function
|
|
// -------------------------------------------------------------------------------------
|
|
if ((keys_pressed & KEY_A) && (keys_pressed & KEY_X))
|
|
{
|
|
if (myConfig.key_AX_map >= OVL_META_RESET)
|
|
{
|
|
if (last_pressed != keys_pressed) ds_handle_meta(myConfig.key_AX_map);
|
|
}
|
|
else if (myConfig.key_AX_map >= OVL_BTN_FIRE)
|
|
ds_key_input[ctrl_side][myConfig.key_AX_map] = 1;
|
|
else
|
|
ds_key_input[ctrl_keys][myConfig.key_AX_map] = 1;
|
|
}
|
|
else
|
|
if ((keys_pressed & KEY_X) && (keys_pressed & KEY_Y))
|
|
{
|
|
if (myConfig.key_XY_map >= OVL_META_RESET)
|
|
{
|
|
if (last_pressed != keys_pressed) ds_handle_meta(myConfig.key_XY_map);
|
|
}
|
|
else if (myConfig.key_XY_map >= OVL_BTN_FIRE)
|
|
ds_key_input[ctrl_side][myConfig.key_XY_map] = 1;
|
|
else
|
|
ds_key_input[ctrl_keys][myConfig.key_XY_map] = 1;
|
|
}
|
|
else
|
|
if ((keys_pressed & KEY_Y) && (keys_pressed & KEY_B))
|
|
{
|
|
if (myConfig.key_YB_map >= OVL_META_RESET)
|
|
{
|
|
if (last_pressed != keys_pressed) ds_handle_meta(myConfig.key_YB_map);
|
|
}
|
|
else if (myConfig.key_YB_map >= OVL_BTN_FIRE)
|
|
ds_key_input[ctrl_side][myConfig.key_YB_map] = 1;
|
|
else
|
|
ds_key_input[ctrl_keys][myConfig.key_YB_map] = 1;
|
|
}
|
|
else
|
|
if ((keys_pressed & KEY_B) && (keys_pressed & KEY_A))
|
|
{
|
|
if (myConfig.key_BA_map >= OVL_META_RESET)
|
|
{
|
|
if (last_pressed != keys_pressed) ds_handle_meta(myConfig.key_BA_map);
|
|
}
|
|
else if (myConfig.key_BA_map >= OVL_BTN_FIRE)
|
|
ds_key_input[ctrl_side][myConfig.key_BA_map] = 1;
|
|
else
|
|
ds_key_input[ctrl_keys][myConfig.key_BA_map] = 1;
|
|
}
|
|
else
|
|
{
|
|
if (keys_pressed & KEY_A)
|
|
{
|
|
if (myConfig.key_A_map >= OVL_META_RESET)
|
|
{
|
|
if (last_pressed != keys_pressed) ds_handle_meta(myConfig.key_A_map);
|
|
}
|
|
else if (myConfig.key_A_map >= OVL_BTN_FIRE)
|
|
ds_key_input[ctrl_side][myConfig.key_A_map] = 1;
|
|
else
|
|
ds_key_input[ctrl_keys][myConfig.key_A_map] = 1;
|
|
}
|
|
|
|
if (keys_pressed & KEY_B)
|
|
{
|
|
if (myConfig.key_B_map >= OVL_META_RESET)
|
|
{
|
|
if (last_pressed != keys_pressed) ds_handle_meta(myConfig.key_B_map);
|
|
}
|
|
else if (myConfig.key_B_map >= OVL_BTN_FIRE)
|
|
ds_key_input[ctrl_side][myConfig.key_B_map] = 1;
|
|
else
|
|
ds_key_input[ctrl_keys][myConfig.key_B_map] = 1;
|
|
}
|
|
|
|
if (keys_pressed & KEY_X)
|
|
{
|
|
if (myConfig.key_X_map >= OVL_META_RESET)
|
|
{
|
|
if (last_pressed != keys_pressed) ds_handle_meta(myConfig.key_X_map);
|
|
}
|
|
else if (myConfig.key_X_map >= OVL_BTN_FIRE)
|
|
ds_key_input[ctrl_side][myConfig.key_X_map] = 1;
|
|
else
|
|
ds_key_input[ctrl_keys][myConfig.key_X_map] = 1;
|
|
}
|
|
|
|
if (keys_pressed & KEY_Y)
|
|
{
|
|
if (myConfig.key_Y_map >= OVL_META_RESET)
|
|
{
|
|
if (last_pressed != keys_pressed) ds_handle_meta(myConfig.key_Y_map);
|
|
}
|
|
else if (myConfig.key_Y_map >= OVL_BTN_FIRE)
|
|
ds_key_input[ctrl_side][myConfig.key_Y_map] = 1;
|
|
else
|
|
ds_key_input[ctrl_keys][myConfig.key_Y_map] = 1;
|
|
}
|
|
}
|
|
|
|
if (keys_pressed & KEY_L)
|
|
{
|
|
if (myConfig.key_L_map >= OVL_META_RESET)
|
|
{
|
|
if (last_pressed != keys_pressed) ds_handle_meta(myConfig.key_L_map);
|
|
}
|
|
else if (myConfig.key_L_map >= OVL_BTN_FIRE)
|
|
ds_key_input[ctrl_side][myConfig.key_L_map] = 1;
|
|
else
|
|
ds_key_input[ctrl_keys][myConfig.key_L_map] = 1;
|
|
}
|
|
|
|
if (keys_pressed & KEY_R)
|
|
{
|
|
if (myConfig.key_R_map >= OVL_META_RESET)
|
|
{
|
|
if (last_pressed != keys_pressed) ds_handle_meta(myConfig.key_R_map);
|
|
}
|
|
else if (myConfig.key_R_map >= OVL_BTN_FIRE)
|
|
ds_key_input[ctrl_side][myConfig.key_R_map] = 1;
|
|
else
|
|
ds_key_input[ctrl_keys][myConfig.key_R_map] = 1;
|
|
}
|
|
|
|
if (keys_pressed & KEY_START)
|
|
{
|
|
if (myConfig.key_START_map >= OVL_META_RESET)
|
|
{
|
|
if (last_pressed != keys_pressed) ds_handle_meta(myConfig.key_START_map);
|
|
}
|
|
else if (myConfig.key_START_map >= OVL_BTN_FIRE)
|
|
ds_key_input[ctrl_side][myConfig.key_START_map] = 1;
|
|
else
|
|
ds_key_input[ctrl_keys][myConfig.key_START_map] = 1;
|
|
}
|
|
|
|
if (keys_pressed & KEY_SELECT)
|
|
{
|
|
if (myConfig.key_SELECT_map >= OVL_META_RESET)
|
|
{
|
|
if (last_pressed != keys_pressed) ds_handle_meta(myConfig.key_SELECT_map);
|
|
}
|
|
else if (myConfig.key_SELECT_map >= OVL_BTN_FIRE)
|
|
ds_key_input[ctrl_side][myConfig.key_SELECT_map] = 1;
|
|
else
|
|
ds_key_input[ctrl_keys][myConfig.key_SELECT_map] = 1;
|
|
}
|
|
|
|
last_pressed = keys_pressed;
|
|
|
|
// -----------------------------------------------------------------
|
|
// Now handle the on-screen Intellivision overlay and meta keys...
|
|
// -----------------------------------------------------------------
|
|
if (keys_pressed & KEY_TOUCH)
|
|
{
|
|
touchPosition touch;
|
|
touchRead(&touch);
|
|
|
|
#ifdef DEBUG_ENABLE
|
|
debugger_input(touch.px, touch.py);
|
|
#endif
|
|
// -----------------------------------------------------------
|
|
// Did we map any hotspots on the overlay to disc directions?
|
|
// -----------------------------------------------------------
|
|
if (bUseDiscOverlay)
|
|
{
|
|
for (int i=0; i < DISC_MAX; i++)
|
|
{
|
|
if (touch.px > myDisc[i].x1 && touch.px < myDisc[i].x2 && touch.py > myDisc[i].y1 && touch.py < myDisc[i].y2) ds_disc_input[ctrl_disc][i] = 1;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Handle the 12 keypad keys on the intellivision controller overlay...
|
|
// ----------------------------------------------------------------------
|
|
for (int i=0; i <= OVL_KEY_ENTER; i++)
|
|
{
|
|
if (touch.px > myOverlay[i].x1 && touch.px < myOverlay[i].x2 && touch.py > myOverlay[i].y1 && touch.py < myOverlay[i].y2) ds_key_input[ctrl_keys][i] = 1;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Handle the 3 side buttons (top=Fire... Left-Action and Right-Action)
|
|
// ----------------------------------------------------------------------
|
|
for (int i=OVL_BTN_FIRE; i<=OVL_BTN_R_ACT; i++)
|
|
{
|
|
if (touch.px > myOverlay[i].x1 && touch.px < myOverlay[i].x2 && touch.py > myOverlay[i].y1 && touch.py < myOverlay[i].y2) ds_key_input[ctrl_side][i] = 1;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------
|
|
// Handled "META" keys here... this includes things like RESET, LOAD, CONFIG, etc
|
|
// ----------------------------------------------------------------------------------
|
|
|
|
// RESET
|
|
if (touch.px > myOverlay[OVL_META_RESET].x1 && touch.px < myOverlay[OVL_META_RESET].x2 && touch.py > myOverlay[OVL_META_RESET].y1 && touch.py < myOverlay[OVL_META_RESET].y2)
|
|
{
|
|
ds_handle_meta(OVL_META_RESET);
|
|
}
|
|
// LOAD
|
|
else if (touch.px > myOverlay[OVL_META_LOAD].x1 && touch.px < myOverlay[OVL_META_LOAD].x2 && touch.py > myOverlay[OVL_META_LOAD].y1 && touch.py < myOverlay[OVL_META_LOAD].y2)
|
|
{
|
|
ds_handle_meta(OVL_META_LOAD);
|
|
}
|
|
// CONFIG
|
|
else if (touch.px > myOverlay[OVL_META_CONFIG].x1 && touch.px < myOverlay[OVL_META_CONFIG].x2 && touch.py > myOverlay[OVL_META_CONFIG].y1 && touch.py < myOverlay[OVL_META_CONFIG].y2)
|
|
{
|
|
ds_handle_meta(OVL_META_CONFIG);
|
|
}
|
|
// HIGHSCORES
|
|
else if (touch.px > myOverlay[OVL_META_SCORES].x1 && touch.px < myOverlay[OVL_META_SCORES].x2 && touch.py > myOverlay[OVL_META_SCORES].y1 && touch.py < myOverlay[OVL_META_SCORES].y2)
|
|
{
|
|
ds_handle_meta(OVL_META_SCORES);
|
|
}
|
|
// STATE
|
|
else if (touch.px > myOverlay[OVL_META_STATE].x1 && touch.px < myOverlay[OVL_META_STATE].x2 && touch.py > myOverlay[OVL_META_STATE].y1 && touch.py < myOverlay[OVL_META_STATE].y2)
|
|
{
|
|
ds_handle_meta(OVL_META_STATE);
|
|
}
|
|
// QUIT
|
|
else if (touch.px > myOverlay[OVL_META_QUIT].x1 && touch.px < myOverlay[OVL_META_QUIT].x2 && touch.py > myOverlay[OVL_META_QUIT].y1 && touch.py < myOverlay[OVL_META_QUIT].y2)
|
|
{
|
|
ds_handle_meta(OVL_META_QUIT);
|
|
}
|
|
// MENU
|
|
else if (touch.px > myOverlay[OVL_META_MENU].x1 && touch.px < myOverlay[OVL_META_MENU].x2 && touch.py > myOverlay[OVL_META_MENU].y1 && touch.py < myOverlay[OVL_META_MENU].y2)
|
|
{
|
|
ds_handle_meta(OVL_META_MENU);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
int target_frames[] = {60, 66, 72, 78, 84, 90, 999};
|
|
int target_frame_timing[] = {546, 496, 454, 420, 390, 364, 0};
|
|
|
|
ITCM_CODE void Run(char *initial_file)
|
|
{
|
|
// Setup 1 second timer for things like FPS
|
|
TIMER1_CR = 0;
|
|
TIMER1_DATA = 0;
|
|
TIMER1_CR=TIMER_ENABLE | TIMER_DIV_1024;
|
|
|
|
reset_emu_frames();
|
|
|
|
runState = Running;
|
|
|
|
// ------------------------------------------------------
|
|
// If we were passed in a file on the command line...
|
|
// ------------------------------------------------------
|
|
if (initial_file)
|
|
{
|
|
if (LoadCart(initial_file))
|
|
{
|
|
dsInitPalette();
|
|
}
|
|
}
|
|
|
|
while(runState == Running)
|
|
{
|
|
// If we have been told to start up the sound FIFO... do so here...
|
|
if (bStartSoundFifo)
|
|
{
|
|
dsInstallSoundEmuFIFO();
|
|
bStartSoundFifo = false;
|
|
reset_emu_frames();
|
|
}
|
|
|
|
// Time 1 frame...
|
|
while(TIMER0_DATA < (target_frame_timing[myConfig.target_fps]*(emu_frames+1)))
|
|
;
|
|
|
|
// Have we processed target (default 60) frames... start over...
|
|
if (++emu_frames >= target_frames[myConfig.target_fps])
|
|
{
|
|
reset_emu_frames();
|
|
}
|
|
|
|
//poll the input
|
|
pollInputs();
|
|
|
|
if (bInitEmulator) // If the inputs told us we loaded a new file... cleanup and start over...
|
|
{
|
|
InitializeEmulator();
|
|
bInitEmulator = false;
|
|
continue;
|
|
}
|
|
|
|
if (bFirstGameLoaded)
|
|
{
|
|
//run the emulation
|
|
currentEmu->Run();
|
|
|
|
// render the output
|
|
currentEmu->Render();
|
|
|
|
#ifdef DEBUG_ENABLE
|
|
debug_frames++;
|
|
#endif
|
|
}
|
|
|
|
if (TIMER1_DATA >= 32728) // 1000MS (1 sec)
|
|
{
|
|
char tmp[15];
|
|
TIMER1_CR = 0;
|
|
TIMER1_DATA = 0;
|
|
TIMER1_CR=TIMER_ENABLE | TIMER_DIV_1024;
|
|
oneSecTick=TRUE;
|
|
if ((frames_per_sec_calc > 0) && (myGlobalConfig.show_fps > 0))
|
|
{
|
|
if (frames_per_sec_calc==(target_frames[myConfig.target_fps]+1)) frames_per_sec_calc--;
|
|
tmp[0] = '0' + (frames_per_sec_calc/100);
|
|
tmp[1] = '0' + ((frames_per_sec_calc % 100) /10);
|
|
tmp[2] = '0' + ((frames_per_sec_calc % 100) %10);
|
|
tmp[3] = 0;
|
|
dsPrintValue(0,0,0,tmp);
|
|
}
|
|
frames_per_sec_calc=0;
|
|
}
|
|
|
|
#ifdef DEBUG_ENABLE
|
|
debugger();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void dsShowScreenMain(bool bFull)
|
|
{
|
|
// Init BG mode for 16 bits colors
|
|
if (bFull)
|
|
{
|
|
videoSetMode(MODE_0_2D | DISPLAY_BG0_ACTIVE );
|
|
videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE | DISPLAY_BG1_ACTIVE);
|
|
vramSetBankA(VRAM_A_MAIN_BG); vramSetBankC(VRAM_C_SUB_BG);
|
|
bg0 = bgInit(0, BgType_Text8bpp, BgSize_T_256x256, 31,0);
|
|
bg0b = bgInitSub(0, BgType_Text8bpp, BgSize_T_256x256, 31,0);
|
|
bg1b = bgInitSub(1, BgType_Text8bpp, BgSize_T_256x256, 30,0);
|
|
bgSetPriority(bg0b,1);bgSetPriority(bg1b,0);
|
|
|
|
decompress(bgTopTiles, bgGetGfxPtr(bg0), LZ77Vram);
|
|
decompress(bgTopMap, (void*) bgGetMapPtr(bg0), LZ77Vram);
|
|
dmaCopy((void *) bgTopPal,(u16*) BG_PALETTE,256*2);
|
|
}
|
|
|
|
// Now show the bottom screen - usualy some form of overlay...
|
|
#ifdef DEBUG_ENABLE
|
|
show_debug_overlay();
|
|
#else
|
|
show_overlay();
|
|
#endif
|
|
|
|
}
|
|
|
|
void dsMainLoop(char *initial_file)
|
|
{
|
|
// -----------------------------------------------------------------------------------------
|
|
// Eventually these will be used to write to the DS screen and produce DS audio output...
|
|
// -----------------------------------------------------------------------------------------
|
|
videoBus = new VideoBusDS();
|
|
audioMixer = new AudioMixerDS();
|
|
|
|
FindAndLoadConfig();
|
|
dsShowScreenMain(true);
|
|
|
|
Run(initial_file);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// This is called very frequently (15,360 times per second) to fill the
|
|
// pipeline of sound values from the Audio Mixer into the Nintendo DS sound
|
|
// buffer which will be processed in the background by the ARM 7 processor.
|
|
// ---------------------------------------------------------------------------
|
|
#define ARM7_XFER_BUFFER_SIZE (4096)
|
|
UINT16 audio_arm7_xfer_buffer[ARM7_XFER_BUFFER_SIZE];
|
|
UINT32* aptr __attribute__((section(".dtcm"))) = (UINT32*) (&audio_arm7_xfer_buffer[0] + 0xA000000/2);
|
|
UINT32* sptr __attribute__((section(".dtcm"))) = (UINT32*) (&audio_arm7_xfer_buffer[0] + 0xA000000/2);
|
|
UINT32* eptr __attribute__((section(".dtcm"))) = (UINT32*) (&audio_arm7_xfer_buffer[ARM7_XFER_BUFFER_SIZE] + 0xA000000/2);
|
|
UINT16 myCurrentSampleIdx16 __attribute__((section(".dtcm"))) = 0;
|
|
UINT32 lastSample __attribute__((section(".dtcm"))) = 0;
|
|
UINT8 myCurrentSampleIdx8 __attribute__((section(".dtcm"))) = 0;
|
|
|
|
ITCM_CODE void VsoundHandlerDSi(void)
|
|
{
|
|
// If there is a fresh sample...
|
|
if (myCurrentSampleIdx8 != currentSampleIdx8)
|
|
{
|
|
if ((UINT8)(myCurrentSampleIdx8+1) != currentSampleIdx8)
|
|
{
|
|
lastSample = *((UINT32*)&audio_mixer_buffer[myCurrentSampleIdx8++]);
|
|
myCurrentSampleIdx8++;
|
|
}
|
|
}
|
|
*aptr++ = lastSample;
|
|
if (aptr == eptr) aptr = sptr;
|
|
}
|
|
|
|
ITCM_CODE void VsoundHandler(void)
|
|
{
|
|
// If there is a fresh sample...
|
|
if (myCurrentSampleIdx16 != currentSampleIdx16)
|
|
{
|
|
if ((UINT16)(myCurrentSampleIdx16+1) != currentSampleIdx16)
|
|
{
|
|
lastSample = *((UINT32*)&audio_mixer_buffer[myCurrentSampleIdx16++]);
|
|
if (++myCurrentSampleIdx16 == SOUND_SIZE) myCurrentSampleIdx16=0;
|
|
}
|
|
}
|
|
*aptr++ = lastSample;
|
|
if (aptr == eptr) aptr = sptr;
|
|
}
|
|
|
|
UINT8 b_dsi_mode = true;
|
|
void dsInstallSoundEmuFIFO(void)
|
|
{
|
|
// Clear out the sound buffers...
|
|
currentSampleIdx8 = 0;
|
|
currentSampleIdx16 = 0;
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// We are going to move out the memory access to the non-cached mirros since
|
|
// this audio buffer is shared between ARM7 and ARM9 and we want to ensure
|
|
// that the data is never cached as we want the ARM7 to have updated values.
|
|
// -----------------------------------------------------------------------------
|
|
if (isDSiMode())
|
|
{
|
|
b_dsi_mode = true;
|
|
sptr = (UINT32*) (&audio_arm7_xfer_buffer[0] + 0xA000000/2);
|
|
eptr = (UINT32*) (&audio_arm7_xfer_buffer[ARM7_XFER_BUFFER_SIZE] + 0xA000000/2);
|
|
}
|
|
else
|
|
{
|
|
b_dsi_mode = false;
|
|
sptr = (UINT32*) (&audio_arm7_xfer_buffer[0] + 0x00400000/2);
|
|
eptr = (UINT32*) (&audio_arm7_xfer_buffer[ARM7_XFER_BUFFER_SIZE] + 0x00400000/2);
|
|
}
|
|
|
|
aptr = sptr;
|
|
memset(audio_arm7_xfer_buffer, 0x00, ARM7_XFER_BUFFER_SIZE*sizeof(UINT16));
|
|
memset(audio_mixer_buffer, 0x00, 256 * sizeof(UINT16));
|
|
|
|
fifoSendValue32(FIFO_USER_01,(1<<16) | SOUND_KILL);
|
|
swiWaitForVBlank();swiWaitForVBlank(); // Wait 2 vertical blanks... that's enough for the ARM7 to stop...
|
|
|
|
FifoMessage msg;
|
|
msg.SoundPlay.data = audio_arm7_xfer_buffer;
|
|
msg.SoundPlay.freq = mySoundFrequency;
|
|
msg.SoundPlay.volume = SOUND_VOLUME;
|
|
msg.SoundPlay.pan = 64;
|
|
msg.SoundPlay.loop = 1;
|
|
msg.SoundPlay.format = ((1)<<4) | SoundFormat_16Bit;
|
|
msg.SoundPlay.loopPoint = 0;
|
|
msg.SoundPlay.dataSize = (ARM7_XFER_BUFFER_SIZE*sizeof(UINT16)) >> 2;
|
|
msg.type = EMUARM7_PLAY_SND;
|
|
fifoSendDatamsg(FIFO_USER_01, sizeof(msg), (u8*)&msg);
|
|
|
|
swiWaitForVBlank();swiWaitForVBlank(); // Wait 2 vertical blanks... that's enough for the ARM7 to start chugging...
|
|
|
|
// Now setup to feed the audio mixer buffer into the ARM7 core via shared memory
|
|
TIMER2_DATA = TIMER_FREQ((mySoundFrequency/2)+2);
|
|
TIMER2_CR = TIMER_DIV_1 | TIMER_IRQ_REQ | TIMER_ENABLE;
|
|
irqSet(IRQ_TIMER2, b_dsi_mode ? VsoundHandlerDSi:VsoundHandler);
|
|
|
|
if (myConfig.sound_clock_div != SOUND_DIV_DISABLE)
|
|
irqEnable(IRQ_TIMER2);
|
|
else
|
|
irqDisable(IRQ_TIMER2);
|
|
|
|
}
|
|
|
|
|
|
UINT32 muted_gamePalette[32] =
|
|
{
|
|
0x000000, 0x0021AD, 0xE03904, 0xCECE94,
|
|
0x1E4912, 0x01812E, 0xF7E64A, 0xFFFFFF,
|
|
0xA5ADA5, 0x51B7E5, 0xEF9C00, 0x424A08,
|
|
0xFF3173, 0x9A8AEF, 0x4AA552, 0x950457,
|
|
|
|
0x000000, 0x0021AD, 0xE03904, 0xCECE94,
|
|
0x1E4912, 0x01812E, 0xF7E64A, 0xFFFFFF,
|
|
0xA5ADA5, 0x51B7E5, 0xEF9C00, 0x424A08,
|
|
0xFF3173, 0x9A8AEF, 0x4AA552, 0x950457,
|
|
};
|
|
|
|
UINT32 bright_gamePalette[32] =
|
|
{
|
|
0x000000, 0x1438F7, 0xE35B0E, 0xCBF168,
|
|
0x009428, 0x07C200, 0xFFFF01, 0xFFFFFF,
|
|
0xC8C8C8, 0x23CEC3, 0xFD9918, 0x3A8A00,
|
|
0xF0463C, 0xD383FF, 0x7CED00, 0xB81178,
|
|
|
|
0x000000, 0x1438F7, 0xE35B0E, 0xCBF168,
|
|
0x009428, 0x07C200, 0xFFFF01, 0xFFFFFF,
|
|
0xC8C8C8, 0x23CEC3, 0xFD9918, 0x3A8A00,
|
|
0xF0463C, 0xD383FF, 0x7CED00, 0xB81178,
|
|
};
|
|
|
|
UINT32 pal_gamePalette[32] =
|
|
{
|
|
0x000000, 0x0075FF, 0xFF4C39, 0xD1B951,
|
|
0x09B900, 0x30DF10, 0xFFE501, 0xFFFFFF,
|
|
0x8C8C8C, 0x28E5C0, 0xFFA02E, 0x646700,
|
|
0xFF29FF, 0x8C8FFF, 0x7CED00, 0xC42BFC,
|
|
|
|
0x000000, 0x0075FF, 0xFF4C39, 0xD1B951,
|
|
0x09B900, 0x30DF10, 0xFFE501, 0xFFFFFF,
|
|
0x8C8C8C, 0x28E5C0, 0xFFA02E, 0x646700,
|
|
0xFF29FF, 0x8C8FFF, 0x7CED00, 0xC42BFC,
|
|
};
|
|
|
|
|
|
UINT32 default_Palette[32] =
|
|
{
|
|
// Optmized
|
|
0x000000, 0x002DFF, 0xFF3D10, 0xC8D271,
|
|
0x386B3F, 0x00A756, 0xFAEA50, 0xFFFFFF,
|
|
0x9B9DA1, 0x24B8FF, 0xFFB41F, 0x3D5A02,
|
|
0xFF4E57, 0xA496FF, 0x75CC80, 0xB51A58,
|
|
|
|
0x000000, 0x002DFF, 0xFF3D10, 0xC8D271,
|
|
0x386B3F, 0x00A756, 0xFAEA50, 0xFFFFFF,
|
|
0x9B9DA1, 0x24B8FF, 0xFFB41F, 0x3D5A02,
|
|
0xFF4E57, 0xA496FF, 0x75CC80, 0xB51A58,
|
|
};
|
|
|
|
UINT32 custom_Palette[32] =
|
|
{
|
|
// Optmized
|
|
0x000000, 0x002DFF, 0xFF3D10, 0xC8D271,
|
|
0x386B3F, 0x00A756, 0xFAEA50, 0xFFFFFF,
|
|
0x9B9DA1, 0x24B8FF, 0xFFB41F, 0x3D5A02,
|
|
0xFF4E57, 0xA496FF, 0x75CC80, 0xB51A58,
|
|
|
|
0x000000, 0x002DFF, 0xFF3D10, 0xC8D271,
|
|
0x386B3F, 0x00A756, 0xFAEA50, 0xFFFFFF,
|
|
0x9B9DA1, 0x24B8FF, 0xFFB41F, 0x3D5A02,
|
|
0xFF4E57, 0xA496FF, 0x75CC80, 0xB51A58,
|
|
};
|
|
|
|
|
|
const INT8 brightness[] = {0, -3, -6, -9};
|
|
void dsInitPalette(void)
|
|
{
|
|
static UINT8 bFirstTime = TRUE;
|
|
|
|
if (bFirstTime)
|
|
{
|
|
// Load Custom Palette (if it exists)
|
|
FILE *fp;
|
|
fp = fopen("/data/NINTV-DS.PAL", "r");
|
|
if (fp != NULL)
|
|
{
|
|
UINT8 pal_idx=0;
|
|
while (!feof(fp))
|
|
{
|
|
fgets(line, 255, fp);
|
|
if (!feof(fp))
|
|
{
|
|
if (strstr(line, "#") != NULL)
|
|
{
|
|
char *ptr = line;
|
|
while (*ptr == ' ' || *ptr == '#') ptr++;
|
|
custom_Palette[pal_idx] = strtoul(ptr, &ptr, 16);
|
|
custom_Palette[pal_idx+16] = custom_Palette[pal_idx];
|
|
if (pal_idx < 16) pal_idx++;
|
|
}
|
|
}
|
|
}
|
|
fclose(fp);
|
|
}
|
|
bFirstTime = FALSE;
|
|
}
|
|
if (!bFirstGameLoaded) return;
|
|
|
|
// Init DS Specific palette for the Intellivision (16 colors...)
|
|
for(int i = 0; i < 256; i++)
|
|
{
|
|
unsigned char r, g, b;
|
|
|
|
switch (myConfig.palette)
|
|
{
|
|
case 1: // MUTED
|
|
r = (unsigned char) ((muted_gamePalette[i%32] & 0x00ff0000) >> 19);
|
|
g = (unsigned char) ((muted_gamePalette[i%32] & 0x0000ff00) >> 11);
|
|
b = (unsigned char) ((muted_gamePalette[i%32] & 0x000000ff) >> 3);
|
|
break;
|
|
case 2: // BRIGHT
|
|
r = (unsigned char) ((bright_gamePalette[i%32] & 0x00ff0000) >> 19);
|
|
g = (unsigned char) ((bright_gamePalette[i%32] & 0x0000ff00) >> 11);
|
|
b = (unsigned char) ((bright_gamePalette[i%32] & 0x000000ff) >> 3);
|
|
break;
|
|
case 3: // PAL
|
|
r = (unsigned char) ((pal_gamePalette[i%32] & 0x00ff0000) >> 19);
|
|
g = (unsigned char) ((pal_gamePalette[i%32] & 0x0000ff00) >> 11);
|
|
b = (unsigned char) ((pal_gamePalette[i%32] & 0x000000ff) >> 3);
|
|
break;
|
|
case 4: // CUSTOM
|
|
r = (unsigned char) ((custom_Palette[i%32] & 0x00ff0000) >> 19);
|
|
g = (unsigned char) ((custom_Palette[i%32] & 0x0000ff00) >> 11);
|
|
b = (unsigned char) ((custom_Palette[i%32] & 0x000000ff) >> 3);
|
|
break;
|
|
default:
|
|
r = (unsigned char) ((default_Palette[i%32] & 0x00ff0000) >> 19);
|
|
g = (unsigned char) ((default_Palette[i%32] & 0x0000ff00) >> 11);
|
|
b = (unsigned char) ((default_Palette[i%32] & 0x000000ff) >> 3);
|
|
break;
|
|
}
|
|
|
|
BG_PALETTE[i]=RGB15(r,g,b);
|
|
}
|
|
|
|
setBrightness(2, brightness[myGlobalConfig.brightness]); // Subscreen Brightness
|
|
}
|
|
|
|
void dsInitScreenMain(void)
|
|
{
|
|
// Init vbl and hbl func
|
|
vramSetBankD(VRAM_D_LCD ); // Not using this for video but 128K of faster RAM always useful! Mapped at 0x06860000 -
|
|
vramSetBankE(VRAM_E_LCD ); // Not using this for video but 64K of faster RAM always useful! Mapped at 0x06880000 -
|
|
vramSetBankF(VRAM_F_LCD ); // Not using this for video but 16K of faster RAM always useful! Mapped at 0x06890000 -
|
|
vramSetBankG(VRAM_G_LCD ); // Not using this for video but 16K of faster RAM always useful! Mapped at 0x06894000 -
|
|
vramSetBankH(VRAM_H_LCD ); // Not using this for video but 32K of faster RAM always useful! Mapped at 0x06898000 -
|
|
vramSetBankI(VRAM_I_LCD ); // Not using this for video but 16K of faster RAM always useful! Mapped at 0x068A0000 -
|
|
|
|
WAITVBL;
|
|
}
|
|
|
|
void dsShowScreenEmu(void)
|
|
{
|
|
videoSetMode(MODE_5_2D);
|
|
vramSetBankA(VRAM_A_MAIN_BG_0x06000000); // The main emulated (top screen) display.
|
|
vramSetBankB(VRAM_B_MAIN_BG_0x06060000); // This is where we will put our frame buffers to aid DMA Copy routines...
|
|
|
|
bg0 = bgInit(3, BgType_Bmp8, BgSize_B8_256x256, 0,0);
|
|
memset((void*)0x06000000, 0x00, 128*1024);
|
|
|
|
REG_BG3PA = myConfig.stretch_x;
|
|
REG_BG3PB = 0; REG_BG3PC = 0;
|
|
REG_BG3PD = ((100 / 100) << 8) | (100 % 100) ;
|
|
REG_BG3X = (myConfig.offset_x) << 8;
|
|
REG_BG3Y = 0;
|
|
|
|
dsInitPalette();
|
|
swiWaitForVBlank();
|
|
}
|
|
|
|
ITCM_CODE void dsInitTimer(void)
|
|
{
|
|
TIMER0_DATA=0;
|
|
TIMER0_CR=TIMER_ENABLE|TIMER_DIV_1024;
|
|
}
|
|
|
|
void dsFreeEmu(void)
|
|
{
|
|
// Stop timer of sound
|
|
TIMER2_CR=0; irqDisable(IRQ_TIMER2);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Load Rom
|
|
//----------------------------------------------------------------------------------
|
|
FICA_INTV intvromlist[512];
|
|
unsigned short int countintv=0, ucFicAct=0;
|
|
char szName[256];
|
|
char szName2[256];
|
|
|
|
|
|
// Find files (.int) available
|
|
int intvFilescmp (const void *c1, const void *c2)
|
|
{
|
|
FICA_INTV *p1 = (FICA_INTV *) c1;
|
|
FICA_INTV *p2 = (FICA_INTV *) c2;
|
|
|
|
if (p1->filename[0] == '.' && p2->filename[0] != '.')
|
|
return -1;
|
|
if (p2->filename[0] == '.' && p1->filename[0] != '.')
|
|
return 1;
|
|
if (p1->directory && !(p2->directory))
|
|
return -1;
|
|
if (p2->directory && !(p1->directory))
|
|
return 1;
|
|
return strcasecmp (p1->filename, p2->filename);
|
|
}
|
|
|
|
static char filenametmp[255];
|
|
void intvFindFiles(void)
|
|
{
|
|
static bool bFirstTime = true;
|
|
DIR *pdir;
|
|
struct dirent *pent;
|
|
|
|
countintv = 0;
|
|
|
|
// First time in we use the config setting to determine where we open files...
|
|
if (bFirstTime)
|
|
{
|
|
bFirstTime = false;
|
|
if (myGlobalConfig.rom_dir == 1)
|
|
{
|
|
chdir("/ROMS");
|
|
}
|
|
else if (myGlobalConfig.rom_dir == 2)
|
|
{
|
|
chdir("/ROMS/INTV");
|
|
}
|
|
}
|
|
|
|
pdir = opendir(".");
|
|
|
|
if (pdir) {
|
|
|
|
while (((pent=readdir(pdir))!=NULL))
|
|
{
|
|
strcpy(filenametmp,pent->d_name);
|
|
if (pent->d_type == DT_DIR)
|
|
{
|
|
if (!( (filenametmp[0] == '.') && (strlen(filenametmp) == 1)))
|
|
{
|
|
intvromlist[countintv].directory = true;
|
|
strcpy(intvromlist[countintv].filename,filenametmp);
|
|
countintv++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Filter out the BIOS files from the list...
|
|
if (strcasecmp(filenametmp, "grom.bin") == 0) continue;
|
|
if (strcasecmp(filenametmp, "exec.bin") == 0) continue;
|
|
if (strcasecmp(filenametmp, "ivoice.bin") == 0) continue;
|
|
if (strcasecmp(filenametmp, "ecs.bin") == 0) continue;
|
|
if (strstr(filenametmp, "[BIOS]") != NULL) continue;
|
|
if (strstr(filenametmp, "[bios]") != NULL) continue;
|
|
|
|
if (strlen(filenametmp)>4) {
|
|
if ( (strcasecmp(strrchr(filenametmp, '.'), ".int") == 0) ) {
|
|
intvromlist[countintv].directory = false;
|
|
strcpy(intvromlist[countintv].filename,filenametmp);
|
|
countintv++;
|
|
}
|
|
if ( (strcasecmp(strrchr(filenametmp, '.'), ".bin") == 0) ) {
|
|
intvromlist[countintv].directory = false;
|
|
strcpy(intvromlist[countintv].filename,filenametmp);
|
|
countintv++;
|
|
}
|
|
if ( (strcasecmp(strrchr(filenametmp, '.'), ".rom") == 0) ) {
|
|
intvromlist[countintv].directory = false;
|
|
strcpy(intvromlist[countintv].filename,filenametmp);
|
|
countintv++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
closedir(pdir);
|
|
}
|
|
if (countintv)
|
|
qsort (intvromlist, countintv, sizeof (FICA_INTV), intvFilescmp);
|
|
}
|
|
|
|
void dsDisplayFiles(unsigned int NoDebGame,u32 ucSel)
|
|
{
|
|
unsigned int ucBcl,ucGame;
|
|
|
|
// Display all games if possible
|
|
unsigned short dmaVal = *(bgGetMapPtr(bg1b) +31*32);
|
|
dmaFillWords(dmaVal | (dmaVal<<16),(void*) (bgGetMapPtr(bg1b)),32*24*2);
|
|
sprintf(szName,"%04d/%04d GAMES",(int)(1+ucSel+NoDebGame),countintv);
|
|
dsPrintValue(16-strlen(szName)/2,2,0,szName);
|
|
dsPrintValue(31,4,0,(char *) (NoDebGame>0 ? "<" : " "));
|
|
dsPrintValue(31,21,0,(char *) (NoDebGame+14<countintv ? ">" : " "));
|
|
sprintf(szName, "A=LOAD, X=JLP, Y=IVOICE, B=BACK");
|
|
dsPrintValue(16-strlen(szName)/2,23,0,szName);
|
|
for (ucBcl=0;ucBcl<17; ucBcl++) {
|
|
ucGame= ucBcl+NoDebGame;
|
|
if (ucGame < countintv)
|
|
{
|
|
strcpy(szName,intvromlist[ucGame].filename);
|
|
szName[29]='\0';
|
|
if (intvromlist[ucGame].directory)
|
|
{
|
|
szName[27]='\0';
|
|
sprintf(szName2,"[%s]",szName);
|
|
dsPrintValue(0,4+ucBcl,(ucSel == ucBcl ? 1 : 0),szName2);
|
|
}
|
|
else
|
|
{
|
|
dsPrintValue(1,4+ucBcl,(ucSel == ucBcl ? 1 : 0),szName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
unsigned int dsWaitForRom(char *chosen_filename)
|
|
{
|
|
bool bDone=false, bRet=false;
|
|
u32 ucHaut=0x00, ucBas=0x00,ucSHaut=0x00, ucSBas=0x00,romSelected= 0, firstRomDisplay=0,nbRomPerPage, uNbRSPage;
|
|
u32 uLenFic=0, ucFlip=0, ucFlop=0;
|
|
|
|
strcpy(chosen_filename, "tmpz");
|
|
intvFindFiles(); // Initial get of files...
|
|
|
|
decompress(bgFileSelTiles, bgGetGfxPtr(bg0b), LZ77Vram);
|
|
decompress(bgFileSelMap, (void*) bgGetMapPtr(bg0b), LZ77Vram);
|
|
dmaCopy((void *) bgFileSelPal,(u16*) BG_PALETTE_SUB,256*2);
|
|
unsigned short dmaVal = *(bgGetMapPtr(bg1b) +31*32);
|
|
dmaFillWords(dmaVal | (dmaVal<<16),(void*) bgGetMapPtr(bg1b),32*24*2);
|
|
|
|
nbRomPerPage = (countintv>=17 ? 17 : countintv);
|
|
uNbRSPage = (countintv>=5 ? 5 : countintv);
|
|
|
|
if (ucFicAct>countintv-nbRomPerPage)
|
|
{
|
|
firstRomDisplay=countintv-nbRomPerPage;
|
|
romSelected=ucFicAct-countintv+nbRomPerPage;
|
|
}
|
|
else
|
|
{
|
|
firstRomDisplay=ucFicAct;
|
|
romSelected=0;
|
|
}
|
|
dsDisplayFiles(firstRomDisplay,romSelected);
|
|
while (!bDone)
|
|
{
|
|
if (keysCurrent() & KEY_UP)
|
|
{
|
|
if (!ucHaut)
|
|
{
|
|
ucFicAct = (ucFicAct>0 ? ucFicAct-1 : countintv-1);
|
|
if (romSelected>uNbRSPage) { romSelected -= 1; }
|
|
else {
|
|
if (firstRomDisplay>0) { firstRomDisplay -= 1; }
|
|
else {
|
|
if (romSelected>0) { romSelected -= 1; }
|
|
else {
|
|
firstRomDisplay=countintv-nbRomPerPage;
|
|
romSelected=nbRomPerPage-1;
|
|
}
|
|
}
|
|
}
|
|
ucHaut=0x01;
|
|
dsDisplayFiles(firstRomDisplay,romSelected);
|
|
}
|
|
else {
|
|
|
|
ucHaut++;
|
|
if (ucHaut>10) ucHaut=0;
|
|
}
|
|
uLenFic=0; ucFlip=0; ucFlop=0;
|
|
}
|
|
else
|
|
{
|
|
ucHaut = 0;
|
|
}
|
|
if (keysCurrent() & KEY_DOWN)
|
|
{
|
|
if (!ucBas) {
|
|
ucFicAct = (ucFicAct< countintv-1 ? ucFicAct+1 : 0);
|
|
if (romSelected<uNbRSPage-1) { romSelected += 1; }
|
|
else {
|
|
if (firstRomDisplay<countintv-nbRomPerPage) { firstRomDisplay += 1; }
|
|
else {
|
|
if (romSelected<nbRomPerPage-1) { romSelected += 1; }
|
|
else {
|
|
firstRomDisplay=0;
|
|
romSelected=0;
|
|
}
|
|
}
|
|
}
|
|
ucBas=0x01;
|
|
dsDisplayFiles(firstRomDisplay,romSelected);
|
|
}
|
|
else
|
|
{
|
|
ucBas++;
|
|
if (ucBas>10) ucBas=0;
|
|
}
|
|
uLenFic=0; ucFlip=0; ucFlop=0;
|
|
}
|
|
else {
|
|
ucBas = 0;
|
|
}
|
|
if ((keysCurrent() & KEY_R) || (keysCurrent() & KEY_RIGHT))
|
|
{
|
|
if (!ucSBas)
|
|
{
|
|
ucFicAct = (ucFicAct< countintv-nbRomPerPage ? ucFicAct+nbRomPerPage : countintv-nbRomPerPage);
|
|
if (firstRomDisplay<countintv-nbRomPerPage) { firstRomDisplay += nbRomPerPage; }
|
|
else { firstRomDisplay = countintv-nbRomPerPage; }
|
|
if (ucFicAct == countintv-nbRomPerPage) romSelected = 0;
|
|
ucSBas=0x01;
|
|
dsDisplayFiles(firstRomDisplay,romSelected);
|
|
}
|
|
else
|
|
{
|
|
ucSBas++;
|
|
if (ucSBas>10) ucSBas=0;
|
|
}
|
|
uLenFic=0; ucFlip=0; ucFlop=0;
|
|
}
|
|
else {
|
|
ucSBas = 0;
|
|
}
|
|
if ((keysCurrent() & KEY_L) || (keysCurrent() & KEY_LEFT))
|
|
{
|
|
if (!ucSHaut)
|
|
{
|
|
ucFicAct = (ucFicAct> nbRomPerPage ? ucFicAct-nbRomPerPage : 0);
|
|
if (firstRomDisplay>nbRomPerPage) { firstRomDisplay -= nbRomPerPage; }
|
|
else { firstRomDisplay = 0; }
|
|
if (ucFicAct == 0) romSelected = 0;
|
|
if (romSelected > ucFicAct) romSelected = ucFicAct;
|
|
ucSHaut=0x01;
|
|
dsDisplayFiles(firstRomDisplay,romSelected);
|
|
}
|
|
else
|
|
{
|
|
ucSHaut++;
|
|
if (ucSHaut>10) ucSHaut=0;
|
|
}
|
|
uLenFic=0; ucFlip=0; ucFlop=0;
|
|
}
|
|
else {
|
|
ucSHaut = 0;
|
|
}
|
|
|
|
if ( keysCurrent() & KEY_B )
|
|
{
|
|
bDone=true;
|
|
while (keysCurrent() & KEY_B);
|
|
}
|
|
|
|
if (keysCurrent() & KEY_A || keysCurrent() & KEY_Y || keysCurrent() & KEY_X)
|
|
{
|
|
if (!intvromlist[ucFicAct].directory)
|
|
{
|
|
bRet=true;
|
|
bDone=true;
|
|
WAITVBL;
|
|
if (keysCurrent() & KEY_X) bUseJLP = true; else bUseJLP=false;
|
|
if (keysCurrent() & KEY_Y) bForceIvoice = true; else bForceIvoice=false;
|
|
strcpy(chosen_filename, intvromlist[ucFicAct].filename);
|
|
}
|
|
else
|
|
{
|
|
chdir(intvromlist[ucFicAct].filename);
|
|
intvFindFiles();
|
|
ucFicAct = 0;
|
|
nbRomPerPage = (countintv>=16 ? 16 : countintv);
|
|
uNbRSPage = (countintv>=5 ? 5 : countintv);
|
|
if (ucFicAct>countintv-nbRomPerPage) {
|
|
firstRomDisplay=countintv-nbRomPerPage;
|
|
romSelected=ucFicAct-countintv+nbRomPerPage;
|
|
}
|
|
else {
|
|
firstRomDisplay=ucFicAct;
|
|
romSelected=0;
|
|
}
|
|
dsDisplayFiles(firstRomDisplay,romSelected);
|
|
while (keysCurrent() & KEY_A);
|
|
}
|
|
}
|
|
|
|
// If the filename is too long... scroll it.
|
|
if (strlen(intvromlist[ucFicAct].filename) > 29)
|
|
{
|
|
ucFlip++;
|
|
if (ucFlip >= 15)
|
|
{
|
|
ucFlip = 0;
|
|
uLenFic++;
|
|
if ((uLenFic+29)>strlen(intvromlist[ucFicAct].filename))
|
|
{
|
|
ucFlop++;
|
|
if (ucFlop >= 15)
|
|
{
|
|
uLenFic=0;
|
|
ucFlop = 0;
|
|
}
|
|
else
|
|
uLenFic--;
|
|
}
|
|
strncpy(szName,intvromlist[ucFicAct].filename+uLenFic,29);
|
|
szName[29] = '\0';
|
|
dsPrintValue(1,4+romSelected,1,szName);
|
|
}
|
|
}
|
|
|
|
swiWaitForVBlank();
|
|
}
|
|
|
|
dsShowScreenMain(false);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
bool dsWaitOnQuit(void)
|
|
{
|
|
bool bRet=false, bDone=false;
|
|
unsigned int keys_pressed;
|
|
unsigned int posdeb=0;
|
|
char szName[32];
|
|
|
|
decompress(bgHighScoreTiles, bgGetGfxPtr(bg0b), LZ77Vram);
|
|
decompress(bgHighScoreMap, (void*) bgGetMapPtr(bg0b), LZ77Vram);
|
|
dmaCopy((void *) bgHighScorePal,(u16*) BG_PALETTE_SUB,256*2);
|
|
unsigned short dmaVal = *(bgGetMapPtr(bg1b) +31*32);
|
|
dmaFillWords(dmaVal | (dmaVal<<16),(void*) bgGetMapPtr(bg1b),32*24*2);
|
|
|
|
strcpy(szName,"Quit NINTV-DS?");
|
|
dsPrintValue(16-strlen(szName)/2,2,0,szName);
|
|
sprintf(szName,"%s","A TO CONFIRM, B TO GO BACK");
|
|
dsPrintValue(16-strlen(szName)/2,23,0,szName);
|
|
|
|
while(!bDone)
|
|
{
|
|
strcpy(szName," YES ");
|
|
dsPrintValue(5,10+0,(posdeb == 0 ? 1 : 0),szName);
|
|
strcpy(szName," NO ");
|
|
dsPrintValue(5,14+1,(posdeb == 2 ? 1 : 0),szName);
|
|
swiWaitForVBlank();
|
|
|
|
// Check pad
|
|
keys_pressed=keysCurrent();
|
|
if (keys_pressed & KEY_UP) {
|
|
if (posdeb) posdeb-=2;
|
|
}
|
|
if (keys_pressed & KEY_DOWN) {
|
|
if (posdeb<1) posdeb+=2;
|
|
}
|
|
if (keys_pressed & KEY_A) {
|
|
bRet = (posdeb ? false : true);
|
|
bDone = true;
|
|
}
|
|
if (keys_pressed & KEY_B) {
|
|
bDone = true;
|
|
}
|
|
}
|
|
|
|
dsShowScreenMain(false);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
// End of Line
|
|
|