mirror of
https://github.com/simple64/simple64.git
synced 2026-07-11 09:33:59 +02:00
1200 lines
37 KiB
C++
1200 lines
37 KiB
C++
#include <QString>
|
|
#include <QFileDialog>
|
|
#include <QCloseEvent>
|
|
#include <QActionGroup>
|
|
#include <QDesktopServices>
|
|
#include "settingsdialog.h"
|
|
#include "plugindialog.h"
|
|
#include "hotkeydialog.h"
|
|
#include "cheats.h"
|
|
#include "mainwindow.h"
|
|
#include "ui_mainwindow.h"
|
|
#include "interface/common.h"
|
|
#include "vidext.h"
|
|
#include "netplay/createroom.h"
|
|
#include "netplay/joinroom.h"
|
|
|
|
#include "osal/osal_preproc.h"
|
|
#include "interface/core_commands.h"
|
|
#include "interface/version.h"
|
|
#include "m64p_common.h"
|
|
#include "version.h"
|
|
|
|
#define RECENT_SIZE 10
|
|
|
|
#define SETTINGS_VER 2
|
|
|
|
m64p_video_extension_functions vidExtFunctions = {17,
|
|
qtVidExtFuncInit,
|
|
qtVidExtFuncQuit,
|
|
qtVidExtFuncListModes,
|
|
qtVidExtFuncListRates,
|
|
qtVidExtFuncSetMode,
|
|
qtVidExtFuncSetModeWithRate,
|
|
qtVidExtFuncGLGetProc,
|
|
qtVidExtFuncGLSetAttr,
|
|
qtVidExtFuncGLGetAttr,
|
|
qtVidExtFuncGLSwapBuf,
|
|
qtVidExtFuncSetCaption,
|
|
qtVidExtFuncToggleFS,
|
|
qtVidExtFuncResizeWindow,
|
|
qtVidExtFuncGLGetDefaultFramebuffer,
|
|
qtVidExtFuncInitWithRenderMode,
|
|
qtVidExtFuncGetVkSurface,
|
|
qtVidExtFuncGetVkInstExtensions};
|
|
|
|
void MainWindow::updatePlugins()
|
|
{
|
|
#ifdef PLUGIN_DIR_PATH
|
|
QString pluginPath = PLUGIN_DIR_PATH;
|
|
#else
|
|
QString pluginPath = QCoreApplication::applicationDirPath();
|
|
#endif
|
|
QDir PluginDir(pluginPath);
|
|
PluginDir.setFilter(QDir::Files);
|
|
QStringList Filter;
|
|
Filter.append("");
|
|
QStringList current;
|
|
QString default_value;
|
|
|
|
if (!settings->contains("inputPlugin"))
|
|
{
|
|
Filter.replace(0, "*-input-*");
|
|
current = PluginDir.entryList(Filter);
|
|
default_value = "simple64-input-qt";
|
|
default_value += OSAL_DLL_EXTENSION;
|
|
if (current.isEmpty())
|
|
settings->setValue("inputPlugin", "dummy");
|
|
else if (current.indexOf(default_value) != -1)
|
|
settings->setValue("inputPlugin", default_value);
|
|
else
|
|
settings->setValue("inputPlugin", current.at(0));
|
|
}
|
|
|
|
ui->actionController_Configuration->setEnabled(settings->value("inputPlugin").toString().contains("-qt"));
|
|
}
|
|
|
|
void MainWindow::updateGB(Ui::MainWindow *ui)
|
|
{
|
|
QMenu *GB = new QMenu(this);
|
|
GB->setTitle("Game Boy Cartridges");
|
|
ui->menuFile->insertMenu(ui->actionTake_Screenshot, GB);
|
|
|
|
QAction *fileSelect = new QAction(this);
|
|
QString current = settings->value("Player1GBROM").toString();
|
|
fileSelect->setText("Player 1 ROM: " + current);
|
|
GB->addAction(fileSelect);
|
|
connect(fileSelect, &QAction::triggered, [=]()
|
|
{
|
|
QString filename = QFileDialog::getOpenFileName(this,
|
|
tr("GB ROM File"), NULL, tr("GB ROM Files (*.gb *.gbc)"));
|
|
if (!filename.isNull()) {
|
|
settings->setValue("Player1GBROM", filename);
|
|
QString current = filename;
|
|
fileSelect->setText("Player 1 ROM: " + current);
|
|
} });
|
|
|
|
QAction *fileSelect2 = new QAction(this);
|
|
current = settings->value("Player1GBRAM").toString();
|
|
fileSelect2->setText("Player 1 SAV: " + current);
|
|
GB->addAction(fileSelect2);
|
|
connect(fileSelect2, &QAction::triggered, [=]()
|
|
{
|
|
QString filename = QFileDialog::getOpenFileName(this,
|
|
tr("GB RAM File"), NULL, tr("GB SAV Files (*.sav *.ram)"));
|
|
if (!filename.isNull()) {
|
|
settings->setValue("Player1GBRAM", filename);
|
|
QString current = filename;
|
|
fileSelect2->setText("Player 1 SAV: " + current);
|
|
} });
|
|
|
|
QAction *clearSelect = new QAction(this);
|
|
clearSelect->setText("Clear Player 1 Selections");
|
|
GB->addAction(clearSelect);
|
|
connect(clearSelect, &QAction::triggered, [=]()
|
|
{
|
|
settings->remove("Player1GBROM");
|
|
settings->remove("Player1GBRAM");
|
|
fileSelect->setText("Player 1 ROM: ");
|
|
fileSelect2->setText("Player 1 SAV: "); });
|
|
GB->addSeparator();
|
|
|
|
fileSelect = new QAction(this);
|
|
current = settings->value("Player2GBROM").toString();
|
|
fileSelect->setText("Player 2 ROM: " + current);
|
|
GB->addAction(fileSelect);
|
|
connect(fileSelect, &QAction::triggered, [=]()
|
|
{
|
|
QString filename = QFileDialog::getOpenFileName(this,
|
|
tr("GB ROM File"), NULL, tr("GB ROM Files (*.gb *.gbc)"));
|
|
if (!filename.isNull()) {
|
|
settings->setValue("Player2GBROM", filename);
|
|
QString current = filename;
|
|
fileSelect->setText("Player 2 ROM: " + current);
|
|
} });
|
|
|
|
fileSelect2 = new QAction(this);
|
|
current = settings->value("Player2GBRAM").toString();
|
|
fileSelect2->setText("Player 2 SAV: " + current);
|
|
GB->addAction(fileSelect2);
|
|
connect(fileSelect2, &QAction::triggered, [=]()
|
|
{
|
|
QString filename = QFileDialog::getOpenFileName(this,
|
|
tr("GB RAM File"), NULL, tr("GB SAV Files (*.sav *.ram)"));
|
|
if (!filename.isNull()) {
|
|
settings->setValue("Player2GBRAM", filename);
|
|
QString current = filename;
|
|
fileSelect2->setText("Player 2 SAV: " + current);
|
|
} });
|
|
|
|
clearSelect = new QAction(this);
|
|
clearSelect->setText("Clear Player 2 Selections");
|
|
GB->addAction(clearSelect);
|
|
connect(clearSelect, &QAction::triggered, [=]()
|
|
{
|
|
settings->remove("Player2GBROM");
|
|
settings->remove("Player2GBRAM");
|
|
fileSelect->setText("Player 2 ROM: ");
|
|
fileSelect2->setText("Player 2 SAV: "); });
|
|
GB->addSeparator();
|
|
|
|
fileSelect = new QAction(this);
|
|
current = settings->value("Player3GBROM").toString();
|
|
fileSelect->setText("Player 3 ROM: " + current);
|
|
GB->addAction(fileSelect);
|
|
connect(fileSelect, &QAction::triggered, [=]()
|
|
{
|
|
QString filename = QFileDialog::getOpenFileName(this,
|
|
tr("GB ROM File"), NULL, tr("GB ROM Files (*.gb *.gbc)"));
|
|
if (!filename.isNull()) {
|
|
settings->setValue("Player3GBROM", filename);
|
|
QString current = filename;
|
|
fileSelect->setText("Player 3 ROM: " + current);
|
|
} });
|
|
|
|
fileSelect2 = new QAction(this);
|
|
current = settings->value("Player3GBRAM").toString();
|
|
fileSelect2->setText("Player 3 SAV: " + current);
|
|
GB->addAction(fileSelect2);
|
|
connect(fileSelect2, &QAction::triggered, [=]()
|
|
{
|
|
QString filename = QFileDialog::getOpenFileName(this,
|
|
tr("GB RAM File"), NULL, tr("GB SAV Files (*.sav *.ram)"));
|
|
if (!filename.isNull()) {
|
|
settings->setValue("Player3GBRAM", filename);
|
|
QString current = filename;
|
|
fileSelect2->setText("Player 3 SAV: " + current);
|
|
} });
|
|
|
|
clearSelect = new QAction(this);
|
|
clearSelect->setText("Clear Player 3 Selections");
|
|
GB->addAction(clearSelect);
|
|
connect(clearSelect, &QAction::triggered, [=]()
|
|
{
|
|
settings->remove("Player3GBROM");
|
|
settings->remove("Player3GBRAM");
|
|
fileSelect->setText("Player 3 ROM: ");
|
|
fileSelect2->setText("Player 3 SAV: "); });
|
|
GB->addSeparator();
|
|
|
|
fileSelect = new QAction(this);
|
|
current = settings->value("Player4GBROM").toString();
|
|
fileSelect->setText("Player 4 ROM: " + current);
|
|
GB->addAction(fileSelect);
|
|
connect(fileSelect, &QAction::triggered, [=]()
|
|
{
|
|
QString filename = QFileDialog::getOpenFileName(this,
|
|
tr("GB ROM File"), NULL, tr("GB ROM Files (*.gb *.gbc)"));
|
|
if (!filename.isNull()) {
|
|
settings->setValue("Player4GBROM", filename);
|
|
QString current = filename;
|
|
fileSelect->setText("Player 4 ROM: " + current);
|
|
} });
|
|
|
|
fileSelect2 = new QAction(this);
|
|
current = settings->value("Player4GBRAM").toString();
|
|
fileSelect2->setText("Player 4 SAV: " + current);
|
|
GB->addAction(fileSelect2);
|
|
connect(fileSelect2, &QAction::triggered, [=]()
|
|
{
|
|
QString filename = QFileDialog::getOpenFileName(this,
|
|
tr("GB RAM File"), NULL, tr("GB SAV Files (*.sav *.ram)"));
|
|
if (!filename.isNull()) {
|
|
settings->setValue("Player4GBRAM", filename);
|
|
QString current = filename;
|
|
fileSelect2->setText("Player 4 SAV: " + current);
|
|
} });
|
|
|
|
clearSelect = new QAction(this);
|
|
clearSelect->setText("Clear Player 4 Selections");
|
|
GB->addAction(clearSelect);
|
|
connect(clearSelect, &QAction::triggered, [=]()
|
|
{
|
|
settings->remove("Player4GBROM");
|
|
settings->remove("Player4GBRAM");
|
|
fileSelect->setText("Player 4 ROM: ");
|
|
fileSelect2->setText("Player 4 SAV: "); });
|
|
}
|
|
|
|
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),
|
|
ui(new Ui::MainWindow)
|
|
{
|
|
verbose = 0;
|
|
nogui = 0;
|
|
run_test = 0;
|
|
test_key_value = 225; // Shift/A
|
|
ui->setupUi(this);
|
|
this->setWindowTitle("simple64 build: " + QStringLiteral(GUI_VERSION).mid(0, 7));
|
|
|
|
QString ini_path = QDir(QCoreApplication::applicationDirPath()).filePath("simple64-gui.ini");
|
|
settings = new QSettings(ini_path, QSettings::IniFormat, this);
|
|
|
|
if (!settings->isWritable())
|
|
settings = new QSettings("simple64", "gui", this);
|
|
|
|
if (!settings->contains("version") || settings->value("version").toInt() != SETTINGS_VER)
|
|
{
|
|
settings->clear();
|
|
settings->setValue("version", SETTINGS_VER);
|
|
}
|
|
|
|
restoreGeometry(settings->value("geometry").toByteArray());
|
|
restoreState(settings->value("windowState").toByteArray());
|
|
|
|
QActionGroup *my_slots_group = new QActionGroup(this);
|
|
QAction *my_slots[10];
|
|
OpenRecent = new QMenu(this);
|
|
QMenu *SaveSlot = new QMenu(this);
|
|
OpenRecent->setTitle("Open Recent");
|
|
SaveSlot->setTitle("Change Save Slot");
|
|
ui->menuFile->insertMenu(ui->actionSave_State, OpenRecent);
|
|
ui->menuFile->insertSeparator(ui->actionSave_State);
|
|
ui->menuFile->insertMenu(ui->actionSave_State_To, SaveSlot);
|
|
ui->menuFile->insertSeparator(ui->actionSave_State_To);
|
|
for (int i = 0; i < 10; ++i)
|
|
{
|
|
my_slots[i] = new QAction(this);
|
|
my_slots[i]->setCheckable(true);
|
|
my_slots[i]->setText("Slot " + QString::number(i));
|
|
my_slots[i]->setActionGroup(my_slots_group);
|
|
SaveSlot->addAction(my_slots[i]);
|
|
QAction *temp_slot = my_slots[i];
|
|
connect(temp_slot, &QAction::triggered, [=](bool checked)
|
|
{
|
|
if (checked) {
|
|
(*CoreDoCommand)(M64CMD_STATE_SET_SLOT, i, NULL);
|
|
} });
|
|
}
|
|
|
|
updateOpenRecent();
|
|
updateGB(ui);
|
|
|
|
// migrate from old $CONFIG_PATH$ default
|
|
if (settings->value("configDirPath").toString().startsWith("$"))
|
|
settings->remove("configDirPath");
|
|
|
|
#ifdef CONFIG_DIR_PATH
|
|
settings->setValue("configDirPath", CONFIG_DIR_PATH);
|
|
#endif
|
|
|
|
updatePlugins();
|
|
|
|
if (!settings->contains("volume"))
|
|
settings->setValue("volume", 100);
|
|
VolumeAction *volumeAction = new VolumeAction(tr("Volume"), this);
|
|
connect(volumeAction->slider(), &QSlider::valueChanged, this, &MainWindow::volumeValueChanged);
|
|
volumeAction->slider()->setValue(settings->value("volume").toInt());
|
|
ui->menuEmulation->insertAction(ui->actionMute, volumeAction);
|
|
|
|
coreLib = nullptr;
|
|
gfxPlugin = nullptr;
|
|
rspPlugin = nullptr;
|
|
audioPlugin = nullptr;
|
|
inputPlugin = nullptr;
|
|
loadCoreLib();
|
|
loadPlugins();
|
|
|
|
if (coreLib)
|
|
{
|
|
m64p_handle coreConfigHandle;
|
|
m64p_error res = (*ConfigOpenSection)("Core", &coreConfigHandle);
|
|
if (res == M64ERR_SUCCESS)
|
|
{
|
|
int current_slot = (*ConfigGetParamInt)(coreConfigHandle, "CurrentStateSlot");
|
|
my_slots[current_slot]->setChecked(true);
|
|
}
|
|
}
|
|
|
|
setupDiscord();
|
|
FPSLabel = new QLabel(this);
|
|
statusBar()->addPermanentWidget(FPSLabel);
|
|
}
|
|
|
|
MainWindow::~MainWindow()
|
|
{
|
|
delete ui;
|
|
}
|
|
|
|
void MainWindow::updateApp()
|
|
{
|
|
#ifdef _AUTOUPDATE
|
|
QString disable_update = qEnvironmentVariable("SIMPLE64_DISABLE_UPDATER");
|
|
if (!disable_update.isEmpty())
|
|
return;
|
|
#ifndef __APPLE__
|
|
QNetworkAccessManager *updateManager = new QNetworkAccessManager(this);
|
|
connect(updateManager, &QNetworkAccessManager::finished,
|
|
this, &MainWindow::updateReplyFinished);
|
|
|
|
updateManager->get(QNetworkRequest(QUrl("https://api.github.com/repos/simple64/simple64/releases/latest")));
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void MainWindow::setupDiscord()
|
|
{
|
|
QLibrary *discordLib = new QLibrary((QDir(QCoreApplication::applicationDirPath()).filePath("discord_game_sdk")), this);
|
|
|
|
memset(&discord_app, 0, sizeof(discord_app));
|
|
|
|
DiscordCreateParams params;
|
|
DiscordCreateParamsSetDefault(¶ms);
|
|
params.client_id = 770838334015930398LL;
|
|
params.flags = DiscordCreateFlags_NoRequireDiscord;
|
|
params.event_data = &discord_app;
|
|
|
|
typedef EDiscordResult (*CreatePrototype)(DiscordVersion version, struct DiscordCreateParams *params, struct IDiscordCore **result);
|
|
CreatePrototype createFunction = (CreatePrototype)discordLib->resolve("DiscordCreate");
|
|
if (createFunction)
|
|
createFunction(DISCORD_VERSION, ¶ms, &discord_app.core);
|
|
|
|
if (discord_app.core)
|
|
{
|
|
discord_app.activities = discord_app.core->get_activity_manager(discord_app.core);
|
|
|
|
QTimer *timer = new QTimer(this);
|
|
connect(timer, &QTimer::timeout, this, &MainWindow::discordCallback);
|
|
timer->start(1000);
|
|
}
|
|
}
|
|
|
|
struct Discord_Application *MainWindow::getDiscordApp()
|
|
{
|
|
return &discord_app;
|
|
}
|
|
|
|
void MainWindow::updateDiscordActivity(struct DiscordActivity activity)
|
|
{
|
|
if (discord_app.activities)
|
|
discord_app.activities->update_activity(discord_app.activities, &activity, &discord_app, nullptr);
|
|
}
|
|
|
|
void MainWindow::clearDiscordActivity()
|
|
{
|
|
if (discord_app.activities)
|
|
discord_app.activities->clear_activity(discord_app.activities, &discord_app, nullptr);
|
|
}
|
|
|
|
void MainWindow::discordCallback()
|
|
{
|
|
if (discord_app.core)
|
|
discord_app.core->run_callbacks(discord_app.core);
|
|
}
|
|
|
|
void MainWindow::updateDownloadFinished(QNetworkReply *reply)
|
|
{
|
|
if (!reply->error())
|
|
{
|
|
QTemporaryDir dir;
|
|
dir.setAutoRemove(false);
|
|
if (dir.isValid())
|
|
{
|
|
download_message->done(QDialog::Accepted);
|
|
QString fullpath = dir.filePath(reply->url().fileName());
|
|
QFile file(fullpath);
|
|
file.open(QIODevice::WriteOnly);
|
|
file.write(reply->readAll());
|
|
file.setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner | QFileDevice::ExeOwner);
|
|
file.close();
|
|
QProcess process;
|
|
process.setProgram(fullpath);
|
|
QStringList arguments = {QCoreApplication::applicationDirPath()};
|
|
process.setArguments(arguments);
|
|
process.startDetached();
|
|
reply->deleteLater();
|
|
QCoreApplication::quit();
|
|
}
|
|
}
|
|
reply->deleteLater();
|
|
}
|
|
|
|
void MainWindow::updateReplyFinished(QNetworkReply *reply)
|
|
{
|
|
if (!reply->error())
|
|
{
|
|
QJsonDocument json_doc = QJsonDocument::fromJson(reply->readAll());
|
|
QJsonObject json = json_doc.object();
|
|
if (json.value("target_commitish").toString() != QString(GUI_VERSION))
|
|
{
|
|
QMessageBox::StandardButton reply;
|
|
reply = QMessageBox::question(this, "Update Available", "A newer version is available, update?", QMessageBox::Yes | QMessageBox::No);
|
|
if (reply == QMessageBox::Yes)
|
|
{
|
|
QNetworkAccessManager *updateManager = new QNetworkAccessManager(this);
|
|
connect(updateManager, &QNetworkAccessManager::finished,
|
|
this, &MainWindow::updateDownloadFinished);
|
|
#ifdef _WIN32
|
|
QNetworkRequest req(QUrl("https://github.com/simple64/simple64-updater/releases/latest/download/simple64-updater.exe"));
|
|
#else
|
|
QNetworkRequest req(QUrl("https://github.com/simple64/simple64-updater/releases/latest/download/simple64-updater"));
|
|
#endif
|
|
req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
|
|
updateManager->get(req);
|
|
download_message = new QMessageBox(this);
|
|
download_message->setStandardButtons(QMessageBox::NoButton);
|
|
download_message->setText("Downloading updater");
|
|
download_message->show();
|
|
}
|
|
}
|
|
}
|
|
reply->deleteLater();
|
|
}
|
|
|
|
void MainWindow::volumeValueChanged(int value)
|
|
{
|
|
if (value != settings->value("volume").toInt())
|
|
{
|
|
settings->setValue("volume", value);
|
|
settings->sync();
|
|
(*CoreDoCommand)(M64CMD_CORE_STATE_SET, M64CORE_AUDIO_VOLUME, &value);
|
|
}
|
|
}
|
|
|
|
void MainWindow::setVerbose()
|
|
{
|
|
verbose = 1;
|
|
}
|
|
|
|
void MainWindow::setNoGUI()
|
|
{
|
|
nogui = 1;
|
|
if (!menuBar()->isNativeMenuBar())
|
|
menuBar()->hide();
|
|
statusBar()->hide();
|
|
}
|
|
|
|
int MainWindow::getNoGUI()
|
|
{
|
|
return nogui;
|
|
}
|
|
|
|
void MainWindow::setTest(int value)
|
|
{
|
|
run_test = value;
|
|
}
|
|
|
|
int MainWindow::getTest()
|
|
{
|
|
return run_test;
|
|
}
|
|
|
|
int MainWindow::getVerbose()
|
|
{
|
|
return verbose;
|
|
}
|
|
|
|
void MainWindow::resizeMainWindow(int Width, int Height)
|
|
{
|
|
QSize size = this->size();
|
|
Height += (menuBar()->isNativeMenuBar() ? 0 : ui->menuBar->height()) + ui->statusBar->height();
|
|
if (size.width() != Width || size.height() != Height)
|
|
resize(Width, Height);
|
|
}
|
|
|
|
void MainWindow::toggleFS(int force)
|
|
{
|
|
if (coreLib == nullptr)
|
|
return;
|
|
|
|
int response = M64VIDEO_NONE;
|
|
if (force == M64VIDEO_NONE)
|
|
(*CoreDoCommand)(M64CMD_CORE_STATE_QUERY, M64CORE_VIDEO_MODE, &response);
|
|
if (response == M64VIDEO_WINDOWED || force == M64VIDEO_FULLSCREEN)
|
|
{
|
|
if (!menuBar()->isNativeMenuBar())
|
|
menuBar()->hide();
|
|
statusBar()->hide();
|
|
showFullScreen();
|
|
}
|
|
else if (response == M64VIDEO_FULLSCREEN || force == M64VIDEO_WINDOWED)
|
|
{
|
|
if (!nogui)
|
|
{
|
|
if (!menuBar()->isNativeMenuBar())
|
|
menuBar()->show();
|
|
statusBar()->show();
|
|
}
|
|
showNormal();
|
|
}
|
|
}
|
|
|
|
void MainWindow::closeEvent(QCloseEvent *event)
|
|
{
|
|
stopGame();
|
|
|
|
closePlugins();
|
|
closeCoreLib();
|
|
|
|
if (discord_app.activities)
|
|
discord_app.activities->clear_activity(discord_app.activities, &discord_app, nullptr);
|
|
if (discord_app.core)
|
|
{
|
|
discord_app.core->run_callbacks(discord_app.core);
|
|
discord_app.core->destroy(discord_app.core);
|
|
}
|
|
|
|
settings->setValue("geometry", saveGeometry());
|
|
settings->setValue("windowState", saveState());
|
|
|
|
event->accept();
|
|
}
|
|
|
|
void MainWindow::updateOpenRecent()
|
|
{
|
|
OpenRecent->clear();
|
|
QAction *recent[RECENT_SIZE];
|
|
QStringList list = settings->value("RecentROMs2").toStringList();
|
|
if (list.isEmpty())
|
|
{
|
|
OpenRecent->setEnabled(false);
|
|
return;
|
|
}
|
|
|
|
OpenRecent->setEnabled(true);
|
|
for (int i = 0; i < list.size() && i < RECENT_SIZE; ++i)
|
|
{
|
|
recent[i] = new QAction(this);
|
|
recent[i]->setText(list.at(i));
|
|
OpenRecent->addAction(recent[i]);
|
|
QAction *temp_recent = recent[i];
|
|
connect(temp_recent, &QAction::triggered, [=]()
|
|
{ openROM(list.at(i), "", 0, 0, QJsonObject()); });
|
|
}
|
|
OpenRecent->addSeparator();
|
|
|
|
QAction *clearRecent = new QAction(this);
|
|
clearRecent->setText("Clear List");
|
|
OpenRecent->addAction(clearRecent);
|
|
connect(clearRecent, &QAction::triggered, [=]()
|
|
{
|
|
settings->remove("RecentROMs2");
|
|
updateOpenRecent(); });
|
|
}
|
|
|
|
void MainWindow::showMessage(QString message)
|
|
{
|
|
QMessageBox *msgBox = new QMessageBox(this);
|
|
msgBox->setText(message);
|
|
msgBox->show();
|
|
}
|
|
|
|
void MainWindow::createVkWindow(QVulkanInstance *vulkan_inst)
|
|
{
|
|
my_window = new VkWindow;
|
|
my_window->setVulkanInstance(vulkan_inst);
|
|
|
|
QWidget *container = QWidget::createWindowContainer(my_window, this);
|
|
container->setFocusPolicy(Qt::StrongFocus);
|
|
|
|
my_window->setCursor(Qt::BlankCursor);
|
|
|
|
setCentralWidget(container);
|
|
|
|
my_window->installEventFilter(&keyPressFilter);
|
|
this->installEventFilter(&keyPressFilter);
|
|
frame_timer = new QTimer(this);
|
|
connect(frame_timer, &QTimer::timeout, this, &MainWindow::updateFrameCount);
|
|
frame_timer->start(1000);
|
|
frame_count = 0;
|
|
}
|
|
|
|
void MainWindow::deleteVkWindow()
|
|
{
|
|
QWidget *container = new QWidget(this);
|
|
setCentralWidget(container);
|
|
delete my_window;
|
|
frame_timer->stop();
|
|
frame_timer->deleteLater();
|
|
FPSLabel->clear();
|
|
}
|
|
|
|
void MainWindow::killThread()
|
|
{
|
|
printf("Application hung, exiting\n");
|
|
exit(1); // Force kill the application, it's stuck
|
|
}
|
|
|
|
void MainWindow::stopGame()
|
|
{
|
|
if (!coreLib)
|
|
return;
|
|
|
|
int response;
|
|
(*CoreDoCommand)(M64CMD_CORE_STATE_QUERY, M64CORE_EMU_STATE, &response);
|
|
if (response != M64EMU_STOPPED)
|
|
{
|
|
(*CoreDoCommand)(M64CMD_STOP, 0, NULL);
|
|
kill_timer = new QTimer(this);
|
|
kill_timer->setInterval(5000);
|
|
kill_timer->setSingleShot(true);
|
|
connect(kill_timer, &QTimer::timeout, this, &MainWindow::killThread);
|
|
kill_timer->start();
|
|
while (workerThread->isRunning())
|
|
QCoreApplication::processEvents();
|
|
kill_timer->stop();
|
|
kill_timer->deleteLater();
|
|
}
|
|
}
|
|
|
|
void MainWindow::resetCore()
|
|
{
|
|
closePlugins();
|
|
closeCoreLib();
|
|
loadCoreLib();
|
|
loadPlugins();
|
|
}
|
|
|
|
void MainWindow::openROM(QString filename, QString netplay_ip, int netplay_port, int netplay_player, QJsonObject cheats)
|
|
{
|
|
stopGame();
|
|
|
|
logViewer.clearLog();
|
|
|
|
resetCore();
|
|
|
|
workerThread = new WorkerThread(netplay_ip, netplay_port, netplay_player, cheats, this);
|
|
workerThread->setFileName(filename);
|
|
|
|
QStringList list;
|
|
if (settings->contains("RecentROMs2"))
|
|
list = settings->value("RecentROMs2").toStringList();
|
|
list.removeAll(filename);
|
|
list.prepend(filename);
|
|
if (list.size() > RECENT_SIZE)
|
|
list.removeLast();
|
|
settings->setValue("RecentROMs2", list);
|
|
updateOpenRecent();
|
|
|
|
workerThread->start();
|
|
}
|
|
|
|
void MainWindow::on_actionOpen_ROM_triggered()
|
|
{
|
|
QString filename = QFileDialog::getOpenFileName(this,
|
|
tr("Open ROM"), settings->value("ROMdir").toString(), tr("ROM Files (*.n64 *.N64 *.z64 *.Z64 *.v64 *.V64 *.rom *.ROM *.zip *.ZIP *.7z)"));
|
|
if (!filename.isNull())
|
|
{
|
|
QFileInfo info(filename);
|
|
settings->setValue("ROMdir", info.absoluteDir().absolutePath());
|
|
openROM(filename, "", 0, 0, QJsonObject());
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_actionPlugin_Paths_triggered()
|
|
{
|
|
SettingsDialog *settings = new SettingsDialog(this);
|
|
settings->show();
|
|
}
|
|
|
|
void MainWindow::on_actionStop_Game_triggered()
|
|
{
|
|
stopGame();
|
|
}
|
|
|
|
void MainWindow::on_actionExit_triggered()
|
|
{
|
|
this->close();
|
|
}
|
|
|
|
void MainWindow::on_actionPlugin_Settings_triggered()
|
|
{
|
|
PluginDialog *settings = new PluginDialog(this);
|
|
settings->show();
|
|
}
|
|
|
|
void MainWindow::on_actionPause_Game_triggered()
|
|
{
|
|
int response;
|
|
(*CoreDoCommand)(M64CMD_CORE_STATE_QUERY, M64CORE_EMU_STATE, &response);
|
|
if (response == M64EMU_RUNNING)
|
|
(*CoreDoCommand)(M64CMD_PAUSE, 0, NULL);
|
|
else if (response == M64EMU_PAUSED)
|
|
(*CoreDoCommand)(M64CMD_RESUME, 0, NULL);
|
|
}
|
|
|
|
void MainWindow::on_actionMute_triggered()
|
|
{
|
|
int response;
|
|
(*CoreDoCommand)(M64CMD_CORE_STATE_QUERY, M64CORE_AUDIO_MUTE, &response);
|
|
if (response == 0)
|
|
{
|
|
response = 1;
|
|
(*CoreDoCommand)(M64CMD_CORE_STATE_SET, M64CORE_AUDIO_MUTE, &response);
|
|
}
|
|
else if (response == 1)
|
|
{
|
|
response = 0;
|
|
(*CoreDoCommand)(M64CMD_CORE_STATE_SET, M64CORE_AUDIO_MUTE, &response);
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_actionHard_Reset_triggered()
|
|
{
|
|
(*CoreDoCommand)(M64CMD_RESET, 1, NULL);
|
|
}
|
|
|
|
void MainWindow::on_actionSoft_Reset_triggered()
|
|
{
|
|
(*CoreDoCommand)(M64CMD_RESET, 0, NULL);
|
|
}
|
|
|
|
void MainWindow::on_actionTake_Screenshot_triggered()
|
|
{
|
|
(*CoreDoCommand)(M64CMD_TAKE_NEXT_SCREENSHOT, 0, NULL);
|
|
}
|
|
|
|
void MainWindow::on_actionSave_State_triggered()
|
|
{
|
|
(*CoreDoCommand)(M64CMD_STATE_SAVE, 1, NULL);
|
|
}
|
|
|
|
void MainWindow::on_actionLoad_State_triggered()
|
|
{
|
|
(*CoreDoCommand)(M64CMD_STATE_LOAD, 1, NULL);
|
|
}
|
|
|
|
void MainWindow::on_actionToggle_Fullscreen_triggered()
|
|
{
|
|
int response;
|
|
(*CoreDoCommand)(M64CMD_CORE_STATE_QUERY, M64CORE_VIDEO_MODE, &response);
|
|
if (response == M64VIDEO_WINDOWED)
|
|
{
|
|
response = M64VIDEO_FULLSCREEN;
|
|
(*CoreDoCommand)(M64CMD_CORE_STATE_SET, M64CORE_VIDEO_MODE, &response);
|
|
}
|
|
else if (response == M64VIDEO_FULLSCREEN)
|
|
{
|
|
response = M64VIDEO_WINDOWED;
|
|
(*CoreDoCommand)(M64CMD_CORE_STATE_SET, M64CORE_VIDEO_MODE, &response);
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_actionCheats_triggered()
|
|
{
|
|
QString gameName = getCheatGameName();
|
|
if (!gameName.isEmpty())
|
|
{
|
|
CheatsDialog *cheats = new CheatsDialog(gameName, this);
|
|
cheats->show();
|
|
}
|
|
else
|
|
{
|
|
QMessageBox msgBox;
|
|
msgBox.setText("Game must be running.");
|
|
msgBox.exec();
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_actionSave_State_To_triggered()
|
|
{
|
|
QString filename = QFileDialog::getSaveFileName(this,
|
|
tr("Save State File"), NULL, NULL);
|
|
if (!filename.isNull())
|
|
{
|
|
if (!filename.contains(".st"))
|
|
filename.append(".state");
|
|
(*CoreDoCommand)(M64CMD_STATE_SAVE, 1, filename.toUtf8().data());
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_actionLoad_State_From_triggered()
|
|
{
|
|
QString filename = QFileDialog::getOpenFileName(this,
|
|
tr("Open Save State"), NULL, tr("State Files (*.st* *.pj*)"));
|
|
if (!filename.isNull())
|
|
{
|
|
(*CoreDoCommand)(M64CMD_STATE_LOAD, 1, filename.toUtf8().data());
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_actionController_Configuration_triggered()
|
|
{
|
|
if (!coreLib)
|
|
return;
|
|
|
|
int response;
|
|
(*CoreDoCommand)(M64CMD_CORE_STATE_QUERY, M64CORE_EMU_STATE, &response);
|
|
if (response == M64EMU_STOPPED)
|
|
resetCore();
|
|
|
|
typedef void (*Config_Func)();
|
|
Config_Func PluginConfig = (Config_Func)osal_dynlib_getproc(inputPlugin, "PluginConfig");
|
|
if (PluginConfig)
|
|
PluginConfig();
|
|
}
|
|
|
|
void MainWindow::on_actionHotkey_Configuration_triggered()
|
|
{
|
|
HotkeyDialog *settings = new HotkeyDialog(this);
|
|
settings->show();
|
|
}
|
|
|
|
void MainWindow::on_actionToggle_Speed_Limiter_triggered()
|
|
{
|
|
int value;
|
|
(*CoreDoCommand)(M64CMD_CORE_STATE_QUERY, M64CORE_SPEED_LIMITER, &value);
|
|
value = !value;
|
|
(*CoreDoCommand)(M64CMD_CORE_STATE_SET, M64CORE_SPEED_LIMITER, &value);
|
|
}
|
|
|
|
void MainWindow::on_actionView_Log_triggered()
|
|
{
|
|
logViewer.show();
|
|
}
|
|
|
|
void MainWindow::on_actionCreate_Room_triggered()
|
|
{
|
|
CreateRoom *createRoom = new CreateRoom(this);
|
|
createRoom->show();
|
|
}
|
|
|
|
void MainWindow::on_actionJoin_Room_triggered()
|
|
{
|
|
JoinRoom *joinRoom = new JoinRoom(this);
|
|
joinRoom->show();
|
|
}
|
|
|
|
void MainWindow::on_actionSupport_on_Patreon_triggered()
|
|
{
|
|
QDesktopServices::openUrl(QUrl("https://www.patreon.com/loganmc10"));
|
|
}
|
|
|
|
void MainWindow::on_actionSupport_on_GithubSponser_triggered()
|
|
{
|
|
QDesktopServices::openUrl(QUrl("https://github.com/sponsors/loganmc10"));
|
|
}
|
|
|
|
void MainWindow::on_actionOpen_Discord_Channel_triggered()
|
|
{
|
|
QDesktopServices::openUrl(QUrl("https://discord.gg/tsR3RtYynZ"));
|
|
}
|
|
|
|
WorkerThread *MainWindow::getWorkerThread()
|
|
{
|
|
return workerThread;
|
|
}
|
|
|
|
VkWindow *MainWindow::getVkWindow()
|
|
{
|
|
return my_window;
|
|
}
|
|
|
|
QSettings *MainWindow::getSettings()
|
|
{
|
|
return settings;
|
|
}
|
|
|
|
LogViewer *MainWindow::getLogViewer()
|
|
{
|
|
return &logViewer;
|
|
}
|
|
|
|
m64p_dynlib_handle MainWindow::getAudioPlugin()
|
|
{
|
|
return audioPlugin;
|
|
}
|
|
|
|
m64p_dynlib_handle MainWindow::getRspPlugin()
|
|
{
|
|
return rspPlugin;
|
|
}
|
|
|
|
m64p_dynlib_handle MainWindow::getInputPlugin()
|
|
{
|
|
return inputPlugin;
|
|
}
|
|
|
|
m64p_dynlib_handle MainWindow::getGfxPlugin()
|
|
{
|
|
return gfxPlugin;
|
|
}
|
|
|
|
void MainWindow::closeCoreLib()
|
|
{
|
|
if (coreLib != nullptr)
|
|
{
|
|
(*ConfigSaveFile)();
|
|
(*CoreShutdown)();
|
|
osal_dynlib_close(coreLib);
|
|
coreLib = nullptr;
|
|
}
|
|
}
|
|
|
|
void MainWindow::loadCoreLib()
|
|
{
|
|
#ifdef CORE_LIBRARY_PATH
|
|
QString corePath = CORE_LIBRARY_PATH;
|
|
#else
|
|
QString corePath = QCoreApplication::applicationDirPath();
|
|
#endif
|
|
m64p_error res = osal_dynlib_open(&coreLib, QDir(corePath).filePath(OSAL_DEFAULT_DYNLIB_FILENAME).toUtf8().constData());
|
|
|
|
if (res != M64ERR_SUCCESS)
|
|
{
|
|
QMessageBox msgBox;
|
|
msgBox.setText("Failed to load core library");
|
|
msgBox.exec();
|
|
return;
|
|
}
|
|
|
|
CoreStartup = (ptr_CoreStartup)osal_dynlib_getproc(coreLib, "CoreStartup");
|
|
CoreShutdown = (ptr_CoreShutdown)osal_dynlib_getproc(coreLib, "CoreShutdown");
|
|
CoreDoCommand = (ptr_CoreDoCommand)osal_dynlib_getproc(coreLib, "CoreDoCommand");
|
|
CoreAttachPlugin = (ptr_CoreAttachPlugin)osal_dynlib_getproc(coreLib, "CoreAttachPlugin");
|
|
CoreDetachPlugin = (ptr_CoreDetachPlugin)osal_dynlib_getproc(coreLib, "CoreDetachPlugin");
|
|
CoreOverrideVidExt = (ptr_CoreOverrideVidExt)osal_dynlib_getproc(coreLib, "CoreOverrideVidExt");
|
|
|
|
ConfigGetUserConfigPath = (ptr_ConfigGetUserConfigPath)osal_dynlib_getproc(coreLib, "ConfigGetUserConfigPath");
|
|
ConfigSaveFile = (ptr_ConfigSaveFile)osal_dynlib_getproc(coreLib, "ConfigSaveFile");
|
|
ConfigGetParameterHelp = (ptr_ConfigGetParameterHelp)osal_dynlib_getproc(coreLib, "ConfigGetParameterHelp");
|
|
ConfigGetParamInt = (ptr_ConfigGetParamInt)osal_dynlib_getproc(coreLib, "ConfigGetParamInt");
|
|
ConfigGetParamFloat = (ptr_ConfigGetParamFloat)osal_dynlib_getproc(coreLib, "ConfigGetParamFloat");
|
|
ConfigGetParamBool = (ptr_ConfigGetParamBool)osal_dynlib_getproc(coreLib, "ConfigGetParamBool");
|
|
ConfigGetParamString = (ptr_ConfigGetParamString)osal_dynlib_getproc(coreLib, "ConfigGetParamString");
|
|
ConfigSetParameter = (ptr_ConfigSetParameter)osal_dynlib_getproc(coreLib, "ConfigSetParameter");
|
|
ConfigDeleteSection = (ptr_ConfigDeleteSection)osal_dynlib_getproc(coreLib, "ConfigDeleteSection");
|
|
ConfigOpenSection = (ptr_ConfigOpenSection)osal_dynlib_getproc(coreLib, "ConfigOpenSection");
|
|
ConfigSaveSection = (ptr_ConfigSaveSection)osal_dynlib_getproc(coreLib, "ConfigSaveSection");
|
|
ConfigListParameters = (ptr_ConfigListParameters)osal_dynlib_getproc(coreLib, "ConfigListParameters");
|
|
ConfigGetSharedDataFilepath = (ptr_ConfigGetSharedDataFilepath)osal_dynlib_getproc(coreLib, "ConfigGetSharedDataFilepath");
|
|
|
|
CoreAddCheat = (ptr_CoreAddCheat)osal_dynlib_getproc(coreLib, "CoreAddCheat");
|
|
|
|
QString qtConfigDir = settings->value("configDirPath").toString();
|
|
|
|
if (!qtConfigDir.isEmpty())
|
|
(*CoreStartup)(CORE_API_VERSION, qtConfigDir.toUtf8().constData() /*Config dir*/, QCoreApplication::applicationDirPath().toUtf8().constData(), (char *)"Core", DebugCallback, NULL, NULL);
|
|
else
|
|
(*CoreStartup)(CORE_API_VERSION, NULL /*Config dir*/, QCoreApplication::applicationDirPath().toUtf8().constData(), (char *)"Core", DebugCallback, NULL, NULL);
|
|
|
|
CoreOverrideVidExt(&vidExtFunctions);
|
|
}
|
|
|
|
void MainWindow::closePlugins()
|
|
{
|
|
ptr_PluginShutdown PluginShutdown;
|
|
|
|
if (gfxPlugin != nullptr)
|
|
{
|
|
PluginShutdown = (ptr_PluginShutdown)osal_dynlib_getproc(gfxPlugin, "PluginShutdown");
|
|
(*PluginShutdown)();
|
|
osal_dynlib_close(gfxPlugin);
|
|
gfxPlugin = nullptr;
|
|
}
|
|
if (audioPlugin != nullptr)
|
|
{
|
|
PluginShutdown = (ptr_PluginShutdown)osal_dynlib_getproc(audioPlugin, "PluginShutdown");
|
|
(*PluginShutdown)();
|
|
osal_dynlib_close(audioPlugin);
|
|
audioPlugin = nullptr;
|
|
}
|
|
if (inputPlugin != nullptr)
|
|
{
|
|
PluginShutdown = (ptr_PluginShutdown)osal_dynlib_getproc(inputPlugin, "PluginShutdown");
|
|
(*PluginShutdown)();
|
|
osal_dynlib_close(inputPlugin);
|
|
inputPlugin = nullptr;
|
|
}
|
|
if (rspPlugin != nullptr)
|
|
{
|
|
PluginShutdown = (ptr_PluginShutdown)osal_dynlib_getproc(rspPlugin, "PluginShutdown");
|
|
(*PluginShutdown)();
|
|
osal_dynlib_close(rspPlugin);
|
|
rspPlugin = nullptr;
|
|
}
|
|
}
|
|
|
|
typedef void (*ptr_VolumeSetLevel)(int level);
|
|
void MainWindow::loadPlugins()
|
|
{
|
|
if (coreLib == nullptr)
|
|
return;
|
|
|
|
ptr_VolumeSetLevel VolumeSetLevel;
|
|
ptr_PluginStartup PluginStartup;
|
|
ptr_PluginGetVersion PluginGetVersion;
|
|
m64p_error res;
|
|
QMessageBox msgBox;
|
|
#ifdef PLUGIN_DIR_PATH
|
|
QString pluginPath = PLUGIN_DIR_PATH;
|
|
#else
|
|
QString pluginPath = QCoreApplication::applicationDirPath();
|
|
#endif
|
|
QString file_path;
|
|
QString plugin_path;
|
|
|
|
file_path = "simple64-video-parallel";
|
|
file_path += OSAL_DLL_EXTENSION;
|
|
plugin_path = QDir(pluginPath).filePath(file_path);
|
|
|
|
res = osal_dynlib_open(&gfxPlugin, plugin_path.toUtf8().constData());
|
|
if (res != M64ERR_SUCCESS)
|
|
{
|
|
msgBox.setText("Failed to load video plugin");
|
|
msgBox.exec();
|
|
return;
|
|
}
|
|
|
|
PluginGetVersion = (ptr_PluginGetVersion)osal_dynlib_getproc(gfxPlugin, "PluginGetVersion");
|
|
const char *pluginName;
|
|
(*PluginGetVersion)(NULL, NULL, NULL, &pluginName, NULL);
|
|
if (strcmp("parallel", pluginName))
|
|
{
|
|
osal_dynlib_close(gfxPlugin);
|
|
gfxPlugin = nullptr;
|
|
msgBox.setText("Incorrect GFX plugin");
|
|
msgBox.exec();
|
|
return;
|
|
}
|
|
|
|
PluginStartup = (ptr_PluginStartup)osal_dynlib_getproc(gfxPlugin, "PluginStartup");
|
|
(*PluginStartup)(coreLib, (char *)"Video", DebugCallback);
|
|
|
|
file_path = "simple64-audio-sdl2";
|
|
file_path += OSAL_DLL_EXTENSION;
|
|
plugin_path = QDir(pluginPath).filePath(file_path);
|
|
|
|
res = osal_dynlib_open(&audioPlugin, plugin_path.toUtf8().constData());
|
|
if (res != M64ERR_SUCCESS)
|
|
{
|
|
msgBox.setText("Failed to load audio plugin");
|
|
msgBox.exec();
|
|
return;
|
|
}
|
|
|
|
PluginGetVersion = (ptr_PluginGetVersion)osal_dynlib_getproc(audioPlugin, "PluginGetVersion");
|
|
(*PluginGetVersion)(NULL, NULL, NULL, &pluginName, NULL);
|
|
if (strcmp("simple64 SDL2 Audio Plugin", pluginName))
|
|
{
|
|
osal_dynlib_close(audioPlugin);
|
|
audioPlugin = nullptr;
|
|
msgBox.setText("Incorrect Audio plugin");
|
|
msgBox.exec();
|
|
return;
|
|
}
|
|
|
|
PluginStartup = (ptr_PluginStartup)osal_dynlib_getproc(audioPlugin, "PluginStartup");
|
|
(*PluginStartup)(coreLib, (char *)"Audio", DebugCallback);
|
|
int volume = 100;
|
|
if (settings->contains("volume"))
|
|
volume = settings->value("volume").toInt();
|
|
VolumeSetLevel = (ptr_VolumeSetLevel)osal_dynlib_getproc(audioPlugin, "VolumeSetLevel");
|
|
(*VolumeSetLevel)(volume);
|
|
|
|
res = osal_dynlib_open(&inputPlugin, QDir(pluginPath).filePath(settings->value("inputPlugin").toString()).toUtf8().constData());
|
|
if (res != M64ERR_SUCCESS)
|
|
{
|
|
msgBox.setText("Failed to load input plugin");
|
|
msgBox.exec();
|
|
return;
|
|
}
|
|
PluginStartup = (ptr_PluginStartup)osal_dynlib_getproc(inputPlugin, "PluginStartup");
|
|
if (settings->value("inputPlugin").toString().contains("-qt"))
|
|
(*PluginStartup)(coreLib, this, DebugCallback);
|
|
else
|
|
(*PluginStartup)(coreLib, (char *)"Input", DebugCallback);
|
|
|
|
file_path = "simple64-rsp-parallel";
|
|
file_path += OSAL_DLL_EXTENSION;
|
|
plugin_path = QDir(pluginPath).filePath(file_path);
|
|
|
|
res = osal_dynlib_open(&rspPlugin, plugin_path.toUtf8().constData());
|
|
if (res != M64ERR_SUCCESS)
|
|
{
|
|
msgBox.setText("Failed to load rsp plugin");
|
|
msgBox.exec();
|
|
return;
|
|
}
|
|
|
|
PluginGetVersion = (ptr_PluginGetVersion)osal_dynlib_getproc(rspPlugin, "PluginGetVersion");
|
|
(*PluginGetVersion)(NULL, NULL, NULL, &pluginName, NULL);
|
|
if (strcmp("ParaLLEl RSP", pluginName))
|
|
{
|
|
osal_dynlib_close(rspPlugin);
|
|
rspPlugin = nullptr;
|
|
msgBox.setText("Incorrect RSP plugin");
|
|
msgBox.exec();
|
|
return;
|
|
}
|
|
|
|
PluginStartup = (ptr_PluginStartup)osal_dynlib_getproc(rspPlugin, "PluginStartup");
|
|
(*PluginStartup)(coreLib, (char *)"RSP", DebugCallback);
|
|
}
|
|
|
|
m64p_dynlib_handle MainWindow::getCoreLib()
|
|
{
|
|
return coreLib;
|
|
}
|
|
|
|
void MainWindow::addFrameCount()
|
|
{
|
|
++frame_count;
|
|
}
|
|
|
|
void MainWindow::simulateInput()
|
|
{
|
|
if (run_test % 2)
|
|
(*CoreDoCommand)(M64CMD_SEND_SDL_KEYDOWN, test_key_value, NULL);
|
|
else
|
|
{
|
|
(*CoreDoCommand)(M64CMD_SEND_SDL_KEYUP, test_key_value, NULL);
|
|
if (test_key_value == 40)
|
|
test_key_value = 225; // Enter/Start
|
|
else
|
|
test_key_value = 40;
|
|
}
|
|
printf("%u\n", frame_count);
|
|
if (run_test == 1)
|
|
{
|
|
if (frame_count == 0)
|
|
abort();
|
|
else
|
|
(*CoreDoCommand)(M64CMD_STOP, 0, NULL);
|
|
}
|
|
--run_test;
|
|
}
|
|
|
|
void MainWindow::updateFrameCount()
|
|
{
|
|
if (run_test)
|
|
simulateInput();
|
|
QString FPS = QString("%1 FPS").arg(frame_count);
|
|
if (m_cheatsEnabled)
|
|
{
|
|
FPS.prepend("Cheats Enabled ");
|
|
}
|
|
FPSLabel->setText(FPS);
|
|
frame_count = 0;
|
|
}
|
|
|
|
void MainWindow::setCheats(QJsonObject cheatsData, bool netplay)
|
|
{
|
|
if (!netplay)
|
|
{
|
|
QString gameName = getCheatGameName();
|
|
QJsonObject gameData = loadCheatData(gameName);
|
|
cheatsData = getCheatsFromSettings(gameName, gameData);
|
|
}
|
|
m_cheatsEnabled = loadCheats(cheatsData);
|
|
}
|