more work. also, make archive shito somewhat better.
This commit is contained in:
parent
3383c396cd
commit
aa443c6bce
|
@ -479,11 +479,11 @@ void CartGame::SRAMWrite_FLASH(u32 addr, u8 val)
|
|||
u32 start_addr = addr + 0x10000 * SRAMFlashState.bank;
|
||||
memset((u8*)&SRAM[start_addr], 0xFF, 0x1000);
|
||||
|
||||
if (SRAMFile)
|
||||
/*if (SRAMFile)
|
||||
{
|
||||
fseek(SRAMFile, start_addr, SEEK_SET);
|
||||
fwrite((u8*)&SRAM[start_addr], 1, 0x1000, SRAMFile);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
SRAMFlashState.state = 0;
|
||||
SRAMFlashState.cmd = 0;
|
||||
|
@ -541,11 +541,11 @@ void CartGame::SRAMWrite_SRAM(u32 addr, u8 val)
|
|||
{
|
||||
*(u8*)&SRAM[addr] = val;
|
||||
|
||||
if (SRAMFile)
|
||||
/*if (SRAMFile)
|
||||
{
|
||||
fseek(SRAMFile, addr, SEEK_SET);
|
||||
fwrite((u8*)&SRAM[addr], 1, 1, SRAMFile);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1134,7 +1134,7 @@ u32 RunFrame()
|
|||
#endif
|
||||
SPU::TransferOutput();
|
||||
|
||||
NDSCart::FlushSRAMFile();
|
||||
//NDSCart::FlushSRAMFile();
|
||||
}
|
||||
|
||||
// In the context of TASes, frame count is traditionally the primary measure of emulated time,
|
||||
|
@ -1273,10 +1273,10 @@ void MicInputFrame(s16* data, int samples)
|
|||
return SPI_TSC::MicInputFrame(data, samples);
|
||||
}
|
||||
|
||||
int ImportSRAM(u8* data, u32 length)
|
||||
/*int ImportSRAM(u8* data, u32 length)
|
||||
{
|
||||
return NDSCart::ImportSRAM(data, length);
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
void Halt()
|
||||
|
|
|
@ -259,7 +259,7 @@ void SetLidClosed(bool closed);
|
|||
|
||||
void MicInputFrame(s16* data, int samples);
|
||||
|
||||
int ImportSRAM(u8* data, u32 length);
|
||||
//int ImportSRAM(u8* data, u32 length);
|
||||
|
||||
void ScheduleEvent(u32 id, bool periodic, s32 delay, void (*func)(u32), u32 param);
|
||||
void CancelEvent(u32 id);
|
||||
|
|
|
@ -934,18 +934,18 @@ void CartRetailNAND::DoSavestate(Savestate* file)
|
|||
BuildSRAMID();
|
||||
}
|
||||
|
||||
void CartRetailNAND::LoadSave(const char* path, u32 type)
|
||||
void CartRetailNAND::LoadSave(const u8* savedata, u32 savelen)
|
||||
{
|
||||
CartRetail::LoadSave(path, type);
|
||||
CartRetail::LoadSave(savedata, savelen);
|
||||
BuildSRAMID();
|
||||
}
|
||||
|
||||
int CartRetailNAND::ImportSRAM(const u8* data, u32 length)
|
||||
/*int CartRetailNAND::ImportSRAM(const u8* data, u32 length)
|
||||
{
|
||||
int ret = CartRetail::ImportSRAM(data, length);
|
||||
BuildSRAMID();
|
||||
return ret;
|
||||
}
|
||||
}*/
|
||||
|
||||
int CartRetailNAND::ROMCommandStart(u8* cmd, u8* data, u32 len)
|
||||
{
|
||||
|
|
|
@ -84,7 +84,7 @@ void Setup(const char* path, u8* buffer, u32 length)
|
|||
Buffer = buffer;
|
||||
Length = length;
|
||||
|
||||
if(SecondaryBuffer) delete[] SecondaryBuffer; // Delete secondary buffer, there might be previous state.
|
||||
if (SecondaryBuffer) delete[] SecondaryBuffer; // Delete secondary buffer, there might be previous state.
|
||||
|
||||
SecondaryBuffer = new u8[length];
|
||||
SecondaryBufferLength = length;
|
||||
|
|
|
@ -343,7 +343,7 @@ int LoadROM(const u8 *romdata, u32 romlength, const char *archivefilename, const
|
|||
|
||||
NDS::SetConsoleType(Config::ConsoleType);
|
||||
|
||||
if (slot == ROMSlot_NDS && NDS::LoadROM(romdata, romlength, SRAMPath[slot].c_str(), directboot))
|
||||
/* if (slot == ROMSlot_NDS && NDS::LoadROM(romdata, romlength, SRAMPath[slot].c_str(), directboot))
|
||||
{
|
||||
SavestateLoaded = false;
|
||||
|
||||
|
@ -363,7 +363,7 @@ int LoadROM(const u8 *romdata, u32 romlength, const char *archivefilename, const
|
|||
PrevSRAMPath[slot] = SRAMPath[slot]; // safety
|
||||
return Load_OK;
|
||||
}
|
||||
else
|
||||
else*/
|
||||
{
|
||||
ROMPath[slot] = oldpath;
|
||||
SRAMPath[slot] = oldsram;
|
||||
|
@ -423,7 +423,7 @@ int LoadROM(const char* file, int slot)
|
|||
|
||||
NDS::SetConsoleType(Config::ConsoleType);
|
||||
|
||||
if (slot == ROMSlot_NDS && NDS::LoadROM(ROMPath[slot].c_str(), SRAMPath[slot].c_str(), directboot))
|
||||
/*if (slot == ROMSlot_NDS && NDS::LoadROM(ROMPath[slot].c_str(), SRAMPath[slot].c_str(), directboot))
|
||||
{
|
||||
SavestateLoaded = false;
|
||||
|
||||
|
@ -443,7 +443,7 @@ int LoadROM(const char* file, int slot)
|
|||
PrevSRAMPath[slot] = SRAMPath[slot]; // safety
|
||||
return Load_OK;
|
||||
}
|
||||
else
|
||||
else*/
|
||||
{
|
||||
ROMPath[slot] = oldpath;
|
||||
SRAMPath[slot] = oldsram;
|
||||
|
@ -577,7 +577,7 @@ int Reset()
|
|||
{
|
||||
NDS::LoadBIOS();
|
||||
}
|
||||
else
|
||||
/*else
|
||||
{
|
||||
std::string ext = ROMPath[ROMSlot_NDS].substr(ROMPath[ROMSlot_NDS].length() - 4);
|
||||
std::transform(ext.begin(), ext.end(), ext.begin(), tolower);
|
||||
|
@ -611,7 +611,7 @@ int Reset()
|
|||
|
||||
bool ok = NDS::LoadROM(romdata, romlen, sramfilename, directboot);
|
||||
delete romdata;
|
||||
if (!ok)*/
|
||||
if (!ok)*-/
|
||||
return Load_ROMLoadError;
|
||||
}
|
||||
#endif
|
||||
|
@ -650,11 +650,11 @@ int Reset()
|
|||
|
||||
bool ok = NDS::LoadGBAROM(romdata, romlen, romfilename, SRAMPath[ROMSlot_GBA]);
|
||||
delete romdata;
|
||||
if (!ok)*/
|
||||
if (!ok)*-/
|
||||
return Load_ROMLoadError;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}*/
|
||||
|
||||
LoadCheats();
|
||||
|
||||
|
@ -735,7 +735,7 @@ bool LoadState(std::string filename)
|
|||
// TODO: how should this interact with custom paths?
|
||||
SRAMPath[ROMSlot_NDS] = filename + ".sav";
|
||||
|
||||
NDS::RelocateSave(SRAMPath[ROMSlot_NDS].c_str(), false);
|
||||
// NDS::RelocateSave(SRAMPath[ROMSlot_NDS].c_str(), false);
|
||||
}
|
||||
|
||||
bool loadedPartialGBAROM = false;
|
||||
|
@ -783,7 +783,7 @@ bool SaveState(std::string filename)
|
|||
// TODO: how should this interact with custom paths?
|
||||
SRAMPath[ROMSlot_NDS] = filename + ".sav";
|
||||
|
||||
NDS::RelocateSave(SRAMPath[ROMSlot_NDS].c_str(), true);
|
||||
// NDS::RelocateSave(SRAMPath[ROMSlot_NDS].c_str(), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -804,13 +804,13 @@ void UndoStateLoad()
|
|||
if (!ROMPath[ROMSlot_NDS].empty())
|
||||
{
|
||||
SRAMPath[ROMSlot_NDS] = PrevSRAMPath[ROMSlot_NDS];
|
||||
NDS::RelocateSave(SRAMPath[ROMSlot_NDS].c_str(), false);
|
||||
// NDS::RelocateSave(SRAMPath[ROMSlot_NDS].c_str(), false);
|
||||
}
|
||||
}
|
||||
|
||||
int ImportSRAM(const char* filename)
|
||||
{
|
||||
FILE* file = fopen(filename, "rb");
|
||||
/*FILE* file = fopen(filename, "rb");
|
||||
fseek(file, 0, SEEK_END);
|
||||
u32 size = ftell(file);
|
||||
u8* importData = new u8[size];
|
||||
|
@ -820,7 +820,8 @@ int ImportSRAM(const char* filename)
|
|||
|
||||
int diff = NDS::ImportSRAM(importData, size);
|
||||
delete[] importData;
|
||||
return diff;
|
||||
return diff;*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
void EnableCheats(bool enable)
|
||||
|
|
|
@ -17,22 +17,37 @@
|
|||
*/
|
||||
|
||||
#include "ArchiveUtil.h"
|
||||
#include "Platform.h"
|
||||
|
||||
namespace Archive
|
||||
{
|
||||
|
||||
QVector<QString> ListArchive(const char* path)
|
||||
#ifdef __WIN32__
|
||||
#define melon_archive_open(a, f, b) archive_read_open_filename_w(a, (const wchar_t*)f.utf16(), b)
|
||||
#else
|
||||
#define melon_archive_open(a, f, b) archive_read_open_filename(a, f.toUtf8().constData(), b)
|
||||
#endif // __WIN32__
|
||||
|
||||
bool compareCI(const QString& s1, const QString& s2)
|
||||
{
|
||||
return s1.toLower() < s2.toLower();
|
||||
}
|
||||
|
||||
QVector<QString> ListArchive(QString path)
|
||||
{
|
||||
struct archive *a;
|
||||
struct archive_entry *entry;
|
||||
int r;
|
||||
|
||||
QVector<QString> fileList = {"OK"};
|
||||
QVector<QString> fileList;
|
||||
|
||||
a = archive_read_new();
|
||||
|
||||
archive_read_support_filter_all(a);
|
||||
archive_read_support_format_all(a);
|
||||
r = archive_read_open_filename(a, path, 10240);
|
||||
|
||||
//r = archive_read_open_filename(a, path, 10240);
|
||||
r = melon_archive_open(a, path, 10240);
|
||||
if (r != ARCHIVE_OK)
|
||||
{
|
||||
return QVector<QString> {"Err"};
|
||||
|
@ -40,20 +55,28 @@ QVector<QString> ListArchive(const char* path)
|
|||
|
||||
while (archive_read_next_header(a, &entry) == ARCHIVE_OK)
|
||||
{
|
||||
fileList.push_back(archive_entry_pathname(entry));
|
||||
if (archive_entry_filetype(entry) != AE_IFREG)
|
||||
continue;
|
||||
|
||||
fileList.push_back(archive_entry_pathname_utf8(entry));
|
||||
archive_read_data_skip(a);
|
||||
}
|
||||
|
||||
archive_read_close(a);
|
||||
archive_read_free(a);
|
||||
|
||||
if (r != ARCHIVE_OK)
|
||||
{
|
||||
return QVector<QString> {"Err"};
|
||||
}
|
||||
|
||||
std::stable_sort(fileList.begin(), fileList.end(), compareCI);
|
||||
fileList.prepend("OK");
|
||||
|
||||
return fileList;
|
||||
}
|
||||
|
||||
QVector<QString> ExtractFileFromArchive(const char* path, const char* wantedFile, QByteArray *romBuffer)
|
||||
QVector<QString> ExtractFileFromArchive(QString path, QString wantedFile, QByteArray *romBuffer)
|
||||
{
|
||||
struct archive *a = archive_read_new();
|
||||
struct archive_entry *entry;
|
||||
|
@ -62,7 +85,8 @@ QVector<QString> ExtractFileFromArchive(const char* path, const char* wantedFile
|
|||
archive_read_support_format_all(a);
|
||||
archive_read_support_filter_all(a);
|
||||
|
||||
r = archive_read_open_filename(a, path, 10240);
|
||||
//r = archive_read_open_filename(a, path, 10240);
|
||||
r = melon_archive_open(a, path, 10240);
|
||||
if (r != ARCHIVE_OK)
|
||||
{
|
||||
return QVector<QString> {"Err"};
|
||||
|
@ -70,7 +94,7 @@ QVector<QString> ExtractFileFromArchive(const char* path, const char* wantedFile
|
|||
|
||||
while (archive_read_next_header(a, &entry) == ARCHIVE_OK)
|
||||
{
|
||||
if (strcmp(wantedFile, archive_entry_pathname(entry)) == 0)
|
||||
if (strcmp(wantedFile.toUtf8().constData(), archive_entry_pathname_utf8(entry)) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -35,9 +35,9 @@
|
|||
namespace Archive
|
||||
{
|
||||
|
||||
QVector<QString> ListArchive(const char* path);
|
||||
QVector<QString> ExtractFileFromArchive(const char* path, const char* wantedFile, QByteArray *romBuffer);
|
||||
u32 ExtractFileFromArchive(const char* path, const char* wantedFile, u8 **romdata);
|
||||
QVector<QString> ListArchive(QString path);
|
||||
QVector<QString> ExtractFileFromArchive(QString path, QString wantedFile, QByteArray *romBuffer);
|
||||
//u32 ExtractFileFromArchive(const char* path, const char* wantedFile, u8 **romdata);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ SET(SOURCES_QT_SDL
|
|||
font.h
|
||||
Platform.cpp
|
||||
QPathInput.h
|
||||
ROMLoader.cpp
|
||||
SaveManager.cpp
|
||||
|
||||
ArchiveUtil.h
|
||||
|
|
|
@ -0,0 +1,834 @@
|
|||
/*
|
||||
Copyright 2016-2021 Arisotura
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
melonDS is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation, either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#ifdef ARCHIVE_SUPPORT_ENABLED
|
||||
#include "ArchiveUtil.h"
|
||||
#endif
|
||||
#include "ROMLoader.h"
|
||||
#include "SharedConfig.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include "NDS.h"
|
||||
#include "DSi.h"
|
||||
#include "GBACart.h"
|
||||
|
||||
#include "AREngine.h"
|
||||
|
||||
|
||||
namespace ROMLoader
|
||||
{
|
||||
|
||||
std::string ROMPath [ROMSlot_MAX];
|
||||
std::string SRAMPath [ROMSlot_MAX];
|
||||
std::string PrevSRAMPath[ROMSlot_MAX]; // for savestate 'undo load'
|
||||
|
||||
std::string NDSROMExtension;
|
||||
|
||||
bool SavestateLoaded;
|
||||
|
||||
ARCodeFile* CheatFile;
|
||||
bool CheatsOn;
|
||||
|
||||
|
||||
void Init_ROM()
|
||||
{
|
||||
SavestateLoaded = false;
|
||||
|
||||
ROMPath[ROMSlot_NDS] = "";
|
||||
ROMPath[ROMSlot_GBA] = "";
|
||||
SRAMPath[ROMSlot_NDS] = "";
|
||||
SRAMPath[ROMSlot_GBA] = "";
|
||||
PrevSRAMPath[ROMSlot_NDS] = "";
|
||||
PrevSRAMPath[ROMSlot_GBA] = "";
|
||||
|
||||
CheatFile = nullptr;
|
||||
CheatsOn = false;
|
||||
}
|
||||
|
||||
void DeInit_ROM()
|
||||
{
|
||||
if (CheatFile)
|
||||
{
|
||||
delete CheatFile;
|
||||
CheatFile = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: currently, when failing to load a ROM for whatever reason, we attempt
|
||||
// to revert to the previous state and resume execution; this may not be a very
|
||||
// good thing, depending on what state the core was left in.
|
||||
// should we do a better state revert (via the savestate system)? completely stop?
|
||||
|
||||
void SetupSRAMPath(int slot)
|
||||
{
|
||||
SRAMPath[slot] = ROMPath[slot].substr(0, ROMPath[slot].length() - 3) + "sav";
|
||||
}
|
||||
|
||||
int VerifyDSBIOS()
|
||||
{
|
||||
FILE* f;
|
||||
long len;
|
||||
|
||||
if (!Config::ExternalBIOSEnable) return Load_OK;
|
||||
|
||||
f = Platform::OpenLocalFile(Config::BIOS9Path, "rb");
|
||||
if (!f) return Load_BIOS9Missing;
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
len = ftell(f);
|
||||
if (len != 0x1000)
|
||||
{
|
||||
fclose(f);
|
||||
return Load_BIOS9Bad;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
f = Platform::OpenLocalFile(Config::BIOS7Path, "rb");
|
||||
if (!f) return Load_BIOS7Missing;
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
len = ftell(f);
|
||||
if (len != 0x4000)
|
||||
{
|
||||
fclose(f);
|
||||
return Load_BIOS7Bad;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
return Load_OK;
|
||||
}
|
||||
|
||||
int VerifyDSiBIOS()
|
||||
{
|
||||
FILE* f;
|
||||
long len;
|
||||
|
||||
// TODO: check the first 32 bytes
|
||||
|
||||
f = Platform::OpenLocalFile(Config::DSiBIOS9Path, "rb");
|
||||
if (!f) return Load_DSiBIOS9Missing;
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
len = ftell(f);
|
||||
if (len != 0x10000)
|
||||
{
|
||||
fclose(f);
|
||||
return Load_DSiBIOS9Bad;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
f = Platform::OpenLocalFile(Config::DSiBIOS7Path, "rb");
|
||||
if (!f) return Load_DSiBIOS7Missing;
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
len = ftell(f);
|
||||
if (len != 0x10000)
|
||||
{
|
||||
fclose(f);
|
||||
return Load_DSiBIOS7Bad;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
return Load_OK;
|
||||
}
|
||||
|
||||
int VerifyDSFirmware()
|
||||
{
|
||||
FILE* f;
|
||||
long len;
|
||||
|
||||
if (!Config::ExternalBIOSEnable) return Load_FirmwareNotBootable;
|
||||
|
||||
f = Platform::OpenLocalFile(Config::FirmwarePath, "rb");
|
||||
if (!f) return Load_FirmwareNotBootable;
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
len = ftell(f);
|
||||
if (len == 0x20000)
|
||||
{
|
||||
// 128KB firmware, not bootable
|
||||
fclose(f);
|
||||
return Load_FirmwareNotBootable;
|
||||
}
|
||||
else if (len != 0x40000 && len != 0x80000)
|
||||
{
|
||||
fclose(f);
|
||||
return Load_FirmwareBad;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
return Load_OK;
|
||||
}
|
||||
|
||||
int VerifyDSiFirmware()
|
||||
{
|
||||
FILE* f;
|
||||
long len;
|
||||
|
||||
f = Platform::OpenLocalFile(Config::DSiFirmwarePath, "rb");
|
||||
if (!f) return Load_FirmwareMissing;
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
len = ftell(f);
|
||||
if (len != 0x20000)
|
||||
{
|
||||
// not 128KB
|
||||
// TODO: check whether those work
|
||||
fclose(f);
|
||||
return Load_FirmwareBad;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
return Load_OK;
|
||||
}
|
||||
|
||||
int SetupDSiNAND()
|
||||
{
|
||||
FILE* f;
|
||||
long len;
|
||||
|
||||
f = Platform::OpenLocalFile(Config::DSiNANDPath, "r+b");
|
||||
if (!f) return Load_DSiNANDMissing;
|
||||
|
||||
// TODO: some basic checks
|
||||
// check that it has the nocash footer, and all
|
||||
|
||||
DSi::SDMMCFile = f;
|
||||
|
||||
return Load_OK;
|
||||
}
|
||||
|
||||
void LoadCheats()
|
||||
{
|
||||
if (CheatFile)
|
||||
{
|
||||
delete CheatFile;
|
||||
CheatFile = nullptr;
|
||||
}
|
||||
|
||||
std::string filename;
|
||||
if (!ROMPath[ROMSlot_NDS].empty())
|
||||
{
|
||||
filename = ROMPath[ROMSlot_NDS].substr(0, ROMPath[ROMSlot_NDS].length() - 3) + "mch";
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = "firmware.mch";
|
||||
}
|
||||
|
||||
// TODO: add custom path here
|
||||
|
||||
// TODO: check for error (malformed cheat file, ...)
|
||||
CheatFile = new ARCodeFile(filename);
|
||||
|
||||
AREngine::SetCodeFile(CheatsOn ? CheatFile : nullptr);
|
||||
}
|
||||
|
||||
int LoadBIOS()
|
||||
{
|
||||
DSi::CloseDSiNAND();
|
||||
|
||||
int res;
|
||||
|
||||
res = VerifyDSBIOS();
|
||||
if (res != Load_OK) return res;
|
||||
|
||||
if (Config::ConsoleType == 1)
|
||||
{
|
||||
res = VerifyDSiBIOS();
|
||||
if (res != Load_OK) return res;
|
||||
|
||||
res = VerifyDSiFirmware();
|
||||
if (res != Load_OK) return res;
|
||||
|
||||
res = SetupDSiNAND();
|
||||
if (res != Load_OK) return res;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = VerifyDSFirmware();
|
||||
if (res != Load_OK) return res;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// original code in the libui frontend called NDS::LoadGBAROM() if needed
|
||||
// should this be carried over here?
|
||||
// is that behavior consistent with that of LoadROM() below?
|
||||
|
||||
ROMPath[ROMSlot_NDS] = "";
|
||||
SRAMPath[ROMSlot_NDS] = "";
|
||||
|
||||
NDS::SetConsoleType(Config::ConsoleType);
|
||||
NDS::LoadBIOS();
|
||||
|
||||
SavestateLoaded = false;
|
||||
|
||||
LoadCheats();
|
||||
|
||||
return Load_OK;
|
||||
}
|
||||
|
||||
int LoadROM(const u8 *romdata, u32 romlength, const char *archivefilename, const char *romfilename, const char *sramfilename, int slot)
|
||||
{
|
||||
int res;
|
||||
bool directboot = Config::DirectBoot;
|
||||
|
||||
if (Config::ConsoleType == 1 && slot == 1)
|
||||
{
|
||||
// cannot load a GBA ROM into a DSi
|
||||
return Load_ROMLoadError;
|
||||
}
|
||||
|
||||
res = VerifyDSBIOS();
|
||||
if (res != Load_OK) return res;
|
||||
|
||||
if (Config::ConsoleType == 1)
|
||||
{
|
||||
res = VerifyDSiBIOS();
|
||||
if (res != Load_OK) return res;
|
||||
|
||||
res = VerifyDSiFirmware();
|
||||
if (res != Load_OK) return res;
|
||||
|
||||
res = SetupDSiNAND();
|
||||
if (res != Load_OK) return res;
|
||||
|
||||
GBACart::Eject();
|
||||
ROMPath[ROMSlot_GBA] = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
res = VerifyDSFirmware();
|
||||
if (res != Load_OK)
|
||||
{
|
||||
if (res == Load_FirmwareNotBootable)
|
||||
directboot = true;
|
||||
else
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
std::string oldpath = ROMPath[slot];
|
||||
std::string oldsram = SRAMPath[slot];
|
||||
|
||||
SRAMPath[slot] = sramfilename;
|
||||
ROMPath[slot] = archivefilename;
|
||||
|
||||
NDS::SetConsoleType(Config::ConsoleType);
|
||||
|
||||
/* if (slot == ROMSlot_NDS && NDS::LoadROM(romdata, romlength, SRAMPath[slot].c_str(), directboot))
|
||||
{
|
||||
SavestateLoaded = false;
|
||||
|
||||
LoadCheats();
|
||||
|
||||
// Reload the inserted GBA cartridge (if any)
|
||||
// TODO: report failure there??
|
||||
//if (!ROMPath[ROMSlot_GBA].empty()) NDS::LoadGBAROM(ROMPath[ROMSlot_GBA], SRAMPath[ROMSlot_GBA]);
|
||||
|
||||
PrevSRAMPath[slot] = SRAMPath[slot]; // safety
|
||||
return Load_OK;
|
||||
}
|
||||
else if (slot == ROMSlot_GBA && NDS::LoadGBAROM(romdata, romlength, romfilename, SRAMPath[slot].c_str()))
|
||||
{
|
||||
SavestateLoaded = false; // checkme??
|
||||
|
||||
PrevSRAMPath[slot] = SRAMPath[slot]; // safety
|
||||
return Load_OK;
|
||||
}
|
||||
else*/
|
||||
{
|
||||
ROMPath[slot] = oldpath;
|
||||
SRAMPath[slot] = oldsram;
|
||||
return Load_ROMLoadError;
|
||||
}
|
||||
}
|
||||
|
||||
int LoadROM(const char* file, int slot)
|
||||
{
|
||||
DSi::CloseDSiNAND();
|
||||
|
||||
int res;
|
||||
bool directboot = Config::DirectBoot != 0;
|
||||
|
||||
if (Config::ConsoleType == 1 && slot == 1)
|
||||
{
|
||||
// cannot load a GBA ROM into a DSi
|
||||
return Load_ROMLoadError;
|
||||
}
|
||||
|
||||
res = VerifyDSBIOS();
|
||||
if (res != Load_OK) return res;
|
||||
|
||||
if (Config::ConsoleType == 1)
|
||||
{
|
||||
res = VerifyDSiBIOS();
|
||||
if (res != Load_OK) return res;
|
||||
|
||||
res = VerifyDSiFirmware();
|
||||
if (res != Load_OK) return res;
|
||||
|
||||
res = SetupDSiNAND();
|
||||
if (res != Load_OK) return res;
|
||||
|
||||
GBACart::Eject();
|
||||
ROMPath[ROMSlot_GBA] = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
res = VerifyDSFirmware();
|
||||
if (res != Load_OK)
|
||||
{
|
||||
if (res == Load_FirmwareNotBootable)
|
||||
directboot = true;
|
||||
else
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
std::string oldpath = ROMPath[slot];
|
||||
std::string oldsram = SRAMPath[slot];
|
||||
|
||||
ROMPath[slot] = file;
|
||||
|
||||
SetupSRAMPath(0);
|
||||
SetupSRAMPath(1);
|
||||
|
||||
NDS::SetConsoleType(Config::ConsoleType);
|
||||
|
||||
/*if (slot == ROMSlot_NDS && NDS::LoadROM(ROMPath[slot].c_str(), SRAMPath[slot].c_str(), directboot))
|
||||
{
|
||||
SavestateLoaded = false;
|
||||
|
||||
LoadCheats();
|
||||
|
||||
// Reload the inserted GBA cartridge (if any)
|
||||
// TODO: report failure there??
|
||||
if (!ROMPath[ROMSlot_GBA].empty()) NDS::LoadGBAROM(ROMPath[ROMSlot_GBA].c_str(), SRAMPath[ROMSlot_GBA].c_str());
|
||||
|
||||
PrevSRAMPath[slot] = SRAMPath[slot]; // safety
|
||||
return Load_OK;
|
||||
}
|
||||
else if (slot == ROMSlot_GBA && NDS::LoadGBAROM(ROMPath[slot].c_str(), SRAMPath[slot].c_str()))
|
||||
{
|
||||
SavestateLoaded = false; // checkme??
|
||||
|
||||
PrevSRAMPath[slot] = SRAMPath[slot]; // safety
|
||||
return Load_OK;
|
||||
}
|
||||
else*/
|
||||
{
|
||||
ROMPath[slot] = oldpath;
|
||||
SRAMPath[slot] = oldsram;
|
||||
return Load_ROMLoadError;
|
||||
}
|
||||
}
|
||||
|
||||
void ROMIcon(u8 (&data)[512], u16 (&palette)[16], u32* iconRef)
|
||||
{
|
||||
int index = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
for (int k = 0; k < 8; k++)
|
||||
{
|
||||
for (int l = 0; l < 8; l++)
|
||||
{
|
||||
u8 pal_index = index % 2 ? data[index/2] >> 4 : data[index/2] & 0x0F;
|
||||
u8 r = ((palette[pal_index] >> 0) & 0x1F) * 255 / 31;
|
||||
u8 g = ((palette[pal_index] >> 5) & 0x1F) * 255 / 31;
|
||||
u8 b = ((palette[pal_index] >> 10) & 0x1F) * 255 / 31;
|
||||
u8 a = pal_index ? 255: 0;
|
||||
u32* row = &iconRef[256 * i + 32 * k + 8 * j];
|
||||
row[l] = (a << 24) | (r << 16) | (g << 8) | b;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define SEQ_FLIPV(i) ((i & 0b1000000000000000) >> 15)
|
||||
#define SEQ_FLIPH(i) ((i & 0b0100000000000000) >> 14)
|
||||
#define SEQ_PAL(i) ((i & 0b0011100000000000) >> 11)
|
||||
#define SEQ_BMP(i) ((i & 0b0000011100000000) >> 8)
|
||||
#define SEQ_DUR(i) ((i & 0b0000000011111111) >> 0)
|
||||
|
||||
void AnimatedROMIcon(u8 (&data)[8][512], u16 (&palette)[8][16], u16 (&sequence)[64], u32 (&animatedTexRef)[32 * 32 * 64], std::vector<int> &animatedSequenceRef)
|
||||
{
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
if (!sequence[i])
|
||||
break;
|
||||
u32* frame = &animatedTexRef[32 * 32 * i];
|
||||
ROMIcon(data[SEQ_BMP(sequence[i])], palette[SEQ_PAL(sequence[i])], frame);
|
||||
|
||||
if (SEQ_FLIPH(sequence[i]))
|
||||
{
|
||||
for (int x = 0; x < 32; x++)
|
||||
{
|
||||
for (int y = 0; y < 32/2; y++)
|
||||
{
|
||||
std::swap(frame[x * 32 + y], frame[x * 32 + (32 - 1 - y)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (SEQ_FLIPV(sequence[i]))
|
||||
{
|
||||
for (int x = 0; x < 32/2; x++)
|
||||
{
|
||||
for (int y = 0; y < 32; y++)
|
||||
{
|
||||
std::swap(frame[x * 32 + y], frame[(32 - 1 - x) * 32 + y]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < SEQ_DUR(sequence[i]); j++)
|
||||
animatedSequenceRef.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
void UnloadROM(int slot)
|
||||
{
|
||||
if (slot == ROMSlot_NDS)
|
||||
{
|
||||
// TODO!
|
||||
}
|
||||
else if (slot == ROMSlot_GBA)
|
||||
{
|
||||
GBACart::Eject();
|
||||
}
|
||||
|
||||
ROMPath[slot] = "";
|
||||
|
||||
DSi::CloseDSiNAND();
|
||||
}
|
||||
|
||||
int Reset()
|
||||
{
|
||||
DSi::CloseDSiNAND();
|
||||
|
||||
int res;
|
||||
bool directboot = Config::DirectBoot != 0;
|
||||
|
||||
res = VerifyDSBIOS();
|
||||
if (res != Load_OK) return res;
|
||||
|
||||
if (Config::ConsoleType == 1)
|
||||
{
|
||||
res = VerifyDSiBIOS();
|
||||
if (res != Load_OK) return res;
|
||||
|
||||
res = VerifyDSiFirmware();
|
||||
if (res != Load_OK) return res;
|
||||
|
||||
res = SetupDSiNAND();
|
||||
if (res != Load_OK) return res;
|
||||
|
||||
GBACart::Eject();
|
||||
ROMPath[ROMSlot_GBA][0] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
res = VerifyDSFirmware();
|
||||
if (res != Load_OK)
|
||||
{
|
||||
if (res == Load_FirmwareNotBootable)
|
||||
directboot = true;
|
||||
else
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
SavestateLoaded = false;
|
||||
|
||||
NDS::SetConsoleType(Config::ConsoleType);
|
||||
|
||||
if (ROMPath[ROMSlot_NDS].empty())
|
||||
{
|
||||
NDS::LoadBIOS();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string ext = ROMPath[ROMSlot_NDS].substr(ROMPath[ROMSlot_NDS].length() - 4);
|
||||
std::transform(ext.begin(), ext.end(), ext.begin(), tolower);
|
||||
|
||||
if (ext == ".nds" || ext == ".srl" || ext == ".dsi")
|
||||
{
|
||||
SetupSRAMPath(0);
|
||||
//if (!NDS::LoadROM(ROMPath[ROMSlot_NDS].c_str(), SRAMPath[ROMSlot_NDS].c_str(), directboot))
|
||||
// return Load_ROMLoadError;
|
||||
}
|
||||
#ifdef ARCHIVE_SUPPORT_ENABLED
|
||||
else
|
||||
{
|
||||
// TODO!!!
|
||||
// THIS WILL BREAK IF CUSTOM SRAM PATHS ARE ADDED
|
||||
|
||||
/*u8 *romdata = nullptr; u32 romlen;
|
||||
char romfilename[1024] = {0}, sramfilename[1024];
|
||||
strncpy(sramfilename, SRAMPath[ROMSlot_NDS], 1024); // Use existing SRAMPath
|
||||
|
||||
int pos = strlen(sramfilename) - 1;
|
||||
while (pos > 0 && sramfilename[pos] != '/' && sramfilename[pos] != '\\')
|
||||
--pos;
|
||||
|
||||
strncpy(romfilename, &sramfilename[pos + 1], 1024);
|
||||
strncpy(&romfilename[strlen(romfilename) - 3], NDSROMExtension, 3); // extension could be nds, srl or dsi
|
||||
printf("RESET loading from archive : %s\n", romfilename);
|
||||
romlen = Archive::ExtractFileFromArchive(ROMPath[ROMSlot_NDS], romfilename, &romdata);
|
||||
if (!romdata)
|
||||
return Load_ROMLoadError;
|
||||
|
||||
bool ok = NDS::LoadROM(romdata, romlen, sramfilename, directboot);
|
||||
delete romdata;
|
||||
if (!ok)*/
|
||||
return Load_ROMLoadError;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!ROMPath[ROMSlot_GBA].empty())
|
||||
{
|
||||
std::string ext = ROMPath[ROMSlot_GBA].substr(ROMPath[ROMSlot_GBA].length() - 4);
|
||||
std::transform(ext.begin(), ext.end(), ext.begin(), tolower);
|
||||
|
||||
if (ext == ".gba")
|
||||
{
|
||||
SetupSRAMPath(1);
|
||||
//if (!NDS::LoadGBAROM(ROMPath[ROMSlot_GBA].c_str(), SRAMPath[ROMSlot_GBA].c_str()))
|
||||
// return Load_ROMLoadError;
|
||||
}
|
||||
#ifdef ARCHIVE_SUPPORT_ENABLED
|
||||
else
|
||||
{
|
||||
// TODO!! SAME AS ABOVE
|
||||
|
||||
/*u8 *romdata = nullptr; u32 romlen;
|
||||
char romfilename[1024] = {0}, sramfilename[1024];
|
||||
strncpy(sramfilename, SRAMPath[ROMSlot_GBA], 1024); // Use existing SRAMPath
|
||||
|
||||
int pos = strlen(sramfilename) - 1;
|
||||
while (pos > 0 && sramfilename[pos] != '/' && sramfilename[pos] != '\\')
|
||||
--pos;
|
||||
|
||||
strncpy(romfilename, &sramfilename[pos + 1], 1024);
|
||||
strncpy(&romfilename[strlen(romfilename) - 3], "gba", 3);
|
||||
printf("RESET loading from archive : %s\n", romfilename);
|
||||
romlen = Archive::ExtractFileFromArchive(ROMPath[ROMSlot_GBA], romfilename, &romdata);
|
||||
if (!romdata)
|
||||
return Load_ROMLoadError;
|
||||
|
||||
bool ok = NDS::LoadGBAROM(romdata, romlen, romfilename, SRAMPath[ROMSlot_GBA]);
|
||||
delete romdata;
|
||||
if (!ok)*/
|
||||
return Load_ROMLoadError;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
LoadCheats();
|
||||
|
||||
return Load_OK;
|
||||
}
|
||||
|
||||
|
||||
// SAVESTATE TODO
|
||||
// * configurable paths. not everyone wants their ROM directory to be polluted, I guess.
|
||||
|
||||
std::string GetSavestateName(int slot)
|
||||
{
|
||||
std::string filename;
|
||||
|
||||
if (ROMPath[ROMSlot_NDS].empty()) // running firmware, no ROM
|
||||
{
|
||||
filename = "firmware";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string rompath;
|
||||
std::string ext = ROMPath[ROMSlot_NDS].substr(ROMPath[ROMSlot_NDS].length() - 4);
|
||||
std::transform(ext.begin(), ext.end(), ext.begin(), tolower);
|
||||
|
||||
// TODO!!! MORE SHIT THAT IS GONNA ASPLODE
|
||||
if (ext == ".nds" || ext == ".srl" || ext == ".dsi")
|
||||
rompath = ROMPath[ROMSlot_NDS];
|
||||
else
|
||||
rompath = SRAMPath[ROMSlot_NDS]; // If archive, construct ssname from sram file
|
||||
|
||||
filename = rompath.substr(0, rompath.rfind('.'));
|
||||
}
|
||||
|
||||
filename += ".ml";
|
||||
filename += ('0'+slot);
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
bool SavestateExists(int slot)
|
||||
{
|
||||
std::string ssfile = GetSavestateName(slot);
|
||||
return Platform::FileExists(ssfile);
|
||||
}
|
||||
|
||||
bool LoadState(std::string filename)
|
||||
{
|
||||
u32 oldGBACartCRC = GBACart::CartCRC;
|
||||
|
||||
// backup
|
||||
Savestate* backup = new Savestate("timewarp.mln", true);
|
||||
NDS::DoSavestate(backup);
|
||||
delete backup;
|
||||
|
||||
bool failed = false;
|
||||
|
||||
Savestate* state = new Savestate(filename, false);
|
||||
if (state->Error)
|
||||
{
|
||||
delete state;
|
||||
|
||||
//uiMsgBoxError(MainWindow, "Error", "Could not load savestate file.");
|
||||
|
||||
// current state might be crapoed, so restore from sane backup
|
||||
state = new Savestate("timewarp.mln", false);
|
||||
failed = true;
|
||||
}
|
||||
|
||||
NDS::DoSavestate(state);
|
||||
delete state;
|
||||
|
||||
if (!failed)
|
||||
{
|
||||
if (Config::SavestateRelocSRAM && !ROMPath[ROMSlot_NDS].empty())
|
||||
{
|
||||
PrevSRAMPath[ROMSlot_NDS] = SRAMPath[ROMSlot_NDS];
|
||||
|
||||
// TODO: how should this interact with custom paths?
|
||||
SRAMPath[ROMSlot_NDS] = filename + ".sav";
|
||||
|
||||
//NDS::RelocateSave(SRAMPath[ROMSlot_NDS].c_str(), false);
|
||||
}
|
||||
|
||||
bool loadedPartialGBAROM = false;
|
||||
|
||||
// in case we have a GBA cart inserted, and the GBA ROM changes
|
||||
// due to having loaded a save state, we do not want to reload
|
||||
// the previous cartridge on reset, or commit writes to any
|
||||
// loaded save file. therefore, their paths are "nulled".
|
||||
if (GBACart::CartInserted && GBACart::CartCRC != oldGBACartCRC)
|
||||
{
|
||||
ROMPath[ROMSlot_GBA] = "";
|
||||
SRAMPath[ROMSlot_GBA] = "";
|
||||
loadedPartialGBAROM = true;
|
||||
}
|
||||
|
||||
// TODO forward this to user in a meaningful way!!
|
||||
/*char msg[64];
|
||||
if (slot > 0) sprintf(msg, "State loaded from slot %d%s",
|
||||
slot, loadedPartialGBAROM ? " (GBA ROM header only)" : "");
|
||||
else sprintf(msg, "State loaded from file%s",
|
||||
loadedPartialGBAROM ? " (GBA ROM header only)" : "");
|
||||
OSD::AddMessage(0, msg);*/
|
||||
|
||||
SavestateLoaded = true;
|
||||
}
|
||||
|
||||
return !failed;
|
||||
}
|
||||
|
||||
bool SaveState(std::string filename)
|
||||
{
|
||||
Savestate* state = new Savestate(filename, true);
|
||||
if (state->Error)
|
||||
{
|
||||
delete state;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
NDS::DoSavestate(state);
|
||||
delete state;
|
||||
|
||||
if (Config::SavestateRelocSRAM && !ROMPath[ROMSlot_NDS].empty())
|
||||
{
|
||||
// TODO: how should this interact with custom paths?
|
||||
SRAMPath[ROMSlot_NDS] = filename + ".sav";
|
||||
|
||||
//NDS::RelocateSave(SRAMPath[ROMSlot_NDS].c_str(), true);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UndoStateLoad()
|
||||
{
|
||||
if (!SavestateLoaded) return;
|
||||
|
||||
// pray that this works
|
||||
// what do we do if it doesn't???
|
||||
// but it should work.
|
||||
Savestate* backup = new Savestate("timewarp.mln", false);
|
||||
NDS::DoSavestate(backup);
|
||||
delete backup;
|
||||
|
||||
if (!ROMPath[ROMSlot_NDS].empty())
|
||||
{
|
||||
SRAMPath[ROMSlot_NDS] = PrevSRAMPath[ROMSlot_NDS];
|
||||
//NDS::RelocateSave(SRAMPath[ROMSlot_NDS].c_str(), false);
|
||||
}
|
||||
}
|
||||
|
||||
int ImportSRAM(const char* filename)
|
||||
{
|
||||
/*FILE* file = fopen(filename, "rb");
|
||||
fseek(file, 0, SEEK_END);
|
||||
u32 size = ftell(file);
|
||||
u8* importData = new u8[size];
|
||||
rewind(file);
|
||||
fread(importData, size, 1, file);
|
||||
fclose(file);
|
||||
|
||||
int diff = NDS::ImportSRAM(importData, size);
|
||||
delete[] importData;
|
||||
return diff;*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
void EnableCheats(bool enable)
|
||||
{
|
||||
CheatsOn = enable;
|
||||
if (CheatFile)
|
||||
AREngine::SetCodeFile(CheatsOn ? CheatFile : nullptr);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
Copyright 2016-2021 Arisotura
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
melonDS is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation, either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef ROMLOADER_H
|
||||
#define ROMLOADER_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace ROMLoader
|
||||
{
|
||||
|
||||
enum
|
||||
{
|
||||
ROMSlot_NDS = 0,
|
||||
ROMSlot_GBA,
|
||||
|
||||
ROMSlot_MAX
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
Load_OK = 0,
|
||||
|
||||
Load_BIOS9Missing,
|
||||
Load_BIOS9Bad,
|
||||
|
||||
Load_BIOS7Missing,
|
||||
Load_BIOS7Bad,
|
||||
|
||||
Load_FirmwareMissing,
|
||||
Load_FirmwareBad,
|
||||
Load_FirmwareNotBootable,
|
||||
|
||||
Load_DSiBIOS9Missing,
|
||||
Load_DSiBIOS9Bad,
|
||||
|
||||
Load_DSiBIOS7Missing,
|
||||
Load_DSiBIOS7Bad,
|
||||
|
||||
Load_DSiNANDMissing,
|
||||
Load_DSiNANDBad,
|
||||
|
||||
// TODO: more precise errors for ROM loading
|
||||
Load_ROMLoadError,
|
||||
};
|
||||
|
||||
extern std::string ROMPath [ROMSlot_MAX];
|
||||
extern std::string SRAMPath[ROMSlot_MAX];
|
||||
extern bool SavestateLoaded;
|
||||
|
||||
// Stores type of nds rom i.e. nds/srl/dsi. Should be updated everytime an NDS rom is loaded from an archive
|
||||
extern std::string NDSROMExtension;
|
||||
|
||||
// initialize the ROM handling utility
|
||||
void Init_ROM();
|
||||
|
||||
// deinitialize the ROM handling utility
|
||||
void DeInit_ROM();
|
||||
|
||||
// load the BIOS/firmware and boot from it
|
||||
int LoadBIOS();
|
||||
|
||||
// load a ROM file to the specified cart slot
|
||||
// note: loading a ROM to the NDS slot resets emulation
|
||||
int LoadROM(const char* file, int slot);
|
||||
int LoadROM(const u8 *romdata, u32 romlength, const char *archivefilename, const char *romfilename, const char *sramfilename, int slot);
|
||||
|
||||
// unload the ROM loaded in the specified cart slot
|
||||
// simulating ejection of the cartridge
|
||||
void UnloadROM(int slot);
|
||||
|
||||
void ROMIcon(u8 (&data)[512], u16 (&palette)[16], u32* iconRef);
|
||||
void AnimatedROMIcon(u8 (&data)[8][512], u16 (&palette)[8][16], u16 (&sequence)[64], u32 (&animatedTexRef)[32 * 32 * 64], std::vector<int> &animatedSequenceRef);
|
||||
|
||||
// reset execution of the current ROM
|
||||
int Reset();
|
||||
|
||||
// get the filename associated with the given savestate slot (1-8)
|
||||
std::string GetSavestateName(int slot);
|
||||
|
||||
// determine whether the given savestate slot does contain a savestate
|
||||
bool SavestateExists(int slot);
|
||||
|
||||
// load the given savestate file
|
||||
// if successful, emulation will continue from the savestate's point
|
||||
bool LoadState(std::string filename);
|
||||
|
||||
// save the current emulator state to the given file
|
||||
bool SaveState(std::string filename);
|
||||
|
||||
// undo the latest savestate load
|
||||
void UndoStateLoad();
|
||||
|
||||
// imports savedata from an external file. Returns the difference between the filesize and the SRAM size
|
||||
int ImportSRAM(const char* filename);
|
||||
|
||||
// enable or disable cheats
|
||||
void EnableCheats(bool enable);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // ROMLOADER_H
|
|
@ -23,7 +23,7 @@
|
|||
#include "Platform.h"
|
||||
|
||||
|
||||
SaveManager()
|
||||
SaveManager::SaveManager()
|
||||
{
|
||||
SecondaryBuffer = nullptr;
|
||||
SecondaryBufferLock = new QMutex();
|
||||
|
@ -31,7 +31,7 @@ SaveManager()
|
|||
Running = false;
|
||||
}
|
||||
|
||||
~SaveManager()
|
||||
SaveManager::~SaveManager()
|
||||
{
|
||||
if (Running)
|
||||
{
|
||||
|
@ -73,7 +73,7 @@ void SaveManager::Setup(std::string path, u8* buffer, u32 length)
|
|||
Running = true;
|
||||
start();
|
||||
}
|
||||
else if (path.empty && Running)
|
||||
else if (path.empty() && Running)
|
||||
{
|
||||
Running = false;
|
||||
wait();
|
||||
|
|
|
@ -1288,9 +1288,9 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
|
|||
connect(actOpenROM, &QAction::triggered, this, &MainWindow::onOpenFile);
|
||||
actOpenROM->setShortcut(QKeySequence(QKeySequence::StandardKey::Open));
|
||||
|
||||
actOpenROMArchive = menu->addAction("Open ROM inside archive...");
|
||||
/*actOpenROMArchive = menu->addAction("Open ROM inside archive...");
|
||||
connect(actOpenROMArchive, &QAction::triggered, this, &MainWindow::onOpenFileArchive);
|
||||
actOpenROMArchive->setShortcut(QKeySequence(Qt::Key_O | Qt::CTRL | Qt::SHIFT));
|
||||
actOpenROMArchive->setShortcut(QKeySequence(Qt::Key_O | Qt::CTRL | Qt::SHIFT));*/
|
||||
|
||||
recentMenu = menu->addMenu("Open recent");
|
||||
for (int i = 0; i < 10; ++i)
|
||||
|
@ -1307,6 +1307,43 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
|
|||
|
||||
menu->addSeparator();
|
||||
|
||||
actCurrentCart = menu->addAction("Slot 1: princessbourf.nds");
|
||||
actCurrentCart->setEnabled(false);
|
||||
|
||||
actInsertCart = menu->addAction("Insert cart...");
|
||||
|
||||
actEjectCart = menu->addAction("Eject cart");
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
actCurrentGBACart = menu->addAction("Slot 2: Fartslapper Mk. II");
|
||||
actCurrentGBACart->setEnabled(false);
|
||||
|
||||
actInsertGBACart = menu->addAction("Insert ROM cart...");
|
||||
|
||||
//actInsertGBAAddon = menu->addAction("Insert add-on cart");
|
||||
{
|
||||
QMenu* submenu = menu->addMenu("Insert add-on cart");
|
||||
|
||||
actInsertGBAAddon[0] = submenu->addAction("Memory expansion");
|
||||
actInsertGBAAddon[1] = submenu->addAction("Vibrator Pak");
|
||||
actInsertGBAAddon[2] = submenu->addAction("Guitar Hero grip");
|
||||
actInsertGBAAddon[3] = submenu->addAction("Fartslapper");
|
||||
actInsertGBAAddon[4] = submenu->addAction("Fartslapper Mk. II");
|
||||
actInsertGBAAddon[5] = submenu->addAction("Ghostbusters ray");
|
||||
actInsertGBAAddon[6] = submenu->addAction("Fridge Pak");
|
||||
actInsertGBAAddon[7] = submenu->addAction("Fazil");
|
||||
}
|
||||
|
||||
actEjectGBACart = menu->addAction("Eject cart");
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
actImportSavefile = menu->addAction("Import savefile");
|
||||
connect(actImportSavefile, &QAction::triggered, this, &MainWindow::onImportSavefile);
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
{
|
||||
QMenu* submenu = menu->addMenu("Save state");
|
||||
|
||||
|
@ -1344,9 +1381,6 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
|
|||
actUndoStateLoad->setShortcut(QKeySequence(Qt::Key_F12));
|
||||
connect(actUndoStateLoad, &QAction::triggered, this, &MainWindow::onUndoStateLoad);
|
||||
|
||||
actImportSavefile = menu->addAction("Import savefile");
|
||||
connect(actImportSavefile, &QAction::triggered, this, &MainWindow::onImportSavefile);
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
actQuit = menu->addAction("Quit");
|
||||
|
@ -1974,26 +2008,69 @@ void MainWindow::loadROM(QString filename)
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::onOpenFile()
|
||||
void MainWindow::pickAndLoadROM(bool gba)
|
||||
{
|
||||
QString console;
|
||||
QStringList romexts;
|
||||
QStringList arcexts{"*.zip", "*.7z", "*.rar", "*.tar", "*.gz", "*.xz", "*.bz2"};
|
||||
|
||||
if (gba)
|
||||
{
|
||||
console = "GBA";
|
||||
romexts.append("*.gba");
|
||||
}
|
||||
else
|
||||
{
|
||||
console = "DS";
|
||||
romexts.append({"*.nds", "*.dsi", "*.srl"});
|
||||
}
|
||||
|
||||
emuThread->emuPause();
|
||||
|
||||
QString filter = romexts.join(' ') + " " + arcexts.join(' ');
|
||||
filter = console + " ROMs (" + filter + ");;Any file (*.*)";
|
||||
|
||||
QString filename = QFileDialog::getOpenFileName(this,
|
||||
"Open ROM",
|
||||
"Open "+console+" ROM",
|
||||
QString::fromStdString(Config::LastROMFolder),
|
||||
"DS ROMs (*.nds *.dsi *.srl);;GBA ROMs (*.gba *.zip);;Any file (*.*)");
|
||||
filter);
|
||||
if (filename.isEmpty())
|
||||
{
|
||||
emuThread->emuUnpause();
|
||||
return;
|
||||
}
|
||||
|
||||
loadROM(filename);
|
||||
int pos = filename.length() - 1;
|
||||
while (filename[pos] != '/' && filename[pos] != '\\' && pos > 0) pos--;
|
||||
QString path_dir = filename.left(pos);
|
||||
QString path_file = filename.mid(pos+1);
|
||||
QString path_ext = path_file.mid(path_file.lastIndexOf('.')).toLower();
|
||||
|
||||
Config::LastROMFolder = path_dir.toStdString();
|
||||
|
||||
printf("LOADING ROM: %s\n", filename.toStdString().c_str());
|
||||
printf("- %s\n", path_dir.toStdString().c_str());
|
||||
printf("- %s\n", path_file.toStdString().c_str());
|
||||
printf("- %s\n", path_ext.toStdString().c_str());
|
||||
|
||||
if (arcexts.contains("*"+path_ext))
|
||||
{
|
||||
QByteArray romBuffer;
|
||||
QString arcfile = pickAndExtractFileFromArchive(filename, &romBuffer);
|
||||
|
||||
printf("ARCHIVE: %s\n", arcfile.toStdString().c_str());
|
||||
printf("SIZE=%d\n", romBuffer.size());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onOpenFile()
|
||||
{
|
||||
pickAndLoadROM(false);
|
||||
}
|
||||
|
||||
void MainWindow::onOpenFileArchive()
|
||||
{
|
||||
emuThread->emuPause();
|
||||
/*emuThread->emuPause();
|
||||
|
||||
QString archiveFileName = QFileDialog::getOpenFileName(this,
|
||||
"Open ROM Archive",
|
||||
|
@ -2010,7 +2087,7 @@ void MainWindow::onOpenFileArchive()
|
|||
if(!romFileName.isEmpty())
|
||||
{
|
||||
loadROM(&romBuffer, archiveFileName, romFileName);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
QString MainWindow::pickAndExtractFileFromArchive(QString archiveFileName, QByteArray *romBuffer)
|
||||
|
@ -2019,7 +2096,7 @@ QString MainWindow::pickAndExtractFileFromArchive(QString archiveFileName, QByte
|
|||
QVector<QString> archiveROMList = Archive::ListArchive(archiveFileName.toUtf8().constData());
|
||||
|
||||
|
||||
QString romFileName; // file name inside archive
|
||||
QString romFileName = ""; // file name inside archive
|
||||
|
||||
if (archiveROMList.size() > 2)
|
||||
{
|
||||
|
@ -2028,7 +2105,7 @@ QString MainWindow::pickAndExtractFileFromArchive(QString archiveFileName, QByte
|
|||
bool ok;
|
||||
QString toLoad = QInputDialog::getItem(this, "melonDS",
|
||||
"The archive was found to have multiple files. Select which ROM you want to load.", archiveROMList.toList(), 0, false, &ok);
|
||||
if(!ok) // User clicked on cancel
|
||||
if (!ok) // User clicked on cancel
|
||||
return QString();
|
||||
|
||||
printf("Extracting '%s'\n", toLoad.toUtf8().constData());
|
||||
|
|
|
@ -298,6 +298,8 @@ private:
|
|||
|
||||
QString pickAndExtractFileFromArchive(QString archiveFileName, QByteArray *romBuffer);
|
||||
|
||||
void pickAndLoadROM(bool gba);
|
||||
|
||||
void createScreenPanel();
|
||||
|
||||
QString loadErrorStr(int error);
|
||||
|
@ -313,12 +315,19 @@ public:
|
|||
ScreenPanelNative* panelNative;
|
||||
|
||||
QAction* actOpenROM;
|
||||
QAction* actOpenROMArchive;
|
||||
//QAction* actOpenROMArchive;
|
||||
QAction* actBootFirmware;
|
||||
QAction* actCurrentCart;
|
||||
QAction* actInsertCart;
|
||||
QAction* actEjectCart;
|
||||
QAction* actCurrentGBACart;
|
||||
QAction* actInsertGBACart;
|
||||
QAction* actInsertGBAAddon[16];
|
||||
QAction* actEjectGBACart;
|
||||
QAction* actImportSavefile;
|
||||
QAction* actSaveState[9];
|
||||
QAction* actLoadState[9];
|
||||
QAction* actUndoStateLoad;
|
||||
QAction* actImportSavefile;
|
||||
QAction* actQuit;
|
||||
|
||||
QAction* actPause;
|
||||
|
|
Loading…
Reference in New Issue