mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-25 15:19:53 -06:00
Refactor NDS
and DSi
to be objects (#1893)
* First crack at refactoring NDS and DSi into objects - Remove all global/`static` variables in `NDS` and related classes - Rely more on virtual dispatch when we need to pick methods at runtime - Pass `NDS&` or `DSi&` to its constituent components where necessary - Introduce some headers or move some definitions to break `#include` cycles * Refactor the frontend to accommodate the core's changes * Move up `SchedList`'s declaration - Move it to before the components are initialized so the `map`s inside are initialized - Fields in C++ are initialized in the order they're declared * Fix a crash when allocating memory * Fix JIT-free builds * Fix GDB-free builds * Fix Linux builds - Explicitly qualify some member types in NDS, since they share the same name as their classes * Remove an unnecessary template argument - This was causing the build to fail on macOS * Fix ARM and Android builds * Rename `Constants.h` to `MemConstants.h` * Add `NDS::IsRunning()` * Use an `#include` guard instead of `#pragma once`
This commit is contained in:

committed by
GitHub

parent
c84cb17462
commit
e973236203
@ -55,8 +55,9 @@ void AudioCallback(void* data, Uint8* stream, int len)
|
||||
s16 buf_in[1024*2];
|
||||
int num_in;
|
||||
|
||||
EmuThread* emuThread = (EmuThread*)data;
|
||||
SDL_LockMutex(audioSyncLock);
|
||||
num_in = NDS::SPU->ReadOutput(buf_in, len_in);
|
||||
num_in = emuThread->NDS->SPU.ReadOutput(buf_in, len_in);
|
||||
SDL_CondSignal(audioSync);
|
||||
SDL_UnlockMutex(audioSyncLock);
|
||||
|
||||
@ -244,7 +245,7 @@ void MicLoadWav(const std::string& name)
|
||||
SDL_FreeWAV(buf);
|
||||
}
|
||||
|
||||
void MicProcess()
|
||||
void MicProcess(melonDS::NDS& nds)
|
||||
{
|
||||
int type = Config::MicInputType;
|
||||
bool cmd = Input::HotkeyDown(HK_Mic);
|
||||
@ -257,16 +258,16 @@ void MicProcess()
|
||||
switch (type)
|
||||
{
|
||||
case micInputType_Silence: // no mic
|
||||
Frontend::Mic_FeedSilence();
|
||||
Frontend::Mic_FeedSilence(nds);
|
||||
break;
|
||||
|
||||
case micInputType_External: // host mic
|
||||
case micInputType_Wav: // WAV
|
||||
Frontend::Mic_FeedExternalBuffer();
|
||||
Frontend::Mic_FeedExternalBuffer(nds);
|
||||
break;
|
||||
|
||||
case micInputType_Noise: // blowing noise
|
||||
Frontend::Mic_FeedNoise();
|
||||
Frontend::Mic_FeedNoise(nds);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -296,7 +297,7 @@ void SetupMicInputData()
|
||||
}
|
||||
}
|
||||
|
||||
void Init()
|
||||
void Init(EmuThread* thread)
|
||||
{
|
||||
audioMuted = false;
|
||||
audioSync = SDL_CreateCond();
|
||||
@ -310,6 +311,7 @@ void Init()
|
||||
whatIwant.channels = 2;
|
||||
whatIwant.samples = 1024;
|
||||
whatIwant.callback = AudioCallback;
|
||||
whatIwant.userdata = thread;
|
||||
audioDevice = SDL_OpenAudioDevice(NULL, 0, &whatIwant, &whatIget, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
|
||||
if (!audioDevice)
|
||||
{
|
||||
@ -349,12 +351,12 @@ void DeInit()
|
||||
micWavBuffer = nullptr;
|
||||
}
|
||||
|
||||
void AudioSync()
|
||||
void AudioSync(NDS& nds)
|
||||
{
|
||||
if (audioDevice)
|
||||
{
|
||||
SDL_LockMutex(audioSyncLock);
|
||||
while (NDS::SPU->GetOutputSize() > 1024)
|
||||
while (nds.SPU.GetOutputSize() > 1024)
|
||||
{
|
||||
int ret = SDL_CondWaitTimeout(audioSync, audioSyncLock, 500);
|
||||
if (ret == SDL_MUTEX_TIMEDOUT) break;
|
||||
@ -363,11 +365,11 @@ void AudioSync()
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateSettings()
|
||||
void UpdateSettings(NDS& nds)
|
||||
{
|
||||
MicClose();
|
||||
|
||||
NDS::SPU->SetInterpolation(Config::AudioInterp);
|
||||
nds.SPU.SetInterpolation(Config::AudioInterp);
|
||||
SetupMicInputData();
|
||||
|
||||
MicOpen();
|
||||
|
@ -23,18 +23,23 @@
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
class EmuThread;
|
||||
namespace melonDS
|
||||
{
|
||||
class NDS;
|
||||
}
|
||||
namespace AudioInOut
|
||||
{
|
||||
|
||||
void Init();
|
||||
void Init(EmuThread* thread);
|
||||
void DeInit();
|
||||
|
||||
void MicProcess();
|
||||
void MicProcess(melonDS::NDS& nds);
|
||||
void AudioMute(QMainWindow* mainWindow);
|
||||
|
||||
void AudioSync();
|
||||
void AudioSync(melonDS::NDS& nds);
|
||||
|
||||
void UpdateSettings();
|
||||
void UpdateSettings(melonDS::NDS& nds);
|
||||
|
||||
void Enable();
|
||||
void Disable();
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
#include "AudioSettingsDialog.h"
|
||||
#include "ui_AudioSettingsDialog.h"
|
||||
|
||||
#include "main.h"
|
||||
|
||||
using namespace melonDS;
|
||||
AudioSettingsDialog* AudioSettingsDialog::currentDlg = nullptr;
|
||||
@ -37,7 +37,7 @@ AudioSettingsDialog* AudioSettingsDialog::currentDlg = nullptr;
|
||||
extern std::string EmuDirectory;
|
||||
|
||||
|
||||
AudioSettingsDialog::AudioSettingsDialog(QWidget* parent, bool emuActive) : QDialog(parent), ui(new Ui::AudioSettingsDialog)
|
||||
AudioSettingsDialog::AudioSettingsDialog(QWidget* parent, bool emuActive, EmuThread* emuThread) : QDialog(parent), ui(new Ui::AudioSettingsDialog), emuThread(emuThread)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
@ -65,7 +65,7 @@ AudioSettingsDialog::AudioSettingsDialog(QWidget* parent, bool emuActive) : QDia
|
||||
ui->chkSyncDSiVolume->setChecked(Config::DSiVolumeSync);
|
||||
|
||||
// Setup volume slider accordingly
|
||||
if (emuActive && NDS::ConsoleType == 1)
|
||||
if (emuActive && emuThread->NDS->ConsoleType == 1)
|
||||
{
|
||||
on_chkSyncDSiVolume_clicked(Config::DSiVolumeSync);
|
||||
}
|
||||
@ -125,10 +125,11 @@ AudioSettingsDialog::~AudioSettingsDialog()
|
||||
|
||||
void AudioSettingsDialog::onSyncVolumeLevel()
|
||||
{
|
||||
if (Config::DSiVolumeSync && NDS::ConsoleType == 1)
|
||||
if (Config::DSiVolumeSync && emuThread->NDS->ConsoleType == 1)
|
||||
{
|
||||
auto& dsi = static_cast<DSi&>(*emuThread->NDS);
|
||||
bool state = ui->slVolume->blockSignals(true);
|
||||
ui->slVolume->setValue(DSi::I2C->GetBPTWL()->GetVolumeLevel());
|
||||
ui->slVolume->setValue(dsi.I2C.GetBPTWL()->GetVolumeLevel());
|
||||
ui->slVolume->blockSignals(state);
|
||||
}
|
||||
}
|
||||
@ -136,7 +137,7 @@ void AudioSettingsDialog::onSyncVolumeLevel()
|
||||
void AudioSettingsDialog::onConsoleReset()
|
||||
{
|
||||
on_chkSyncDSiVolume_clicked(Config::DSiVolumeSync);
|
||||
ui->chkSyncDSiVolume->setEnabled(NDS::ConsoleType == 1);
|
||||
ui->chkSyncDSiVolume->setEnabled(emuThread->NDS->ConsoleType == 1);
|
||||
}
|
||||
|
||||
void AudioSettingsDialog::on_AudioSettingsDialog_accepted()
|
||||
@ -181,9 +182,10 @@ void AudioSettingsDialog::on_cbInterpolation_currentIndexChanged(int idx)
|
||||
|
||||
void AudioSettingsDialog::on_slVolume_valueChanged(int val)
|
||||
{
|
||||
if (Config::DSiVolumeSync && NDS::ConsoleType == 1)
|
||||
if (Config::DSiVolumeSync && emuThread->NDS->ConsoleType == 1)
|
||||
{
|
||||
DSi::I2C->GetBPTWL()->SetVolumeLevel(val);
|
||||
auto& dsi = static_cast<DSi&>(*emuThread->NDS);
|
||||
dsi.I2C.GetBPTWL()->SetVolumeLevel(val);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -195,10 +197,11 @@ void AudioSettingsDialog::on_chkSyncDSiVolume_clicked(bool checked)
|
||||
Config::DSiVolumeSync = checked;
|
||||
|
||||
bool state = ui->slVolume->blockSignals(true);
|
||||
if (Config::DSiVolumeSync && NDS::ConsoleType == 1)
|
||||
if (Config::DSiVolumeSync && emuThread->NDS->ConsoleType == 1)
|
||||
{
|
||||
auto& dsi = static_cast<DSi&>(*emuThread->NDS);
|
||||
ui->slVolume->setMaximum(31);
|
||||
ui->slVolume->setValue(DSi::I2C->GetBPTWL()->GetVolumeLevel());
|
||||
ui->slVolume->setValue(dsi.I2C.GetBPTWL()->GetVolumeLevel());
|
||||
ui->slVolume->setPageStep(4);
|
||||
ui->slVolume->setTickPosition(QSlider::TicksBelow);
|
||||
}
|
||||
|
@ -24,17 +24,18 @@
|
||||
|
||||
namespace Ui { class AudioSettingsDialog; }
|
||||
class AudioSettingsDialog;
|
||||
class EmuThread;
|
||||
|
||||
class AudioSettingsDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AudioSettingsDialog(QWidget* parent, bool emuActive);
|
||||
explicit AudioSettingsDialog(QWidget* parent, bool emuActive, EmuThread* emuThread);
|
||||
~AudioSettingsDialog();
|
||||
|
||||
static AudioSettingsDialog* currentDlg;
|
||||
static AudioSettingsDialog* openDlg(QWidget* parent, bool emuActive)
|
||||
static AudioSettingsDialog* openDlg(QWidget* parent, bool emuActive, EmuThread* emuThread)
|
||||
{
|
||||
if (currentDlg)
|
||||
{
|
||||
@ -42,7 +43,7 @@ public:
|
||||
return currentDlg;
|
||||
}
|
||||
|
||||
currentDlg = new AudioSettingsDialog(parent, emuActive);
|
||||
currentDlg = new AudioSettingsDialog(parent, emuActive, emuThread);
|
||||
currentDlg->show();
|
||||
return currentDlg;
|
||||
}
|
||||
@ -69,6 +70,7 @@ private slots:
|
||||
void on_btnMicWavBrowse_clicked();
|
||||
|
||||
private:
|
||||
EmuThread* emuThread;
|
||||
Ui::AudioSettingsDialog* ui;
|
||||
|
||||
int oldInterp;
|
||||
|
@ -29,45 +29,59 @@
|
||||
#include "types.h"
|
||||
|
||||
#include <QtDebug>
|
||||
#include "main.h"
|
||||
|
||||
using namespace melonDS;
|
||||
|
||||
PowerManagementDialog* PowerManagementDialog::currentDlg = nullptr;
|
||||
|
||||
PowerManagementDialog::PowerManagementDialog(QWidget* parent) : QDialog(parent), ui(new Ui::PowerManagementDialog)
|
||||
PowerManagementDialog::PowerManagementDialog(QWidget* parent, EmuThread* emuThread) : QDialog(parent), emuThread(emuThread), ui(new Ui::PowerManagementDialog)
|
||||
{
|
||||
inited = false;
|
||||
|
||||
ui->setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
if (NDS::ConsoleType == 1)
|
||||
if (emuThread->NDS->ConsoleType == 1)
|
||||
{
|
||||
ui->grpDSBattery->setEnabled(false);
|
||||
|
||||
oldDSiBatteryLevel = DSi::I2C->GetBPTWL()->GetBatteryLevel();
|
||||
oldDSiBatteryCharging = DSi::I2C->GetBPTWL()->GetBatteryCharging();
|
||||
auto& dsi = static_cast<DSi&>(*emuThread->NDS);
|
||||
oldDSiBatteryLevel = dsi.I2C.GetBPTWL()->GetBatteryLevel();
|
||||
oldDSiBatteryCharging = dsi.I2C.GetBPTWL()->GetBatteryCharging();
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->grpDSiBattery->setEnabled(false);
|
||||
|
||||
oldDSBatteryLevel = NDS::SPI->GetPowerMan()->GetBatteryLevelOkay();
|
||||
oldDSBatteryLevel = emuThread->NDS->SPI.GetPowerMan()->GetBatteryLevelOkay();
|
||||
}
|
||||
|
||||
updateDSBatteryLevelControls();
|
||||
|
||||
ui->cbDSiBatteryCharging->setChecked(DSi::I2C->GetBPTWL()->GetBatteryCharging());
|
||||
int dsiBatterySliderPos;
|
||||
switch (DSi::I2C->GetBPTWL()->GetBatteryLevel())
|
||||
bool defaultDSiBatteryCharging = (emuThread->NDS->ConsoleType == 1) ? Config::DSiBatteryCharging : false;
|
||||
|
||||
if (emuThread->NDS->ConsoleType == 1)
|
||||
{
|
||||
auto& dsi = static_cast<DSi&>(*emuThread->NDS);
|
||||
ui->cbDSiBatteryCharging->setChecked(dsi.I2C.GetBPTWL()->GetBatteryCharging());
|
||||
int dsiBatterySliderPos = 4;
|
||||
switch (dsi.I2C.GetBPTWL()->GetBatteryLevel())
|
||||
{
|
||||
case DSi_BPTWL::batteryLevel_AlmostEmpty: dsiBatterySliderPos = 0; break;
|
||||
case DSi_BPTWL::batteryLevel_Low: dsiBatterySliderPos = 1; break;
|
||||
case DSi_BPTWL::batteryLevel_Half: dsiBatterySliderPos = 2; break;
|
||||
case DSi_BPTWL::batteryLevel_ThreeQuarters: dsiBatterySliderPos = 3; break;
|
||||
case DSi_BPTWL::batteryLevel_Full: dsiBatterySliderPos = 4; break;
|
||||
}
|
||||
ui->sliderDSiBatteryLevel->setValue(dsiBatterySliderPos);
|
||||
}
|
||||
ui->sliderDSiBatteryLevel->setValue(dsiBatterySliderPos);
|
||||
else
|
||||
{
|
||||
ui->cbDSiBatteryCharging->setChecked(Config::DSiBatteryCharging);
|
||||
ui->sliderDSiBatteryLevel->setValue(Config::DSiBatteryLevel);
|
||||
}
|
||||
|
||||
|
||||
int inst = Platform::InstanceID();
|
||||
if (inst > 0)
|
||||
@ -87,26 +101,28 @@ void PowerManagementDialog::done(int r)
|
||||
{
|
||||
if (r == QDialog::Accepted)
|
||||
{
|
||||
if (NDS::ConsoleType == 1)
|
||||
if (emuThread->NDS->ConsoleType == 1)
|
||||
{
|
||||
Config::DSiBatteryLevel = DSi::I2C->GetBPTWL()->GetBatteryLevel();
|
||||
Config::DSiBatteryCharging = DSi::I2C->GetBPTWL()->GetBatteryCharging();
|
||||
auto& dsi = static_cast<DSi&>(*emuThread->NDS);
|
||||
Config::DSiBatteryLevel = dsi.I2C.GetBPTWL()->GetBatteryLevel();
|
||||
Config::DSiBatteryCharging = dsi.I2C.GetBPTWL()->GetBatteryCharging();
|
||||
}
|
||||
else
|
||||
{
|
||||
Config::DSBatteryLevelOkay = NDS::SPI->GetPowerMan()->GetBatteryLevelOkay();
|
||||
Config::DSBatteryLevelOkay = emuThread->NDS->SPI.GetPowerMan()->GetBatteryLevelOkay();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NDS::ConsoleType == 1)
|
||||
if (emuThread->NDS->ConsoleType == 1)
|
||||
{
|
||||
DSi::I2C->GetBPTWL()->SetBatteryLevel(oldDSiBatteryLevel);
|
||||
DSi::I2C->GetBPTWL()->SetBatteryCharging(oldDSiBatteryCharging);
|
||||
auto& dsi = static_cast<DSi&>(*emuThread->NDS);
|
||||
dsi.I2C.GetBPTWL()->SetBatteryLevel(oldDSiBatteryLevel);
|
||||
dsi.I2C.GetBPTWL()->SetBatteryCharging(oldDSiBatteryCharging);
|
||||
}
|
||||
else
|
||||
{
|
||||
NDS::SPI->GetPowerMan()->SetBatteryLevelOkay(oldDSBatteryLevel);
|
||||
emuThread->NDS->SPI.GetPowerMan()->SetBatteryLevelOkay(oldDSBatteryLevel);
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,17 +133,17 @@ void PowerManagementDialog::done(int r)
|
||||
|
||||
void PowerManagementDialog::on_rbDSBatteryLow_clicked()
|
||||
{
|
||||
NDS::SPI->GetPowerMan()->SetBatteryLevelOkay(false);
|
||||
emuThread->NDS->SPI.GetPowerMan()->SetBatteryLevelOkay(false);
|
||||
}
|
||||
|
||||
void PowerManagementDialog::on_rbDSBatteryOkay_clicked()
|
||||
{
|
||||
NDS::SPI->GetPowerMan()->SetBatteryLevelOkay(true);
|
||||
emuThread->NDS->SPI.GetPowerMan()->SetBatteryLevelOkay(true);
|
||||
}
|
||||
|
||||
void PowerManagementDialog::updateDSBatteryLevelControls()
|
||||
{
|
||||
if (NDS::SPI->GetPowerMan()->GetBatteryLevelOkay())
|
||||
if (emuThread->NDS->SPI.GetPowerMan()->GetBatteryLevelOkay())
|
||||
ui->rbDSBatteryOkay->setChecked(true);
|
||||
else
|
||||
ui->rbDSBatteryLow->setChecked(true);
|
||||
@ -135,23 +151,32 @@ void PowerManagementDialog::updateDSBatteryLevelControls()
|
||||
|
||||
void PowerManagementDialog::on_cbDSiBatteryCharging_toggled()
|
||||
{
|
||||
DSi::I2C->GetBPTWL()->SetBatteryCharging(ui->cbDSiBatteryCharging->isChecked());
|
||||
if (emuThread->NDS->ConsoleType == 1)
|
||||
{
|
||||
auto& dsi = static_cast<DSi&>(*emuThread->NDS);
|
||||
dsi.I2C.GetBPTWL()->SetBatteryCharging(ui->cbDSiBatteryCharging->isChecked());
|
||||
}
|
||||
}
|
||||
|
||||
void PowerManagementDialog::on_sliderDSiBatteryLevel_valueChanged(int value)
|
||||
{
|
||||
if (!inited) return;
|
||||
|
||||
u8 newBatteryLevel;
|
||||
switch (value)
|
||||
if (emuThread->NDS->ConsoleType == 1)
|
||||
{
|
||||
case 0: newBatteryLevel = DSi::I2C->GetBPTWL()->batteryLevel_AlmostEmpty; break;
|
||||
case 1: newBatteryLevel = DSi::I2C->GetBPTWL()->batteryLevel_Low; break;
|
||||
case 2: newBatteryLevel = DSi::I2C->GetBPTWL()->batteryLevel_Half; break;
|
||||
case 3: newBatteryLevel = DSi::I2C->GetBPTWL()->batteryLevel_ThreeQuarters; break;
|
||||
case 4: newBatteryLevel = DSi::I2C->GetBPTWL()->batteryLevel_Full; break;
|
||||
auto& dsi = static_cast<DSi&>(*emuThread->NDS);
|
||||
u8 newBatteryLevel = DSi_BPTWL::batteryLevel_Full;
|
||||
switch (value)
|
||||
{
|
||||
case 0: newBatteryLevel = DSi_BPTWL::batteryLevel_AlmostEmpty; break;
|
||||
case 1: newBatteryLevel = DSi_BPTWL::batteryLevel_Low; break;
|
||||
case 2: newBatteryLevel = DSi_BPTWL::batteryLevel_Half; break;
|
||||
case 3: newBatteryLevel = DSi_BPTWL::batteryLevel_ThreeQuarters; break;
|
||||
case 4: newBatteryLevel = DSi_BPTWL::batteryLevel_Full; break;
|
||||
}
|
||||
dsi.I2C.GetBPTWL()->SetBatteryLevel(newBatteryLevel);
|
||||
}
|
||||
DSi::I2C->GetBPTWL()->SetBatteryLevel(newBatteryLevel);
|
||||
|
||||
updateDSBatteryLevelControls();
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "types.h"
|
||||
|
||||
namespace Ui { class PowerManagementDialog; }
|
||||
class EmuThread;
|
||||
class PowerManagementDialog;
|
||||
|
||||
class PowerManagementDialog : public QDialog
|
||||
@ -32,11 +33,11 @@ class PowerManagementDialog : public QDialog
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PowerManagementDialog(QWidget* parent);
|
||||
explicit PowerManagementDialog(QWidget* parent, EmuThread* emu_thread);
|
||||
~PowerManagementDialog();
|
||||
|
||||
static PowerManagementDialog* currentDlg;
|
||||
static PowerManagementDialog* openDlg(QWidget* parent)
|
||||
static PowerManagementDialog* openDlg(QWidget* parent, EmuThread* emu_thread)
|
||||
{
|
||||
if (currentDlg)
|
||||
{
|
||||
@ -44,7 +45,7 @@ public:
|
||||
return currentDlg;
|
||||
}
|
||||
|
||||
currentDlg = new PowerManagementDialog(parent);
|
||||
currentDlg = new PowerManagementDialog(parent, emu_thread);
|
||||
currentDlg->open();
|
||||
return currentDlg;
|
||||
}
|
||||
@ -64,6 +65,7 @@ private slots:
|
||||
|
||||
private:
|
||||
Ui::PowerManagementDialog* ui;
|
||||
EmuThread* emuThread;
|
||||
|
||||
bool inited;
|
||||
bool oldDSBatteryLevel;
|
||||
|
@ -24,16 +24,16 @@
|
||||
using namespace melonDS;
|
||||
extern EmuThread* emuThread;
|
||||
|
||||
s32 GetMainRAMValue(const u32& addr, const ramInfo_ByteType& byteType)
|
||||
s32 GetMainRAMValue(NDS& nds, const u32& addr, const ramInfo_ByteType& byteType)
|
||||
{
|
||||
switch (byteType)
|
||||
{
|
||||
case ramInfo_OneByte:
|
||||
return *(s8*)(NDS::MainRAM + (addr&NDS::MainRAMMask));
|
||||
return *(s8*)(nds.MainRAM + (addr&nds.MainRAMMask));
|
||||
case ramInfo_TwoBytes:
|
||||
return *(s16*)(NDS::MainRAM + (addr&NDS::MainRAMMask));
|
||||
return *(s16*)(nds.MainRAM + (addr&nds.MainRAMMask));
|
||||
case ramInfo_FourBytes:
|
||||
return *(s32*)(NDS::MainRAM + (addr&NDS::MainRAMMask));
|
||||
return *(s32*)(nds.MainRAM + (addr&nds.MainRAMMask));
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -41,7 +41,7 @@ s32 GetMainRAMValue(const u32& addr, const ramInfo_ByteType& byteType)
|
||||
|
||||
RAMInfoDialog* RAMInfoDialog::currentDlg = nullptr;
|
||||
|
||||
RAMInfoDialog::RAMInfoDialog(QWidget* parent) : QDialog(parent), ui(new Ui::RAMInfoDialog)
|
||||
RAMInfoDialog::RAMInfoDialog(QWidget* parent, EmuThread* emuThread) : QDialog(parent), emuThread(emuThread), ui(new Ui::RAMInfoDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
@ -91,7 +91,7 @@ void RAMInfoDialog::ShowRowsInTable()
|
||||
for (u32 row = scrollValue; row < std::min<u32>(scrollValue+25, RowDataVector->size()); row++)
|
||||
{
|
||||
ramInfo_RowData& rowData = RowDataVector->at(row);
|
||||
rowData.Update(SearchThread->GetSearchByteType());
|
||||
rowData.Update(*emuThread->NDS, SearchThread->GetSearchByteType());
|
||||
|
||||
if (ui->ramTable->item(row, ramInfo_Address) == nullptr)
|
||||
{
|
||||
@ -186,7 +186,7 @@ void RAMInfoDialog::on_ramTable_itemChanged(QTableWidgetItem *item)
|
||||
s32 itemValue = item->text().toInt();
|
||||
|
||||
if (rowData.Value != itemValue)
|
||||
rowData.SetValue(itemValue);
|
||||
rowData.SetValue(*emuThread->NDS, itemValue);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -241,14 +241,14 @@ void RAMSearchThread::run()
|
||||
if (SearchMode == ramInfoSTh_SearchAll || RowDataVector->size() == 0)
|
||||
{
|
||||
// First search mode
|
||||
for (u32 addr = 0x02000000; SearchRunning && addr < 0x02000000+NDS::MainRAMMaxSize; addr += SearchByteType)
|
||||
for (u32 addr = 0x02000000; SearchRunning && addr < 0x02000000+MainRAMMaxSize; addr += SearchByteType)
|
||||
{
|
||||
const s32& value = GetMainRAMValue(addr, SearchByteType);
|
||||
const s32& value = GetMainRAMValue(*emuThread->NDS, addr, SearchByteType);
|
||||
|
||||
RowDataVector->push_back({ addr, value, value });
|
||||
|
||||
// A solution to prevent to call too many slot.
|
||||
u32 newProgress = (int)((addr-0x02000000) / (NDS::MainRAMMaxSize-1.0f) * 100);
|
||||
u32 newProgress = (int)((addr-0x02000000) / (MainRAMMaxSize-1.0f) * 100);
|
||||
if (progress < newProgress)
|
||||
{
|
||||
progress = newProgress;
|
||||
@ -264,7 +264,7 @@ void RAMSearchThread::run()
|
||||
for (u32 row = 0; SearchRunning && row < RowDataVector->size(); row++)
|
||||
{
|
||||
const u32& addr = RowDataVector->at(row).Address;
|
||||
const s32& value = GetMainRAMValue(addr, SearchByteType);
|
||||
const s32& value = GetMainRAMValue(*emuThread->NDS, addr, SearchByteType);
|
||||
|
||||
if (SearchValue == value)
|
||||
newRowDataVector->push_back({ addr, value, value });
|
||||
|
@ -32,6 +32,7 @@ namespace Ui { class RAMInfoDialog; }
|
||||
class RAMInfoDialog;
|
||||
class RAMSearchThread;
|
||||
class RAMUpdateThread;
|
||||
class EmuThread;
|
||||
|
||||
enum ramInfo_ByteType
|
||||
{
|
||||
@ -53,7 +54,7 @@ enum
|
||||
ramInfo_Previous
|
||||
};
|
||||
|
||||
melonDS::s32 GetMainRAMValue(const melonDS::u32& addr, const ramInfo_ByteType& byteType);
|
||||
melonDS::s32 GetMainRAMValue(melonDS::NDS& nds, const melonDS::u32& addr, const ramInfo_ByteType& byteType);
|
||||
|
||||
struct ramInfo_RowData
|
||||
{
|
||||
@ -61,14 +62,14 @@ struct ramInfo_RowData
|
||||
melonDS::s32 Value;
|
||||
melonDS::s32 Previous;
|
||||
|
||||
void Update(const ramInfo_ByteType& byteType)
|
||||
void Update(melonDS::NDS& nds, const ramInfo_ByteType& byteType)
|
||||
{
|
||||
Value = GetMainRAMValue(Address, byteType);
|
||||
Value = GetMainRAMValue(nds, Address, byteType);
|
||||
}
|
||||
|
||||
void SetValue(const melonDS::s32& value)
|
||||
void SetValue(melonDS::NDS& nds, const melonDS::s32& value)
|
||||
{
|
||||
melonDS::NDS::MainRAM[Address&melonDS::NDS::MainRAMMask] = (melonDS::u32)value;
|
||||
nds.MainRAM[Address&nds.MainRAMMask] = (melonDS::u32)value;
|
||||
Value = value;
|
||||
}
|
||||
};
|
||||
@ -78,11 +79,11 @@ class RAMInfoDialog : public QDialog
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RAMInfoDialog(QWidget* parent);
|
||||
explicit RAMInfoDialog(QWidget* parent, EmuThread* emuThread);
|
||||
~RAMInfoDialog();
|
||||
|
||||
static RAMInfoDialog* currentDlg;
|
||||
static RAMInfoDialog* openDlg(QWidget* parent)
|
||||
static RAMInfoDialog* openDlg(QWidget* parent, EmuThread* emuThread)
|
||||
{
|
||||
if (currentDlg)
|
||||
{
|
||||
@ -90,7 +91,7 @@ public:
|
||||
return currentDlg;
|
||||
}
|
||||
|
||||
currentDlg = new RAMInfoDialog(parent);
|
||||
currentDlg = new RAMInfoDialog(parent, emuThread);
|
||||
currentDlg->show();
|
||||
return currentDlg;
|
||||
}
|
||||
@ -118,6 +119,7 @@ private slots:
|
||||
void SetProgressbarValue(const melonDS::u32& value);
|
||||
|
||||
private:
|
||||
EmuThread* emuThread;
|
||||
Ui::RAMInfoDialog* ui;
|
||||
|
||||
RAMSearchThread* SearchThread;
|
||||
|
@ -42,14 +42,13 @@ QString QStringBytes(u64 num)
|
||||
|
||||
ROMInfoDialog* ROMInfoDialog::currentDlg = nullptr;
|
||||
|
||||
ROMInfoDialog::ROMInfoDialog(QWidget* parent) : QDialog(parent), ui(new Ui::ROMInfoDialog)
|
||||
ROMInfoDialog::ROMInfoDialog(QWidget* parent, const melonDS::NDSCart::CartCommon& rom) : QDialog(parent), ui(new Ui::ROMInfoDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
const NDSBanner* banner = NDS::NDSCartSlot->GetCart()->Banner();
|
||||
const NDSHeader& header = NDS::NDSCartSlot->GetCart()->GetHeader();
|
||||
|
||||
const NDSBanner* banner = rom.Banner();
|
||||
const NDSHeader& header = rom.GetHeader();
|
||||
u32 iconData[32 * 32];
|
||||
ROMManager::ROMIcon(banner->Icon, banner->Palette, iconData);
|
||||
iconImage = QImage(reinterpret_cast<u8*>(iconData), 32, 32, QImage::Format_RGBA8888).copy();
|
||||
|
@ -29,17 +29,17 @@
|
||||
|
||||
namespace Ui { class ROMInfoDialog; }
|
||||
class ROMInfoDialog;
|
||||
|
||||
namespace melonDS::NDSCart { class CartCommon; }
|
||||
class ROMInfoDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ROMInfoDialog(QWidget* parent);
|
||||
explicit ROMInfoDialog(QWidget* parent, const melonDS::NDSCart::CartCommon& rom);
|
||||
~ROMInfoDialog();
|
||||
|
||||
static ROMInfoDialog* currentDlg;
|
||||
static ROMInfoDialog* openDlg(QWidget* parent)
|
||||
static ROMInfoDialog* openDlg(QWidget* parent, const melonDS::NDSCart::CartCommon& rom)
|
||||
{
|
||||
if (currentDlg)
|
||||
{
|
||||
@ -47,7 +47,7 @@ public:
|
||||
return currentDlg;
|
||||
}
|
||||
|
||||
currentDlg = new ROMInfoDialog(parent);
|
||||
currentDlg = new ROMInfoDialog(parent, rom);
|
||||
currentDlg->open();
|
||||
return currentDlg;
|
||||
}
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "RTC.h"
|
||||
#include "DSi_I2C.h"
|
||||
#include "FreeBIOS.h"
|
||||
#include "main.h"
|
||||
|
||||
using std::make_unique;
|
||||
using std::pair;
|
||||
@ -316,7 +317,7 @@ bool SavestateExists(int slot)
|
||||
return Platform::FileExists(ssfile);
|
||||
}
|
||||
|
||||
bool LoadState(const std::string& filename)
|
||||
bool LoadState(NDS& nds, const std::string& filename)
|
||||
{
|
||||
FILE* file = fopen(filename.c_str(), "rb");
|
||||
if (file == nullptr)
|
||||
@ -333,7 +334,7 @@ bool LoadState(const std::string& filename)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!NDS::DoSavestate(backup.get()) || backup->Error)
|
||||
if (!nds.DoSavestate(backup.get()) || backup->Error)
|
||||
{ // Back up the emulator's state. If that failed...
|
||||
Platform::Log(Platform::LogLevel::Error, "Failed to back up state, aborting load (from \"%s\")\n", filename.c_str());
|
||||
fclose(file);
|
||||
@ -365,7 +366,7 @@ bool LoadState(const std::string& filename)
|
||||
// Get ready to load the state from the buffer into the emulator
|
||||
std::unique_ptr<Savestate> state = std::make_unique<Savestate>(buffer.data(), size, false);
|
||||
|
||||
if (!NDS::DoSavestate(state.get()) || state->Error)
|
||||
if (!nds.DoSavestate(state.get()) || state->Error)
|
||||
{ // If we couldn't load the savestate from the buffer...
|
||||
Platform::Log(Platform::LogLevel::Error, "Failed to load state file \"%s\" into emulator\n", filename.c_str());
|
||||
return false;
|
||||
@ -390,7 +391,7 @@ bool LoadState(const std::string& filename)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveState(const std::string& filename)
|
||||
bool SaveState(NDS& nds, const std::string& filename)
|
||||
{
|
||||
FILE* file = fopen(filename.c_str(), "wb");
|
||||
|
||||
@ -407,7 +408,7 @@ bool SaveState(const std::string& filename)
|
||||
}
|
||||
|
||||
// Write the savestate to the in-memory buffer
|
||||
NDS::DoSavestate(&state);
|
||||
nds.DoSavestate(&state);
|
||||
|
||||
if (state.Error)
|
||||
{
|
||||
@ -439,7 +440,7 @@ bool SaveState(const std::string& filename)
|
||||
return true;
|
||||
}
|
||||
|
||||
void UndoStateLoad()
|
||||
void UndoStateLoad(NDS& nds)
|
||||
{
|
||||
if (!SavestateLoaded || !BackupState) return;
|
||||
|
||||
@ -448,7 +449,7 @@ void UndoStateLoad()
|
||||
// pray that this works
|
||||
// what do we do if it doesn't???
|
||||
// but it should work.
|
||||
NDS::DoSavestate(BackupState.get());
|
||||
nds.DoSavestate(BackupState.get());
|
||||
|
||||
if (NDSSave && (!PreviousSaveFile.empty()))
|
||||
{
|
||||
@ -457,36 +458,264 @@ void UndoStateLoad()
|
||||
}
|
||||
|
||||
|
||||
void UnloadCheats()
|
||||
void UnloadCheats(NDS& nds)
|
||||
{
|
||||
if (CheatFile)
|
||||
{
|
||||
delete CheatFile;
|
||||
CheatFile = nullptr;
|
||||
NDS::AREngine->SetCodeFile(nullptr);
|
||||
nds.AREngine.SetCodeFile(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadCheats()
|
||||
void LoadCheats(NDS& nds)
|
||||
{
|
||||
UnloadCheats();
|
||||
UnloadCheats(nds);
|
||||
|
||||
std::string filename = GetAssetPath(false, Config::CheatFilePath, ".mch");
|
||||
|
||||
// TODO: check for error (malformed cheat file, ...)
|
||||
CheatFile = new ARCodeFile(filename);
|
||||
|
||||
NDS::AREngine->SetCodeFile(CheatsOn ? CheatFile : nullptr);
|
||||
nds.AREngine.SetCodeFile(CheatsOn ? CheatFile : nullptr);
|
||||
}
|
||||
|
||||
void LoadBIOSFiles()
|
||||
std::optional<std::array<u8, ARM9BIOSSize>> LoadARM9BIOS() noexcept
|
||||
{
|
||||
if (FileHandle* f = OpenLocalFile(Config::BIOS9Path, Read))
|
||||
{
|
||||
std::array<u8, ARM9BIOSSize> bios {};
|
||||
FileRewind(f);
|
||||
FileRead(bios.data(), sizeof(bios), 1, f);
|
||||
CloseFile(f);
|
||||
Log(Info, "ARM9 BIOS loaded from %s\n", Config::BIOS9Path.c_str());
|
||||
return bios;
|
||||
}
|
||||
|
||||
Log(Warn, "ARM9 BIOS not found\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::array<u8, ARM7BIOSSize>> LoadARM7BIOS() noexcept
|
||||
{
|
||||
if (FileHandle* f = OpenLocalFile(Config::BIOS7Path, Read))
|
||||
{
|
||||
std::array<u8, ARM7BIOSSize> bios {};
|
||||
FileRead(bios.data(), sizeof(bios), 1, f);
|
||||
CloseFile(f);
|
||||
Log(Info, "ARM7 BIOS loaded from %s\n", Config::BIOS7Path.c_str());
|
||||
return bios;
|
||||
}
|
||||
|
||||
Log(Warn, "ARM7 BIOS not found\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::array<u8, DSiBIOSSize>> LoadDSiARM9BIOS() noexcept
|
||||
{
|
||||
if (FileHandle* f = OpenLocalFile(Config::DSiBIOS9Path, Read))
|
||||
{
|
||||
std::array<u8, DSiBIOSSize> bios {};
|
||||
FileRead(bios.data(), sizeof(bios), 1, f);
|
||||
CloseFile(f);
|
||||
Log(Info, "ARM9i BIOS loaded from %s\n", Config::DSiBIOS9Path.c_str());
|
||||
return bios;
|
||||
}
|
||||
|
||||
Log(Warn, "ARM9i BIOS not found\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::array<u8, DSiBIOSSize>> LoadDSiARM7BIOS() noexcept
|
||||
{
|
||||
if (FileHandle* f = OpenLocalFile(Config::DSiBIOS7Path, Read))
|
||||
{
|
||||
std::array<u8, DSiBIOSSize> bios {};
|
||||
FileRead(bios.data(), sizeof(bios), 1, f);
|
||||
CloseFile(f);
|
||||
Log(Info, "ARM7i BIOS loaded from %s\n", Config::DSiBIOS7Path.c_str());
|
||||
return bios;
|
||||
}
|
||||
|
||||
Log(Warn, "ARM7i BIOS not found\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
Firmware GenerateFirmware(int type) noexcept
|
||||
{
|
||||
// Construct the default firmware...
|
||||
string settingspath;
|
||||
Firmware firmware = Firmware(type);
|
||||
assert(firmware.Buffer() != nullptr);
|
||||
|
||||
// If using generated firmware, we keep the wi-fi settings on the host disk separately.
|
||||
// Wi-fi access point data includes Nintendo WFC settings,
|
||||
// and if we didn't keep them then the player would have to reset them in each session.
|
||||
// We don't need to save the whole firmware, just the part that may actually change.
|
||||
if (FileHandle* f = OpenLocalFile(Config::WifiSettingsPath, Read))
|
||||
{// If we have Wi-fi settings to load...
|
||||
constexpr unsigned TOTAL_WFC_SETTINGS_SIZE = 3 * (sizeof(Firmware::WifiAccessPoint) + sizeof(Firmware::ExtendedWifiAccessPoint));
|
||||
|
||||
if (!FileRead(firmware.GetExtendedAccessPointPosition(), TOTAL_WFC_SETTINGS_SIZE, 1, f))
|
||||
{ // If we couldn't read the Wi-fi settings from this file...
|
||||
Log(Warn, "Failed to read Wi-fi settings from \"%s\"; using defaults instead\n", Config::WifiSettingsPath.c_str());
|
||||
|
||||
// The access point and extended access point segments might
|
||||
// be in different locations depending on the firmware revision,
|
||||
// but our generated firmware always keeps them next to each other.
|
||||
// (Extended access points first, then regular ones.)
|
||||
firmware.GetAccessPoints() = {
|
||||
Firmware::WifiAccessPoint(type),
|
||||
Firmware::WifiAccessPoint(),
|
||||
Firmware::WifiAccessPoint(),
|
||||
};
|
||||
|
||||
firmware.GetExtendedAccessPoints() = {
|
||||
Firmware::ExtendedWifiAccessPoint(),
|
||||
Firmware::ExtendedWifiAccessPoint(),
|
||||
Firmware::ExtendedWifiAccessPoint(),
|
||||
};
|
||||
firmware.UpdateChecksums();
|
||||
CloseFile(f);
|
||||
}
|
||||
}
|
||||
|
||||
CustomizeFirmware(firmware);
|
||||
|
||||
// If we don't have Wi-fi settings to load,
|
||||
// then the defaults will have already been populated by the constructor.
|
||||
return firmware;
|
||||
}
|
||||
|
||||
std::optional<Firmware> LoadFirmware(int type) noexcept
|
||||
{
|
||||
const string& firmwarepath = type == 1 ? Config::DSiFirmwarePath : Config::FirmwarePath;
|
||||
|
||||
Log(Debug, "SPI firmware: loading from file %s\n", firmwarepath.c_str());
|
||||
|
||||
FileHandle* file = OpenLocalFile(firmwarepath, Read);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
Log(Error, "SPI firmware: couldn't open firmware file!\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
Firmware firmware(file);
|
||||
CloseFile(file);
|
||||
|
||||
if (!firmware.Buffer())
|
||||
{
|
||||
Log(Error, "SPI firmware: couldn't read firmware file!\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
CustomizeFirmware(firmware);
|
||||
|
||||
return firmware;
|
||||
}
|
||||
|
||||
|
||||
std::optional<DSi_NAND::NANDImage> LoadNAND(const std::array<u8, DSiBIOSSize>& arm7ibios) noexcept
|
||||
{
|
||||
FileHandle* nandfile = OpenLocalFile(Config::DSiNANDPath, ReadWriteExisting);
|
||||
if (!nandfile)
|
||||
return std::nullopt;
|
||||
|
||||
DSi_NAND::NANDImage nandImage(nandfile, &arm7ibios[0x8308]);
|
||||
if (!nandImage)
|
||||
{
|
||||
Log(Error, "Failed to parse DSi NAND\n");
|
||||
return std::nullopt;
|
||||
// the NANDImage takes ownership of the FileHandle, no need to clean it up here
|
||||
}
|
||||
|
||||
// scoped so that mount isn't alive when we move the NAND image to DSi::NANDImage
|
||||
{
|
||||
auto mount = DSi_NAND::NANDMount(nandImage);
|
||||
if (!mount)
|
||||
{
|
||||
Log(Error, "Failed to mount DSi NAND\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
DSi_NAND::DSiFirmwareSystemSettings settings {};
|
||||
if (!mount.ReadUserData(settings))
|
||||
{
|
||||
Log(Error, "Failed to read DSi NAND user data\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// override user settings, if needed
|
||||
if (Config::FirmwareOverrideSettings)
|
||||
{
|
||||
// we store relevant strings as UTF-8, so we need to convert them to UTF-16
|
||||
auto converter = wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{};
|
||||
|
||||
// setting up username
|
||||
std::u16string username = converter.from_bytes(Config::FirmwareUsername);
|
||||
size_t usernameLength = std::min(username.length(), (size_t) 10);
|
||||
memset(&settings.Nickname, 0, sizeof(settings.Nickname));
|
||||
memcpy(&settings.Nickname, username.data(), usernameLength * sizeof(char16_t));
|
||||
|
||||
// setting language
|
||||
settings.Language = static_cast<Firmware::Language>(Config::FirmwareLanguage);
|
||||
|
||||
// setting up color
|
||||
settings.FavoriteColor = Config::FirmwareFavouriteColour;
|
||||
|
||||
// setting up birthday
|
||||
settings.BirthdayMonth = Config::FirmwareBirthdayMonth;
|
||||
settings.BirthdayDay = Config::FirmwareBirthdayDay;
|
||||
|
||||
// setup message
|
||||
std::u16string message = converter.from_bytes(Config::FirmwareMessage);
|
||||
size_t messageLength = std::min(message.length(), (size_t) 26);
|
||||
memset(&settings.Message, 0, sizeof(settings.Message));
|
||||
memcpy(&settings.Message, message.data(), messageLength * sizeof(char16_t));
|
||||
|
||||
// TODO: make other items configurable?
|
||||
}
|
||||
|
||||
// fix touchscreen coords
|
||||
settings.TouchCalibrationADC1 = {0, 0};
|
||||
settings.TouchCalibrationPixel1 = {0, 0};
|
||||
settings.TouchCalibrationADC2 = {255 << 4, 191 << 4};
|
||||
settings.TouchCalibrationPixel2 = {255, 191};
|
||||
|
||||
settings.UpdateHash();
|
||||
|
||||
if (!mount.ApplyUserData(settings))
|
||||
{
|
||||
Log(LogLevel::Error, "Failed to write patched DSi NAND user data\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
return nandImage;
|
||||
}
|
||||
|
||||
constexpr int imgsizes[] = {0, 256, 512, 1024, 2048, 4096};
|
||||
std::optional<FATStorage> LoadDSiSDCard() noexcept
|
||||
{
|
||||
if (!Config::DSiSDEnable)
|
||||
return std::nullopt;
|
||||
|
||||
return FATStorage(
|
||||
Config::DSiSDPath,
|
||||
imgsizes[Config::DSiSDSize],
|
||||
Config::DSiSDReadOnly,
|
||||
Config::DSiSDFolderSync ? Config::DSiSDFolderPath : ""
|
||||
);
|
||||
}
|
||||
|
||||
void LoadBIOSFiles(NDS& nds)
|
||||
{
|
||||
if (Config::ExternalBIOSEnable)
|
||||
{
|
||||
if (FileHandle* f = Platform::OpenLocalFile(Config::BIOS9Path, FileMode::Read))
|
||||
{
|
||||
FileRewind(f);
|
||||
FileRead(NDS::ARM9BIOS, sizeof(NDS::ARM9BIOS), 1, f);
|
||||
FileRead(nds.ARM9BIOS, sizeof(NDS::ARM9BIOS), 1, f);
|
||||
|
||||
Log(LogLevel::Info, "ARM9 BIOS loaded from %s\n", Config::BIOS9Path.c_str());
|
||||
Platform::CloseFile(f);
|
||||
@ -496,12 +725,12 @@ void LoadBIOSFiles()
|
||||
Log(LogLevel::Warn, "ARM9 BIOS not found\n");
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
((u32*)NDS::ARM9BIOS)[i] = 0xE7FFDEFF;
|
||||
((u32*)nds.ARM9BIOS)[i] = 0xE7FFDEFF;
|
||||
}
|
||||
|
||||
if (FileHandle* f = Platform::OpenLocalFile(Config::BIOS7Path, FileMode::Read))
|
||||
{
|
||||
FileRead(NDS::ARM7BIOS, sizeof(NDS::ARM7BIOS), 1, f);
|
||||
FileRead(nds.ARM7BIOS, sizeof(NDS::ARM7BIOS), 1, f);
|
||||
|
||||
Log(LogLevel::Info, "ARM7 BIOS loaded from\n", Config::BIOS7Path.c_str());
|
||||
Platform::CloseFile(f);
|
||||
@ -511,21 +740,22 @@ void LoadBIOSFiles()
|
||||
Log(LogLevel::Warn, "ARM7 BIOS not found\n");
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
((u32*)NDS::ARM7BIOS)[i] = 0xE7FFDEFF;
|
||||
((u32*)nds.ARM7BIOS)[i] = 0xE7FFDEFF;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(LogLevel::Info, "Using built-in ARM7 and ARM9 BIOSes\n");
|
||||
memcpy(NDS::ARM9BIOS, bios_arm9_bin, sizeof(bios_arm9_bin));
|
||||
memcpy(NDS::ARM7BIOS, bios_arm7_bin, sizeof(bios_arm7_bin));
|
||||
memcpy(nds.ARM9BIOS, bios_arm9_bin, sizeof(bios_arm9_bin));
|
||||
memcpy(nds.ARM7BIOS, bios_arm7_bin, sizeof(bios_arm7_bin));
|
||||
}
|
||||
|
||||
if (Config::ConsoleType == 1)
|
||||
{
|
||||
DSi& dsi = static_cast<DSi&>(nds);
|
||||
if (FileHandle* f = Platform::OpenLocalFile(Config::DSiBIOS9Path, FileMode::Read))
|
||||
{
|
||||
FileRead(DSi::ARM9iBIOS, sizeof(DSi::ARM9iBIOS), 1, f);
|
||||
FileRead(dsi.ARM9iBIOS, sizeof(DSi::ARM9iBIOS), 1, f);
|
||||
|
||||
Log(LogLevel::Info, "ARM9i BIOS loaded from %s\n", Config::DSiBIOS9Path.c_str());
|
||||
Platform::CloseFile(f);
|
||||
@ -535,13 +765,13 @@ void LoadBIOSFiles()
|
||||
Log(LogLevel::Warn, "ARM9i BIOS not found\n");
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
((u32*)DSi::ARM9iBIOS)[i] = 0xE7FFDEFF;
|
||||
((u32*)dsi.ARM9iBIOS)[i] = 0xE7FFDEFF;
|
||||
}
|
||||
|
||||
if (FileHandle* f = Platform::OpenLocalFile(Config::DSiBIOS7Path, FileMode::Read))
|
||||
{
|
||||
// TODO: check if the first 32 bytes are crapoed
|
||||
FileRead(DSi::ARM7iBIOS, sizeof(DSi::ARM7iBIOS), 1, f);
|
||||
FileRead(dsi.ARM7iBIOS, sizeof(DSi::ARM7iBIOS), 1, f);
|
||||
|
||||
Log(LogLevel::Info, "ARM7i BIOS loaded from %s\n", Config::DSiBIOS7Path.c_str());
|
||||
CloseFile(f);
|
||||
@ -551,14 +781,14 @@ void LoadBIOSFiles()
|
||||
Log(LogLevel::Warn, "ARM7i BIOS not found\n");
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
((u32*)DSi::ARM7iBIOS)[i] = 0xE7FFDEFF;
|
||||
((u32*)dsi.ARM7iBIOS)[i] = 0xE7FFDEFF;
|
||||
}
|
||||
|
||||
if (!Config::DSiFullBIOSBoot)
|
||||
{
|
||||
// herp
|
||||
*(u32*)&DSi::ARM9iBIOS[0] = 0xEAFFFFFE;
|
||||
*(u32*)&DSi::ARM7iBIOS[0] = 0xEAFFFFFE;
|
||||
*(u32*)&dsi.ARM9iBIOS[0] = 0xEAFFFFFE;
|
||||
*(u32*)&dsi.ARM7iBIOS[0] = 0xEAFFFFFE;
|
||||
|
||||
// TODO!!!!
|
||||
// hax the upper 32K out of the goddamn DSi
|
||||
@ -567,11 +797,11 @@ void LoadBIOSFiles()
|
||||
}
|
||||
}
|
||||
|
||||
void EnableCheats(bool enable)
|
||||
void EnableCheats(NDS& nds, bool enable)
|
||||
{
|
||||
CheatsOn = enable;
|
||||
if (CheatFile)
|
||||
NDS::AREngine->SetCodeFile(CheatsOn ? CheatFile : nullptr);
|
||||
nds.AREngine.SetCodeFile(CheatsOn ? CheatFile : nullptr);
|
||||
}
|
||||
|
||||
ARCodeFile* GetCheatFile()
|
||||
@ -580,42 +810,44 @@ ARCodeFile* GetCheatFile()
|
||||
}
|
||||
|
||||
|
||||
void SetBatteryLevels()
|
||||
void SetBatteryLevels(NDS& nds)
|
||||
{
|
||||
if (NDS::ConsoleType == 1)
|
||||
if (nds.ConsoleType == 1)
|
||||
{
|
||||
DSi::I2C->GetBPTWL()->SetBatteryLevel(Config::DSiBatteryLevel);
|
||||
DSi::I2C->GetBPTWL()->SetBatteryCharging(Config::DSiBatteryCharging);
|
||||
auto& dsi = static_cast<DSi&>(nds);
|
||||
dsi.I2C.GetBPTWL()->SetBatteryLevel(Config::DSiBatteryLevel);
|
||||
dsi.I2C.GetBPTWL()->SetBatteryCharging(Config::DSiBatteryCharging);
|
||||
}
|
||||
else
|
||||
{
|
||||
NDS::SPI->GetPowerMan()->SetBatteryLevelOkay(Config::DSBatteryLevelOkay);
|
||||
nds.SPI.GetPowerMan()->SetBatteryLevelOkay(Config::DSBatteryLevelOkay);
|
||||
}
|
||||
}
|
||||
|
||||
void SetDateTime()
|
||||
void SetDateTime(NDS& nds)
|
||||
{
|
||||
QDateTime hosttime = QDateTime::currentDateTime();
|
||||
QDateTime time = hosttime.addSecs(Config::RTCOffset);
|
||||
|
||||
NDS::RTC->SetDateTime(time.date().year(), time.date().month(), time.date().day(),
|
||||
nds.RTC.SetDateTime(time.date().year(), time.date().month(), time.date().day(),
|
||||
time.time().hour(), time.time().minute(), time.time().second());
|
||||
}
|
||||
|
||||
void Reset()
|
||||
void Reset(EmuThread* thread)
|
||||
{
|
||||
NDS::SetConsoleType(Config::ConsoleType);
|
||||
if (Config::ConsoleType == 1) EjectGBACart();
|
||||
LoadBIOSFiles();
|
||||
thread->RecreateConsole();
|
||||
|
||||
InstallFirmware();
|
||||
if (Config::ConsoleType == 1) EjectGBACart(*thread->NDS);
|
||||
LoadBIOSFiles(*thread->NDS);
|
||||
|
||||
InstallFirmware(*thread->NDS);
|
||||
if (Config::ConsoleType == 1)
|
||||
{
|
||||
InstallNAND(&DSi::ARM7iBIOS[0x8308]);
|
||||
InstallNAND(static_cast<DSi&>(*thread->NDS));
|
||||
}
|
||||
NDS::Reset();
|
||||
SetBatteryLevels();
|
||||
SetDateTime();
|
||||
thread->NDS->Reset();
|
||||
SetBatteryLevels(*thread->NDS);
|
||||
SetDateTime(*thread->NDS);
|
||||
|
||||
if ((CartType != -1) && NDSSave)
|
||||
{
|
||||
@ -659,27 +891,27 @@ void Reset()
|
||||
|
||||
if (!BaseROMName.empty())
|
||||
{
|
||||
if (Config::DirectBoot || NDS::NeedsDirectBoot())
|
||||
if (Config::DirectBoot || thread->NDS->NeedsDirectBoot())
|
||||
{
|
||||
NDS::SetupDirectBoot(BaseROMName);
|
||||
thread->NDS->SetupDirectBoot(BaseROMName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LoadBIOS()
|
||||
bool LoadBIOS(EmuThread* thread)
|
||||
{
|
||||
NDS::SetConsoleType(Config::ConsoleType);
|
||||
thread->RecreateConsole();
|
||||
|
||||
LoadBIOSFiles();
|
||||
LoadBIOSFiles(*thread->NDS);
|
||||
|
||||
if (!InstallFirmware())
|
||||
if (!InstallFirmware(*thread->NDS))
|
||||
return false;
|
||||
|
||||
if (Config::ConsoleType == 1 && !InstallNAND(&DSi::ARM7iBIOS[0x8308]))
|
||||
if (Config::ConsoleType == 1 && !InstallNAND(static_cast<DSi&>(*thread->NDS)))
|
||||
return false;
|
||||
|
||||
if (NDS::NeedsDirectBoot())
|
||||
if (thread->NDS->NeedsDirectBoot())
|
||||
return false;
|
||||
|
||||
/*if (NDSSave) delete NDSSave;
|
||||
@ -690,9 +922,9 @@ bool LoadBIOS()
|
||||
BaseROMName = "";
|
||||
BaseAssetName = "";*/
|
||||
|
||||
NDS::Reset();
|
||||
SetBatteryLevels();
|
||||
SetDateTime();
|
||||
thread->NDS->Reset();
|
||||
SetBatteryLevels(*thread->NDS);
|
||||
SetDateTime(*thread->NDS);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -884,7 +1116,7 @@ pair<unique_ptr<Firmware>, string> GenerateDefaultFirmware()
|
||||
return std::make_pair(std::move(firmware), std::move(wfcsettingspath));
|
||||
}
|
||||
|
||||
void LoadUserSettingsFromConfig(Firmware& firmware)
|
||||
void CustomizeFirmware(Firmware& firmware) noexcept
|
||||
{
|
||||
auto& currentData = firmware.GetEffectiveUserData();
|
||||
|
||||
@ -992,13 +1224,13 @@ static Platform::FileHandle* OpenNANDFile() noexcept
|
||||
return nandfile;
|
||||
}
|
||||
|
||||
bool InstallNAND(const u8* es_keyY)
|
||||
bool InstallNAND(DSi& dsi)
|
||||
{
|
||||
Platform::FileHandle* nandfile = OpenNANDFile();
|
||||
if (!nandfile)
|
||||
return false;
|
||||
|
||||
DSi_NAND::NANDImage nandImage(nandfile, es_keyY);
|
||||
DSi_NAND::NANDImage nandImage(nandfile, &dsi.ARM7iBIOS[0x8308]);
|
||||
if (!nandImage)
|
||||
{
|
||||
Log(LogLevel::Error, "Failed to parse DSi NAND\n");
|
||||
@ -1067,11 +1299,11 @@ bool InstallNAND(const u8* es_keyY)
|
||||
}
|
||||
}
|
||||
|
||||
DSi::NANDImage = std::make_unique<DSi_NAND::NANDImage>(std::move(nandImage));
|
||||
dsi.NANDImage = std::make_unique<DSi_NAND::NANDImage>(std::move(nandImage));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InstallFirmware()
|
||||
bool InstallFirmware(NDS& nds)
|
||||
{
|
||||
FirmwareSave.reset();
|
||||
unique_ptr<Firmware> firmware;
|
||||
@ -1098,15 +1330,15 @@ bool InstallFirmware()
|
||||
|
||||
if (Config::FirmwareOverrideSettings)
|
||||
{
|
||||
LoadUserSettingsFromConfig(*firmware);
|
||||
CustomizeFirmware(*firmware);
|
||||
}
|
||||
|
||||
FirmwareSave = std::make_unique<SaveManager>(firmwarepath);
|
||||
|
||||
return NDS::SPI->GetFirmwareMem()->InstallFirmware(std::move(firmware));
|
||||
return nds.SPI.GetFirmwareMem()->InstallFirmware(std::move(firmware));
|
||||
}
|
||||
|
||||
bool LoadROM(QStringList filepath, bool reset)
|
||||
bool LoadROM(EmuThread* emuthread, QStringList filepath, bool reset)
|
||||
{
|
||||
if (filepath.empty()) return false;
|
||||
|
||||
@ -1201,22 +1433,22 @@ bool LoadROM(QStringList filepath, bool reset)
|
||||
BaseROMName = romname;
|
||||
BaseAssetName = romname.substr(0, romname.rfind('.'));
|
||||
|
||||
if (!InstallFirmware())
|
||||
emuthread->RecreateConsole();
|
||||
if (!InstallFirmware(*emuthread->NDS))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (reset)
|
||||
{
|
||||
NDS::SetConsoleType(Config::ConsoleType);
|
||||
NDS::EjectCart();
|
||||
LoadBIOSFiles();
|
||||
emuthread->NDS->EjectCart();
|
||||
LoadBIOSFiles(*emuthread->NDS);
|
||||
if (Config::ConsoleType == 1)
|
||||
InstallNAND(&DSi::ARM7iBIOS[0x8308]);
|
||||
InstallNAND(static_cast<DSi&>(*emuthread->NDS));
|
||||
|
||||
NDS::Reset();
|
||||
SetBatteryLevels();
|
||||
SetDateTime();
|
||||
emuthread->NDS->Reset();
|
||||
SetBatteryLevels(*emuthread->NDS);
|
||||
SetDateTime(*emuthread->NDS);
|
||||
}
|
||||
|
||||
u32 savelen = 0;
|
||||
@ -1238,12 +1470,12 @@ bool LoadROM(QStringList filepath, bool reset)
|
||||
CloseFile(sav);
|
||||
}
|
||||
|
||||
bool res = NDS::LoadCart(filedata, filelen, savedata, savelen);
|
||||
bool res = emuthread->NDS->LoadCart(filedata, filelen, savedata, savelen);
|
||||
if (res && reset)
|
||||
{
|
||||
if (Config::DirectBoot || NDS::NeedsDirectBoot())
|
||||
if (Config::DirectBoot || emuthread->NDS->NeedsDirectBoot())
|
||||
{
|
||||
NDS::SetupDirectBoot(romname);
|
||||
emuthread->NDS->SetupDirectBoot(romname);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1252,7 +1484,7 @@ bool LoadROM(QStringList filepath, bool reset)
|
||||
CartType = 0;
|
||||
NDSSave = new SaveManager(savname);
|
||||
|
||||
LoadCheats();
|
||||
LoadCheats(*emuthread->NDS);
|
||||
}
|
||||
|
||||
if (savedata) delete[] savedata;
|
||||
@ -1260,14 +1492,14 @@ bool LoadROM(QStringList filepath, bool reset)
|
||||
return res;
|
||||
}
|
||||
|
||||
void EjectCart()
|
||||
void EjectCart(NDS& nds)
|
||||
{
|
||||
if (NDSSave) delete NDSSave;
|
||||
NDSSave = nullptr;
|
||||
|
||||
UnloadCheats();
|
||||
UnloadCheats(nds);
|
||||
|
||||
NDS::EjectCart();
|
||||
nds.EjectCart();
|
||||
|
||||
CartType = -1;
|
||||
BaseROMDir = "";
|
||||
@ -1295,7 +1527,7 @@ QString CartLabel()
|
||||
}
|
||||
|
||||
|
||||
bool LoadGBAROM(QStringList filepath)
|
||||
bool LoadGBAROM(NDS& nds, QStringList filepath)
|
||||
{
|
||||
if (Config::ConsoleType == 1) return false;
|
||||
if (filepath.empty()) return false;
|
||||
@ -1408,7 +1640,7 @@ bool LoadGBAROM(QStringList filepath)
|
||||
CloseFile(sav);
|
||||
}
|
||||
|
||||
bool res = NDS::LoadGBACart(filedata, filelen, savedata, savelen);
|
||||
bool res = nds.LoadGBACart(filedata, filelen, savedata, savelen);
|
||||
|
||||
if (res)
|
||||
{
|
||||
@ -1421,14 +1653,14 @@ bool LoadGBAROM(QStringList filepath)
|
||||
return res;
|
||||
}
|
||||
|
||||
void LoadGBAAddon(int type)
|
||||
void LoadGBAAddon(NDS& nds, int type)
|
||||
{
|
||||
if (Config::ConsoleType == 1) return;
|
||||
|
||||
if (GBASave) delete GBASave;
|
||||
GBASave = nullptr;
|
||||
|
||||
NDS::LoadGBAAddon(type);
|
||||
nds.LoadGBAAddon(type);
|
||||
|
||||
GBACartType = type;
|
||||
BaseGBAROMDir = "";
|
||||
@ -1436,12 +1668,12 @@ void LoadGBAAddon(int type)
|
||||
BaseGBAAssetName = "";
|
||||
}
|
||||
|
||||
void EjectGBACart()
|
||||
void EjectGBACart(NDS& nds)
|
||||
{
|
||||
if (GBASave) delete GBASave;
|
||||
GBASave = nullptr;
|
||||
|
||||
NDS::EjectGBACart();
|
||||
nds.EjectGBACart();
|
||||
|
||||
GBACartType = -1;
|
||||
BaseGBAROMDir = "";
|
||||
@ -1471,7 +1703,7 @@ QString GBACartLabel()
|
||||
return ret;
|
||||
}
|
||||
|
||||
case NDS::GBAAddon_RAMExpansion:
|
||||
case GBAAddon_RAMExpansion:
|
||||
return "Memory expansion";
|
||||
}
|
||||
|
||||
|
@ -24,10 +24,19 @@
|
||||
#include "AREngine.h"
|
||||
#include "DSi_NAND.h"
|
||||
|
||||
#include "MemConstants.h"
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace melonDS
|
||||
{
|
||||
class NDS;
|
||||
class DSi;
|
||||
class FATStorage;
|
||||
}
|
||||
class EmuThread;
|
||||
namespace ROMManager
|
||||
{
|
||||
|
||||
@ -37,30 +46,41 @@ extern SaveManager* GBASave;
|
||||
extern std::unique_ptr<SaveManager> FirmwareSave;
|
||||
|
||||
QString VerifySetup();
|
||||
void Reset();
|
||||
bool LoadBIOS();
|
||||
void Reset(EmuThread* thread);
|
||||
bool LoadBIOS(EmuThread* thread);
|
||||
void ClearBackupState();
|
||||
|
||||
bool InstallFirmware();
|
||||
bool InstallNAND(const u8* es_keyY);
|
||||
bool LoadROM(QStringList filepath, bool reset);
|
||||
void EjectCart();
|
||||
std::optional<std::array<u8, ARM9BIOSSize>> LoadARM9BIOS() noexcept;
|
||||
std::optional<std::array<u8, ARM7BIOSSize>> LoadARM7BIOS() noexcept;
|
||||
std::optional<std::array<u8, DSiBIOSSize>> LoadDSiARM9BIOS() noexcept;
|
||||
std::optional<std::array<u8, DSiBIOSSize>> LoadDSiARM7BIOS() noexcept;
|
||||
std::optional<FATStorage> LoadDSiSDCard() noexcept;
|
||||
void CustomizeFirmware(Firmware& firmware) noexcept;
|
||||
Firmware GenerateFirmware(int type) noexcept;
|
||||
/// Loads and customizes a firmware image based on the values in Config
|
||||
std::optional<Firmware> LoadFirmware(int type) noexcept;
|
||||
/// Loads and customizes a NAND image based on the values in Config
|
||||
std::optional<DSi_NAND::NANDImage> LoadNAND(const std::array<u8, DSiBIOSSize>& arm7ibios) noexcept;
|
||||
bool InstallFirmware(NDS& nds);
|
||||
bool InstallNAND(DSi& dsi);
|
||||
bool LoadROM(EmuThread*, QStringList filepath, bool reset);
|
||||
void EjectCart(NDS& nds);
|
||||
bool CartInserted();
|
||||
QString CartLabel();
|
||||
|
||||
bool LoadGBAROM(QStringList filepath);
|
||||
void LoadGBAAddon(int type);
|
||||
void EjectGBACart();
|
||||
bool LoadGBAROM(NDS& nds, QStringList filepath);
|
||||
void LoadGBAAddon(NDS& nds, int type);
|
||||
void EjectGBACart(NDS& nds);
|
||||
bool GBACartInserted();
|
||||
QString GBACartLabel();
|
||||
|
||||
std::string GetSavestateName(int slot);
|
||||
bool SavestateExists(int slot);
|
||||
bool LoadState(const std::string& filename);
|
||||
bool SaveState(const std::string& filename);
|
||||
void UndoStateLoad();
|
||||
bool LoadState(NDS& nds, const std::string& filename);
|
||||
bool SaveState(NDS& nds, const std::string& filename);
|
||||
void UndoStateLoad(NDS& nds);
|
||||
|
||||
void EnableCheats(bool enable);
|
||||
void EnableCheats(NDS& nds, bool enable);
|
||||
ARCodeFile* GetCheatFile();
|
||||
|
||||
void ROMIcon(const u8 (&data)[512], const u16 (&palette)[16], u32 (&iconRef)[32*32]);
|
||||
|
@ -203,6 +203,30 @@ EmuThread::EmuThread(QObject* parent) : QThread(parent)
|
||||
static_cast<ScreenPanelGL*>(mainWindow->panel)->transferLayout(this);
|
||||
}
|
||||
|
||||
std::unique_ptr<NDS> EmuThread::CreateConsole()
|
||||
{
|
||||
if (Config::ConsoleType == 1)
|
||||
{
|
||||
return std::make_unique<melonDS::DSi>();
|
||||
}
|
||||
|
||||
return std::make_unique<melonDS::NDS>();
|
||||
}
|
||||
|
||||
void EmuThread::RecreateConsole()
|
||||
{
|
||||
if (!NDS || NDS->ConsoleType != Config::ConsoleType)
|
||||
{
|
||||
NDS = nullptr; // To ensure the destructor is called before a new one is created
|
||||
NDS::Current = nullptr;
|
||||
|
||||
NDS = CreateConsole();
|
||||
// TODO: Insert ROMs
|
||||
NDS::Current = NDS.get();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EmuThread::updateScreenSettings(bool filter, const WindowInfo& windowInfo, int numScreens, int* screenKind, float* screenMatrix)
|
||||
{
|
||||
screenSettingsLock.lock();
|
||||
@ -318,7 +342,7 @@ void EmuThread::run()
|
||||
u32 mainScreenPos[3];
|
||||
Platform::FileHandle* file;
|
||||
|
||||
NDS::Init();
|
||||
RecreateConsole();
|
||||
|
||||
mainScreenPos[0] = 0;
|
||||
mainScreenPos[1] = 0;
|
||||
@ -340,10 +364,10 @@ void EmuThread::run()
|
||||
videoRenderer = 0;
|
||||
}
|
||||
|
||||
NDS::GPU->InitRenderer(videoRenderer);
|
||||
NDS::GPU->SetRenderSettings(videoRenderer, videoSettings);
|
||||
NDS->GPU.InitRenderer(videoRenderer);
|
||||
NDS->GPU.SetRenderSettings(videoRenderer, videoSettings);
|
||||
|
||||
NDS::SPU->SetInterpolation(Config::AudioInterp);
|
||||
NDS->SPU.SetInterpolation(Config::AudioInterp);
|
||||
|
||||
Input::Init();
|
||||
|
||||
@ -362,7 +386,7 @@ void EmuThread::run()
|
||||
RTC::StateData state;
|
||||
Platform::FileRead(&state, sizeof(state), 1, file);
|
||||
Platform::CloseFile(file);
|
||||
NDS::RTC->SetState(state);
|
||||
NDS->RTC.SetState(state);
|
||||
}
|
||||
|
||||
char melontitle[100];
|
||||
@ -384,8 +408,7 @@ void EmuThread::run()
|
||||
|
||||
if (Input::HotkeyPressed(HK_SolarSensorDecrease))
|
||||
{
|
||||
assert(NDS::GBACartSlot != nullptr);
|
||||
int level = NDS::GBACartSlot->SetInput(GBACart::Input_SolarSensorDown, true);
|
||||
int level = NDS->GBACartSlot.SetInput(GBACart::Input_SolarSensorDown, true);
|
||||
if (level != -1)
|
||||
{
|
||||
char msg[64];
|
||||
@ -395,8 +418,7 @@ void EmuThread::run()
|
||||
}
|
||||
if (Input::HotkeyPressed(HK_SolarSensorIncrease))
|
||||
{
|
||||
assert(NDS::GBACartSlot != nullptr);
|
||||
int level = NDS::GBACartSlot->SetInput(GBACart::Input_SolarSensorUp, true);
|
||||
int level = NDS->GBACartSlot.SetInput(GBACart::Input_SolarSensorUp, true);
|
||||
if (level != -1)
|
||||
{
|
||||
char msg[64];
|
||||
@ -405,40 +427,41 @@ void EmuThread::run()
|
||||
}
|
||||
}
|
||||
|
||||
if (NDS::ConsoleType == 1)
|
||||
if (NDS->ConsoleType == 1)
|
||||
{
|
||||
DSi& dsi = static_cast<DSi&>(*NDS);
|
||||
double currentTime = SDL_GetPerformanceCounter() * perfCountsSec;
|
||||
|
||||
// Handle power button
|
||||
if (Input::HotkeyDown(HK_PowerButton))
|
||||
{
|
||||
DSi::I2C->GetBPTWL()->SetPowerButtonHeld(currentTime);
|
||||
dsi.I2C.GetBPTWL()->SetPowerButtonHeld(currentTime);
|
||||
}
|
||||
else if (Input::HotkeyReleased(HK_PowerButton))
|
||||
{
|
||||
DSi::I2C->GetBPTWL()->SetPowerButtonReleased(currentTime);
|
||||
dsi.I2C.GetBPTWL()->SetPowerButtonReleased(currentTime);
|
||||
}
|
||||
|
||||
// Handle volume buttons
|
||||
if (Input::HotkeyDown(HK_VolumeUp))
|
||||
{
|
||||
DSi::I2C->GetBPTWL()->SetVolumeSwitchHeld(DSi::I2C->GetBPTWL()->volumeKey_Up);
|
||||
dsi.I2C.GetBPTWL()->SetVolumeSwitchHeld(DSi_BPTWL::volumeKey_Up);
|
||||
}
|
||||
else if (Input::HotkeyReleased(HK_VolumeUp))
|
||||
{
|
||||
DSi::I2C->GetBPTWL()->SetVolumeSwitchReleased(DSi::I2C->GetBPTWL()->volumeKey_Up);
|
||||
dsi.I2C.GetBPTWL()->SetVolumeSwitchReleased(DSi_BPTWL::volumeKey_Up);
|
||||
}
|
||||
|
||||
if (Input::HotkeyDown(HK_VolumeDown))
|
||||
{
|
||||
DSi::I2C->GetBPTWL()->SetVolumeSwitchHeld(DSi::I2C->GetBPTWL()->volumeKey_Down);
|
||||
dsi.I2C.GetBPTWL()->SetVolumeSwitchHeld(DSi_BPTWL::volumeKey_Down);
|
||||
}
|
||||
else if (Input::HotkeyReleased(HK_VolumeDown))
|
||||
{
|
||||
DSi::I2C->GetBPTWL()->SetVolumeSwitchReleased(DSi::I2C->GetBPTWL()->volumeKey_Down);
|
||||
dsi.I2C.GetBPTWL()->SetVolumeSwitchReleased(DSi_BPTWL::volumeKey_Down);
|
||||
}
|
||||
|
||||
DSi::I2C->GetBPTWL()->ProcessVolumeSwitchInput(currentTime);
|
||||
dsi.I2C.GetBPTWL()->ProcessVolumeSwitchInput(currentTime);
|
||||
}
|
||||
|
||||
if (EmuRunning == emuStatus_Running || EmuRunning == emuStatus_FrameStep)
|
||||
@ -472,28 +495,28 @@ void EmuThread::run()
|
||||
videoSettings.GL_ScaleFactor = Config::GL_ScaleFactor;
|
||||
videoSettings.GL_BetterPolygons = Config::GL_BetterPolygons;
|
||||
|
||||
NDS::GPU->SetRenderSettings(videoRenderer, videoSettings);
|
||||
NDS->GPU.SetRenderSettings(videoRenderer, videoSettings);
|
||||
}
|
||||
|
||||
// process input and hotkeys
|
||||
NDS::SetKeyMask(Input::InputMask);
|
||||
NDS->SetKeyMask(Input::InputMask);
|
||||
|
||||
if (Input::HotkeyPressed(HK_Lid))
|
||||
{
|
||||
bool lid = !NDS::IsLidClosed();
|
||||
NDS::SetLidClosed(lid);
|
||||
bool lid = !NDS->IsLidClosed();
|
||||
NDS->SetLidClosed(lid);
|
||||
OSD::AddMessage(0, lid ? "Lid closed" : "Lid opened");
|
||||
}
|
||||
|
||||
// microphone input
|
||||
AudioInOut::MicProcess();
|
||||
AudioInOut::MicProcess(*NDS);
|
||||
|
||||
// auto screen layout
|
||||
if (Config::ScreenSizing == Frontend::screenSizing_Auto)
|
||||
{
|
||||
mainScreenPos[2] = mainScreenPos[1];
|
||||
mainScreenPos[1] = mainScreenPos[0];
|
||||
mainScreenPos[0] = NDS::PowerControl9 >> 15;
|
||||
mainScreenPos[0] = NDS->PowerControl9 >> 15;
|
||||
|
||||
int guess;
|
||||
if (mainScreenPos[0] == mainScreenPos[2] &&
|
||||
@ -520,7 +543,7 @@ void EmuThread::run()
|
||||
|
||||
|
||||
// emulate
|
||||
u32 nlines = NDS::RunFrame();
|
||||
u32 nlines = NDS->RunFrame();
|
||||
|
||||
if (ROMManager::NDSSave)
|
||||
ROMManager::NDSSave->CheckFlush();
|
||||
@ -534,12 +557,12 @@ void EmuThread::run()
|
||||
if (!oglContext)
|
||||
{
|
||||
FrontBufferLock.lock();
|
||||
FrontBuffer = NDS::GPU->FrontBuffer;
|
||||
FrontBuffer = NDS->GPU.FrontBuffer;
|
||||
FrontBufferLock.unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
FrontBuffer = NDS::GPU->FrontBuffer;
|
||||
FrontBuffer = NDS->GPU.FrontBuffer;
|
||||
drawScreenGL();
|
||||
}
|
||||
|
||||
@ -563,9 +586,10 @@ void EmuThread::run()
|
||||
oglContext->SetSwapInterval(0);
|
||||
}
|
||||
|
||||
if (Config::DSiVolumeSync && NDS::ConsoleType == 1)
|
||||
if (Config::DSiVolumeSync && NDS->ConsoleType == 1)
|
||||
{
|
||||
u8 volumeLevel = DSi::I2C->GetBPTWL()->GetVolumeLevel();
|
||||
DSi& dsi = static_cast<DSi&>(*NDS);
|
||||
u8 volumeLevel = dsi.I2C.GetBPTWL()->GetVolumeLevel();
|
||||
if (volumeLevel != dsiVolumeLevel)
|
||||
{
|
||||
dsiVolumeLevel = volumeLevel;
|
||||
@ -576,7 +600,7 @@ void EmuThread::run()
|
||||
}
|
||||
|
||||
if (Config::AudioSync && !fastforward)
|
||||
AudioInOut::AudioSync();
|
||||
AudioInOut::AudioSync(*emuThread->NDS);
|
||||
|
||||
double frametimeStep = nlines / (60.0 * 263.0);
|
||||
|
||||
@ -669,16 +693,15 @@ void EmuThread::run()
|
||||
if (file)
|
||||
{
|
||||
RTC::StateData state;
|
||||
NDS::RTC->GetState(state);
|
||||
NDS->RTC.GetState(state);
|
||||
Platform::FileWrite(&state, sizeof(state), 1, file);
|
||||
Platform::CloseFile(file);
|
||||
}
|
||||
|
||||
EmuStatus = emuStatus_Exit;
|
||||
|
||||
NDS::GPU->DeInitRenderer();
|
||||
NDS::DeInit();
|
||||
//Platform::LAN_DeInit();
|
||||
NDS::Current = nullptr;
|
||||
// nds is out of scope, so unique_ptr cleans it up for us
|
||||
}
|
||||
|
||||
void EmuThread::changeWindowTitle(char* title)
|
||||
@ -759,6 +782,7 @@ bool EmuThread::emuIsActive()
|
||||
|
||||
void EmuThread::drawScreenGL()
|
||||
{
|
||||
if (!NDS) return;
|
||||
int w = windowInfo.surface_width;
|
||||
int h = windowInfo.surface_height;
|
||||
float factor = windowInfo.surface_scale;
|
||||
@ -780,10 +804,10 @@ void EmuThread::drawScreenGL()
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
#ifdef OGLRENDERER_ENABLED
|
||||
if (NDS::GPU->Renderer != 0)
|
||||
if (NDS->GPU.Renderer != 0)
|
||||
{
|
||||
// hardware-accelerated render
|
||||
NDS::GPU->CurGLCompositor->BindOutputTexture(frontbuf);
|
||||
NDS->GPU.CurGLCompositor->BindOutputTexture(frontbuf);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@ -791,12 +815,12 @@ void EmuThread::drawScreenGL()
|
||||
// regular render
|
||||
glBindTexture(GL_TEXTURE_2D, screenTexture);
|
||||
|
||||
if (NDS::GPU->Framebuffer[frontbuf][0] && NDS::GPU->Framebuffer[frontbuf][1])
|
||||
if (NDS->GPU.Framebuffer[frontbuf][0] && NDS->GPU.Framebuffer[frontbuf][1])
|
||||
{
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 192, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, NDS::GPU->Framebuffer[frontbuf][0]);
|
||||
GL_UNSIGNED_BYTE, NDS->GPU.Framebuffer[frontbuf][0]);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192+2, 256, 192, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, NDS::GPU->Framebuffer[frontbuf][1]);
|
||||
GL_UNSIGNED_BYTE, NDS->GPU.Framebuffer[frontbuf][1]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -927,7 +951,8 @@ void ScreenHandler::screenOnMousePress(QMouseEvent* event)
|
||||
if (Frontend::GetTouchCoords(x, y, false))
|
||||
{
|
||||
touching = true;
|
||||
NDS::TouchScreen(x, y);
|
||||
assert(emuThread->NDS != nullptr);
|
||||
emuThread->NDS->TouchScreen(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@ -939,7 +964,8 @@ void ScreenHandler::screenOnMouseRelease(QMouseEvent* event)
|
||||
if (touching)
|
||||
{
|
||||
touching = false;
|
||||
NDS::ReleaseScreen();
|
||||
assert(emuThread->NDS != nullptr);
|
||||
emuThread->NDS->ReleaseScreen();
|
||||
}
|
||||
}
|
||||
|
||||
@ -956,7 +982,10 @@ void ScreenHandler::screenOnMouseMove(QMouseEvent* event)
|
||||
int y = event->pos().y();
|
||||
|
||||
if (Frontend::GetTouchCoords(x, y, true))
|
||||
NDS::TouchScreen(x, y);
|
||||
{
|
||||
assert(emuThread->NDS != nullptr);
|
||||
emuThread->NDS->TouchScreen(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenHandler::screenHandleTablet(QTabletEvent* event)
|
||||
@ -974,14 +1003,16 @@ void ScreenHandler::screenHandleTablet(QTabletEvent* event)
|
||||
if (Frontend::GetTouchCoords(x, y, event->type()==QEvent::TabletMove))
|
||||
{
|
||||
touching = true;
|
||||
NDS::TouchScreen(x, y);
|
||||
assert(emuThread->NDS != nullptr);
|
||||
emuThread->NDS->TouchScreen(x, y);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QEvent::TabletRelease:
|
||||
if (touching)
|
||||
{
|
||||
NDS::ReleaseScreen();
|
||||
assert(emuThread->NDS != nullptr);
|
||||
emuThread->NDS->ReleaseScreen();
|
||||
touching = false;
|
||||
}
|
||||
break;
|
||||
@ -1007,14 +1038,16 @@ void ScreenHandler::screenHandleTouch(QTouchEvent* event)
|
||||
if (Frontend::GetTouchCoords(x, y, event->type()==QEvent::TouchUpdate))
|
||||
{
|
||||
touching = true;
|
||||
NDS::TouchScreen(x, y);
|
||||
assert(emuThread->NDS != nullptr);
|
||||
emuThread->NDS->TouchScreen(x, y);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QEvent::TouchEnd:
|
||||
if (touching)
|
||||
{
|
||||
NDS::ReleaseScreen();
|
||||
assert(emuThread->NDS != nullptr);
|
||||
emuThread->NDS->ReleaseScreen();
|
||||
touching = false;
|
||||
}
|
||||
break;
|
||||
@ -1080,16 +1113,17 @@ void ScreenPanelNative::paintEvent(QPaintEvent* event)
|
||||
|
||||
if (emuThread->emuIsActive())
|
||||
{
|
||||
assert(emuThread->NDS != nullptr);
|
||||
emuThread->FrontBufferLock.lock();
|
||||
int frontbuf = emuThread->FrontBuffer;
|
||||
if (!NDS::GPU->Framebuffer[frontbuf][0] || !NDS::GPU->Framebuffer[frontbuf][1])
|
||||
if (!emuThread->NDS->GPU.Framebuffer[frontbuf][0] || !emuThread->NDS->GPU.Framebuffer[frontbuf][1])
|
||||
{
|
||||
emuThread->FrontBufferLock.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(screen[0].scanLine(0), NDS::GPU->Framebuffer[frontbuf][0], 256 * 192 * 4);
|
||||
memcpy(screen[1].scanLine(0), NDS::GPU->Framebuffer[frontbuf][1], 256 * 192 * 4);
|
||||
memcpy(screen[0].scanLine(0), emuThread->NDS->GPU.Framebuffer[frontbuf][0], 256 * 192 * 4);
|
||||
memcpy(screen[1].scanLine(0), emuThread->NDS->GPU.Framebuffer[frontbuf][1], 256 * 192 * 4);
|
||||
emuThread->FrontBufferLock.unlock();
|
||||
|
||||
QRect screenrc(0, 0, 256, 192);
|
||||
@ -1472,7 +1506,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
|
||||
QMenu* submenu = menu->addMenu("Insert add-on cart");
|
||||
|
||||
actInsertGBAAddon[0] = submenu->addAction("Memory expansion");
|
||||
actInsertGBAAddon[0]->setData(QVariant(NDS::GBAAddon_RAMExpansion));
|
||||
actInsertGBAAddon[0]->setData(QVariant(GBAAddon_RAMExpansion));
|
||||
connect(actInsertGBAAddon[0], &QAction::triggered, this, &MainWindow::onInsertGBAAddon);
|
||||
}
|
||||
|
||||
@ -2025,7 +2059,7 @@ void MainWindow::dropEvent(QDropEvent* event)
|
||||
|
||||
if (isNdsRom)
|
||||
{
|
||||
if (!ROMManager::LoadROM(file, true))
|
||||
if (!ROMManager::LoadROM(emuThread, file, true))
|
||||
{
|
||||
// TODO: better error reporting?
|
||||
QMessageBox::critical(this, "melonDS", "Failed to load the DS ROM.");
|
||||
@ -2038,14 +2072,15 @@ void MainWindow::dropEvent(QDropEvent* event)
|
||||
recentFileList.prepend(barredFilename);
|
||||
updateRecentFilesMenu();
|
||||
|
||||
NDS::Start();
|
||||
assert(emuThread->NDS != nullptr);
|
||||
emuThread->NDS->Start();
|
||||
emuThread->emuRun();
|
||||
|
||||
updateCartInserted(false);
|
||||
}
|
||||
else if (isGbaRom)
|
||||
{
|
||||
if (!ROMManager::LoadGBAROM(file))
|
||||
if (!ROMManager::LoadGBAROM(*emuThread->NDS, file))
|
||||
{
|
||||
// TODO: better error reporting?
|
||||
QMessageBox::critical(this, "melonDS", "Failed to load the GBA ROM.");
|
||||
@ -2111,7 +2146,7 @@ bool MainWindow::preloadROMs(QStringList file, QStringList gbafile, bool boot)
|
||||
bool gbaloaded = false;
|
||||
if (!gbafile.isEmpty())
|
||||
{
|
||||
if (!ROMManager::LoadGBAROM(gbafile))
|
||||
if (!ROMManager::LoadGBAROM(*emuThread->NDS, gbafile))
|
||||
{
|
||||
// TODO: better error reporting?
|
||||
QMessageBox::critical(this, "melonDS", "Failed to load the GBA ROM.");
|
||||
@ -2124,7 +2159,7 @@ bool MainWindow::preloadROMs(QStringList file, QStringList gbafile, bool boot)
|
||||
bool ndsloaded = false;
|
||||
if (!file.isEmpty())
|
||||
{
|
||||
if (!ROMManager::LoadROM(file, true))
|
||||
if (!ROMManager::LoadROM(emuThread, file, true))
|
||||
{
|
||||
// TODO: better error reporting?
|
||||
QMessageBox::critical(this, "melonDS", "Failed to load the ROM.");
|
||||
@ -2140,7 +2175,7 @@ bool MainWindow::preloadROMs(QStringList file, QStringList gbafile, bool boot)
|
||||
{
|
||||
if (ndsloaded)
|
||||
{
|
||||
NDS::Start();
|
||||
emuThread->NDS->Start();
|
||||
emuThread->emuRun();
|
||||
}
|
||||
else
|
||||
@ -2333,7 +2368,7 @@ void MainWindow::onOpenFile()
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ROMManager::LoadROM(file, true))
|
||||
if (!ROMManager::LoadROM(emuThread, file, true))
|
||||
{
|
||||
// TODO: better error reporting?
|
||||
QMessageBox::critical(this, "melonDS", "Failed to load the ROM.");
|
||||
@ -2346,7 +2381,8 @@ void MainWindow::onOpenFile()
|
||||
recentFileList.prepend(filename);
|
||||
updateRecentFilesMenu();
|
||||
|
||||
NDS::Start();
|
||||
assert(emuThread->NDS != nullptr);
|
||||
emuThread->NDS->Start();
|
||||
emuThread->emuRun();
|
||||
|
||||
updateCartInserted(false);
|
||||
@ -2431,7 +2467,7 @@ void MainWindow::onClickRecentFile()
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ROMManager::LoadROM(file, true))
|
||||
if (!ROMManager::LoadROM(emuThread, file, true))
|
||||
{
|
||||
// TODO: better error reporting?
|
||||
QMessageBox::critical(this, "melonDS", "Failed to load the ROM.");
|
||||
@ -2443,7 +2479,8 @@ void MainWindow::onClickRecentFile()
|
||||
recentFileList.prepend(filename);
|
||||
updateRecentFilesMenu();
|
||||
|
||||
NDS::Start();
|
||||
assert(emuThread->NDS != nullptr);
|
||||
emuThread->NDS->Start();
|
||||
emuThread->emuRun();
|
||||
|
||||
updateCartInserted(false);
|
||||
@ -2459,7 +2496,7 @@ void MainWindow::onBootFirmware()
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ROMManager::LoadBIOS())
|
||||
if (!ROMManager::LoadBIOS(emuThread))
|
||||
{
|
||||
// TODO: better error reporting?
|
||||
QMessageBox::critical(this, "melonDS", "This firmware is not bootable.");
|
||||
@ -2467,7 +2504,8 @@ void MainWindow::onBootFirmware()
|
||||
return;
|
||||
}
|
||||
|
||||
NDS::Start();
|
||||
assert(emuThread->NDS != nullptr);
|
||||
emuThread->NDS->Start();
|
||||
emuThread->emuRun();
|
||||
}
|
||||
|
||||
@ -2482,7 +2520,7 @@ void MainWindow::onInsertCart()
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ROMManager::LoadROM(file, false))
|
||||
if (!ROMManager::LoadROM(emuThread, file, false))
|
||||
{
|
||||
// TODO: better error reporting?
|
||||
QMessageBox::critical(this, "melonDS", "Failed to load the ROM.");
|
||||
@ -2499,7 +2537,7 @@ void MainWindow::onEjectCart()
|
||||
{
|
||||
emuThread->emuPause();
|
||||
|
||||
ROMManager::EjectCart();
|
||||
ROMManager::EjectCart(*emuThread->NDS);
|
||||
|
||||
emuThread->emuUnpause();
|
||||
|
||||
@ -2517,7 +2555,7 @@ void MainWindow::onInsertGBACart()
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ROMManager::LoadGBAROM(file))
|
||||
if (!ROMManager::LoadGBAROM(*emuThread->NDS, file))
|
||||
{
|
||||
// TODO: better error reporting?
|
||||
QMessageBox::critical(this, "melonDS", "Failed to load the ROM.");
|
||||
@ -2537,7 +2575,7 @@ void MainWindow::onInsertGBAAddon()
|
||||
|
||||
emuThread->emuPause();
|
||||
|
||||
ROMManager::LoadGBAAddon(type);
|
||||
ROMManager::LoadGBAAddon(*emuThread->NDS, type);
|
||||
|
||||
emuThread->emuUnpause();
|
||||
|
||||
@ -2548,7 +2586,7 @@ void MainWindow::onEjectGBACart()
|
||||
{
|
||||
emuThread->emuPause();
|
||||
|
||||
ROMManager::EjectGBACart();
|
||||
ROMManager::EjectGBACart(*emuThread->NDS);
|
||||
|
||||
emuThread->emuUnpause();
|
||||
|
||||
@ -2582,7 +2620,7 @@ void MainWindow::onSaveState()
|
||||
filename = qfilename.toStdString();
|
||||
}
|
||||
|
||||
if (ROMManager::SaveState(filename))
|
||||
if (ROMManager::SaveState(*emuThread->NDS, filename))
|
||||
{
|
||||
char msg[64];
|
||||
if (slot > 0) sprintf(msg, "State saved to slot %d", slot);
|
||||
@ -2637,7 +2675,7 @@ void MainWindow::onLoadState()
|
||||
return;
|
||||
}
|
||||
|
||||
if (ROMManager::LoadState(filename))
|
||||
if (ROMManager::LoadState(*emuThread->NDS, filename))
|
||||
{
|
||||
char msg[64];
|
||||
if (slot > 0) sprintf(msg, "State loaded from slot %d", slot);
|
||||
@ -2657,7 +2695,7 @@ void MainWindow::onLoadState()
|
||||
void MainWindow::onUndoStateLoad()
|
||||
{
|
||||
emuThread->emuPause();
|
||||
ROMManager::UndoStateLoad();
|
||||
ROMManager::UndoStateLoad(*emuThread->NDS);
|
||||
emuThread->emuUnpause();
|
||||
|
||||
OSD::AddMessage(0, "State load undone");
|
||||
@ -2696,7 +2734,7 @@ void MainWindow::onImportSavefile()
|
||||
return;
|
||||
}
|
||||
|
||||
ROMManager::Reset();
|
||||
ROMManager::Reset(emuThread);
|
||||
}
|
||||
|
||||
u32 len = FileLength(f);
|
||||
@ -2705,7 +2743,8 @@ void MainWindow::onImportSavefile()
|
||||
Platform::FileRewind(f);
|
||||
Platform::FileRead(data, len, 1, f);
|
||||
|
||||
NDS::LoadSave(data, len);
|
||||
assert(emuThread->NDS != nullptr);
|
||||
emuThread->NDS->LoadSave(data, len);
|
||||
delete[] data;
|
||||
|
||||
CloseFile(f);
|
||||
@ -2747,7 +2786,7 @@ void MainWindow::onReset()
|
||||
|
||||
actUndoStateLoad->setEnabled(false);
|
||||
|
||||
ROMManager::Reset();
|
||||
ROMManager::Reset(emuThread);
|
||||
|
||||
OSD::AddMessage(0, "Reset");
|
||||
emuThread->emuRun();
|
||||
@ -2758,7 +2797,7 @@ void MainWindow::onStop()
|
||||
if (!RunningSomething) return;
|
||||
|
||||
emuThread->emuPause();
|
||||
NDS::Stop();
|
||||
emuThread->NDS->Stop();
|
||||
}
|
||||
|
||||
void MainWindow::onFrameStep()
|
||||
@ -2775,13 +2814,13 @@ void MainWindow::onOpenDateTime()
|
||||
|
||||
void MainWindow::onOpenPowerManagement()
|
||||
{
|
||||
PowerManagementDialog* dlg = PowerManagementDialog::openDlg(this);
|
||||
PowerManagementDialog* dlg = PowerManagementDialog::openDlg(this, emuThread);
|
||||
}
|
||||
|
||||
void MainWindow::onEnableCheats(bool checked)
|
||||
{
|
||||
Config::EnableCheats = checked?1:0;
|
||||
ROMManager::EnableCheats(Config::EnableCheats != 0);
|
||||
ROMManager::EnableCheats(*emuThread->NDS, Config::EnableCheats != 0);
|
||||
}
|
||||
|
||||
void MainWindow::onSetupCheats()
|
||||
@ -2799,12 +2838,14 @@ void MainWindow::onCheatsDialogFinished(int res)
|
||||
|
||||
void MainWindow::onROMInfo()
|
||||
{
|
||||
ROMInfoDialog* dlg = ROMInfoDialog::openDlg(this);
|
||||
auto cart = emuThread->NDS->NDSCartSlot.GetCart();
|
||||
if (cart)
|
||||
ROMInfoDialog* dlg = ROMInfoDialog::openDlg(this, *cart);
|
||||
}
|
||||
|
||||
void MainWindow::onRAMInfo()
|
||||
{
|
||||
RAMInfoDialog* dlg = RAMInfoDialog::openDlg(this);
|
||||
RAMInfoDialog* dlg = RAMInfoDialog::openDlg(this, emuThread);
|
||||
}
|
||||
|
||||
void MainWindow::onOpenTitleManager()
|
||||
@ -2907,7 +2948,7 @@ void MainWindow::onCameraSettingsFinished(int res)
|
||||
|
||||
void MainWindow::onOpenAudioSettings()
|
||||
{
|
||||
AudioSettingsDialog* dlg = AudioSettingsDialog::openDlg(this, emuThread->emuIsActive());
|
||||
AudioSettingsDialog* dlg = AudioSettingsDialog::openDlg(this, emuThread->emuIsActive(), emuThread);
|
||||
connect(emuThread, &EmuThread::syncVolumeLevel, dlg, &AudioSettingsDialog::onSyncVolumeLevel);
|
||||
connect(emuThread, &EmuThread::windowEmuStart, dlg, &AudioSettingsDialog::onConsoleReset);
|
||||
connect(dlg, &AudioSettingsDialog::updateAudioSettings, this, &MainWindow::onUpdateAudioSettings);
|
||||
@ -2948,17 +2989,18 @@ void MainWindow::onPathSettingsFinished(int res)
|
||||
|
||||
void MainWindow::onUpdateAudioSettings()
|
||||
{
|
||||
NDS::SPU->SetInterpolation(Config::AudioInterp);
|
||||
assert(emuThread->NDS != nullptr);
|
||||
emuThread->NDS->SPU.SetInterpolation(Config::AudioInterp);
|
||||
|
||||
if (Config::AudioBitDepth == 0)
|
||||
NDS::SPU->SetDegrade10Bit(NDS::ConsoleType == 0);
|
||||
emuThread->NDS->SPU.SetDegrade10Bit(emuThread->NDS->ConsoleType == 0);
|
||||
else
|
||||
NDS::SPU->SetDegrade10Bit(Config::AudioBitDepth == 1);
|
||||
emuThread->NDS->SPU.SetDegrade10Bit(Config::AudioBitDepth == 1);
|
||||
}
|
||||
|
||||
void MainWindow::onAudioSettingsFinished(int res)
|
||||
{
|
||||
AudioInOut::UpdateSettings();
|
||||
AudioInOut::UpdateSettings(*emuThread->NDS);
|
||||
}
|
||||
|
||||
void MainWindow::onOpenMPSettings()
|
||||
@ -3313,13 +3355,11 @@ int main(int argc, char** argv)
|
||||
|
||||
#define SANITIZE(var, min, max) { var = std::clamp(var, min, max); }
|
||||
SANITIZE(Config::ConsoleType, 0, 1);
|
||||
SANITIZE(Config::_3DRenderer,
|
||||
0,
|
||||
0 // Minimum, Software renderer
|
||||
#ifdef OGLRENDERER_ENABLED
|
||||
+ 1 // OpenGL Renderer
|
||||
#endif
|
||||
);
|
||||
#ifdef OGLRENDERER_ENABLED
|
||||
SANITIZE(Config::_3DRenderer, 0, 1); // 0 is the software renderer, 1 is the OpenGL renderer
|
||||
#else
|
||||
SANITIZE(Config::_3DRenderer, 0, 0);
|
||||
#endif
|
||||
SANITIZE(Config::ScreenVSyncInterval, 1, 20);
|
||||
SANITIZE(Config::GL_ScaleFactor, 1, 16);
|
||||
SANITIZE(Config::AudioInterp, 0, 3);
|
||||
@ -3333,7 +3373,6 @@ int main(int argc, char** argv)
|
||||
SANITIZE(Config::ScreenAspectBot, 0, AspectRatiosNum);
|
||||
#undef SANITIZE
|
||||
|
||||
AudioInOut::Init();
|
||||
camStarted[0] = false;
|
||||
camStarted[1] = false;
|
||||
camManager[0] = new CameraManager(0, 640, 480, true);
|
||||
@ -3341,7 +3380,6 @@ int main(int argc, char** argv)
|
||||
camManager[0]->setXFlip(Config::Camera[0].XFlip);
|
||||
camManager[1]->setXFlip(Config::Camera[1].XFlip);
|
||||
|
||||
ROMManager::EnableCheats(Config::EnableCheats != 0);
|
||||
|
||||
Input::JoystickID = Config::JoystickID;
|
||||
Input::OpenJoystick();
|
||||
@ -3354,6 +3392,8 @@ int main(int argc, char** argv)
|
||||
emuThread->start();
|
||||
emuThread->emuPause();
|
||||
|
||||
AudioInOut::Init(emuThread);
|
||||
ROMManager::EnableCheats(*emuThread->NDS, Config::EnableCheats != 0);
|
||||
AudioInOut::AudioMute(mainWindow);
|
||||
|
||||
QObject::connect(&melon, &QApplication::applicationStateChanged, mainWindow, &MainWindow::onAppStateChanged);
|
||||
|
@ -40,6 +40,11 @@
|
||||
#include "FrontendUtil.h"
|
||||
#include "duckstation/gl/context.h"
|
||||
|
||||
namespace melonDS
|
||||
{
|
||||
class NDS;
|
||||
}
|
||||
|
||||
class EmuThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -67,7 +72,8 @@ public:
|
||||
QMutex FrontBufferLock;
|
||||
|
||||
void updateScreenSettings(bool filter, const WindowInfo& windowInfo, int numScreens, int* screenKind, float* screenMatrix);
|
||||
|
||||
void RecreateConsole();
|
||||
std::unique_ptr<melonDS::NDS> NDS; // TODO: Proper encapsulation and synchronization
|
||||
signals:
|
||||
void windowUpdate();
|
||||
void windowTitleChange(QString title);
|
||||
@ -90,6 +96,7 @@ signals:
|
||||
void syncVolumeLevel();
|
||||
|
||||
private:
|
||||
std::unique_ptr<melonDS::NDS> CreateConsole();
|
||||
void drawScreenGL();
|
||||
void initOpenGL();
|
||||
void deinitOpenGL();
|
||||
|
Reference in New Issue
Block a user