Refactor so parallel-rdp is in charge of polling inputs and not the EmuThread
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
#include <Scheduler.hpp>
|
||||
|
||||
namespace n64 {
|
||||
Core::Core(ParallelRDP ¶llel) : cpu(std::make_unique<Interpreter>(parallel)) {}
|
||||
Core::Core() : cpu(std::make_unique<Interpreter>(parallel)) {}
|
||||
|
||||
void Core::Stop() {
|
||||
render = false;
|
||||
@@ -106,15 +106,15 @@ void Core::Serialize() {
|
||||
}
|
||||
|
||||
void Core::Deserialize() {
|
||||
std::vector<u8> dVER(serialized[slot].begin(), serialized[slot].begin() + verSize);
|
||||
std::vector dVER(serialized[slot].begin(), serialized[slot].begin() + verSize);
|
||||
if (dVER[0] != (KAIZEN_VERSION >> 8) || dVER[1] != (KAIZEN_VERSION >> 4) || dVER[2] != (KAIZEN_VERSION & 0xFF)) {
|
||||
Util::panic("PROBLEMI!");
|
||||
}
|
||||
|
||||
cpu->GetMem().Deserialize(
|
||||
std::vector<u8>(serialized[slot].begin() + verSize, serialized[slot].begin() + verSize + memSize));
|
||||
cpu->Deserialize(std::vector<u8>(serialized[slot].begin() + verSize + memSize,
|
||||
serialized[slot].begin() + verSize + memSize + cpuSize));
|
||||
std::vector(serialized[slot].begin() + verSize, serialized[slot].begin() + verSize + memSize));
|
||||
cpu->Deserialize(
|
||||
std::vector(serialized[slot].begin() + verSize + memSize, serialized[slot].begin() + verSize + memSize + cpuSize));
|
||||
serialized[slot].erase(serialized[slot].begin(), serialized[slot].end());
|
||||
}
|
||||
} // namespace n64
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
#pragma once
|
||||
#include <ParallelRDPWrapper.hpp>
|
||||
#include <backend/core/Interpreter.hpp>
|
||||
#include <backend/core/JIT.hpp>
|
||||
#include <string>
|
||||
|
||||
struct Window;
|
||||
struct Event;
|
||||
|
||||
namespace n64 {
|
||||
struct Core {
|
||||
explicit Core(ParallelRDP &);
|
||||
explicit Core();
|
||||
void Stop();
|
||||
void LoadROM(const std::string &);
|
||||
[[nodiscard]] bool LoadTAS(const fs::path &) const;
|
||||
@@ -29,5 +27,6 @@ struct Core {
|
||||
std::vector<u8> serialized[10]{};
|
||||
size_t memSize{}, cpuSize{}, verSize{};
|
||||
int slot = 0;
|
||||
ParallelRDP parallel;
|
||||
};
|
||||
} // namespace n64
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include <capstone/capstone.h>
|
||||
#include <utils/log.hpp>
|
||||
#include <utils/MemoryHelpers.hpp>
|
||||
#include <portable_endian_bswap.h>
|
||||
#include <array>
|
||||
|
||||
struct Disassembler {
|
||||
@@ -19,7 +18,7 @@ struct Disassembler {
|
||||
return ret;
|
||||
}
|
||||
|
||||
DisassemblyResult Disassemble(u32 address, u32 instruction) {
|
||||
DisassemblyResult Disassemble(const u32 address, const u32 instruction) {
|
||||
return details ? DisassembleDetailed(address, instruction) : DisassembleSimple(address, instruction);
|
||||
}
|
||||
|
||||
@@ -29,7 +28,7 @@ private:
|
||||
DisassemblyResult DisassembleDetailed(u32 address, u32 instruction);
|
||||
DisassemblyResult DisassembleSimple(u32 address, u32 instruction);
|
||||
|
||||
Disassembler(bool rsp) : rsp(rsp) {
|
||||
explicit Disassembler(const bool rsp) : rsp(rsp) {
|
||||
if (cs_open(CS_ARCH_MIPS, static_cast<cs_mode>((rsp ? CS_MODE_32 : CS_MODE_64) | CS_MODE_BIG_ENDIAN), &handle) !=
|
||||
CS_ERR_OK) {
|
||||
Util::panic("Could not initialize {} disassembler!", rsp ? "RSP" : "CPU");
|
||||
@@ -43,5 +42,5 @@ private:
|
||||
|
||||
bool rsp = false;
|
||||
bool details = true;
|
||||
csh handle;
|
||||
csh handle{};
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <core/RSP.hpp>
|
||||
#include <log.hpp>
|
||||
#include <parallel-rdp/ParallelRDPWrapper.hpp>
|
||||
#include <core/Mem.hpp>
|
||||
|
||||
namespace n64 {
|
||||
RDP::RDP(Mem &mem, ParallelRDP ¶llel) : mem(mem), parallel(parallel) {
|
||||
|
||||
@@ -1,102 +1,53 @@
|
||||
#include <Core.hpp>
|
||||
#include <EmuThread.hpp>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
EmuThread::EmuThread(RenderWidget &renderWidget, SettingsWindow &settings) noexcept :
|
||||
renderWidget(renderWidget), core(parallel), settings(settings) {}
|
||||
EmuThread::EmuThread(const std::shared_ptr<n64::Core> &core, RenderWidget &renderWidget,
|
||||
SettingsWindow &settings) noexcept : renderWidget(renderWidget), core(core), settings(settings) {}
|
||||
|
||||
[[noreturn]] void EmuThread::run() noexcept {
|
||||
parallel.Init(renderWidget.qtVkInstanceFactory, renderWidget.wsiPlatform, renderWidget.windowInfo,
|
||||
core.cpu->GetMem().GetRDRAMPtr());
|
||||
core->parallel.Init(renderWidget.qtVkInstanceFactory, renderWidget.wsiPlatform, renderWidget.windowInfo,
|
||||
core->cpu->GetMem().GetRDRAMPtr());
|
||||
|
||||
SDL_InitSubSystem(SDL_INIT_GAMEPAD);
|
||||
bool controllerConnected = false;
|
||||
|
||||
if (SDL_AddGamepadMappingsFromFile("resources/gamecontrollerdb.txt") < 0) {
|
||||
Util::warn("[SDL] Could not load game controller DB");
|
||||
}
|
||||
|
||||
auto pollEvents = [&] {
|
||||
SDL_Event e;
|
||||
while (SDL_PollEvent(&e)) {
|
||||
switch (e.type) {
|
||||
case SDL_EVENT_GAMEPAD_ADDED:
|
||||
{
|
||||
const int index = e.gdevice.which;
|
||||
controller = SDL_OpenGamepad(index);
|
||||
Util::info("Found controller!");
|
||||
auto serial = SDL_GetGamepadSerial(controller);
|
||||
auto name = SDL_GetGamepadName(controller);
|
||||
auto path = SDL_GetGamepadPath(controller);
|
||||
Util::info("\tName: {}", name ? name : "Not available");
|
||||
Util::info("\tSerial: {}", serial ? serial : "Not available");
|
||||
Util::info("\tPath: {}", path ? path : "Not available");
|
||||
controllerConnected = true;
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_GAMEPAD_REMOVED:
|
||||
{
|
||||
controllerConnected = false;
|
||||
SDL_CloseGamepad(controller);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
while (!isInterruptionRequested()) {
|
||||
if (!core.pause) {
|
||||
core.Run(settings.getVolumeL(), settings.getVolumeR());
|
||||
if (!core->pause) {
|
||||
core->Run(settings.getVolumeL(), settings.getVolumeR());
|
||||
}
|
||||
|
||||
if (core.render) {
|
||||
parallel.UpdateScreen(core.cpu->GetMem().mmio.vi);
|
||||
}
|
||||
|
||||
pollEvents();
|
||||
|
||||
if (controllerConnected) {
|
||||
n64::PIF &pif = core.cpu->GetMem().mmio.si.pif;
|
||||
pif.UpdateButton(0, n64::Controller::Key::A, SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_SOUTH));
|
||||
pif.UpdateButton(0, n64::Controller::Key::B, SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_WEST));
|
||||
pif.UpdateButton(0, n64::Controller::Key::Z,
|
||||
SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_LEFT_TRIGGER) == SDL_JOYSTICK_AXIS_MAX);
|
||||
pif.UpdateButton(0, n64::Controller::Key::Start, SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_START));
|
||||
pif.UpdateButton(0, n64::Controller::Key::DUp, SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_DPAD_UP));
|
||||
pif.UpdateButton(0, n64::Controller::Key::DDown, SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_DPAD_DOWN));
|
||||
pif.UpdateButton(0, n64::Controller::Key::DLeft, SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_DPAD_LEFT));
|
||||
pif.UpdateButton(0, n64::Controller::Key::DRight,
|
||||
SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_DPAD_RIGHT));
|
||||
pif.UpdateButton(0, n64::Controller::Key::LT, SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER));
|
||||
pif.UpdateButton(0, n64::Controller::Key::RT,
|
||||
SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER));
|
||||
pif.UpdateButton(0, n64::Controller::Key::CUp, SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_RIGHTY) <= -127);
|
||||
pif.UpdateButton(0, n64::Controller::Key::CDown, SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_RIGHTY) >= 127);
|
||||
pif.UpdateButton(0, n64::Controller::Key::CLeft, SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_RIGHTX) <= -127);
|
||||
pif.UpdateButton(0, n64::Controller::Key::CRight, SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_RIGHTX) >= 127);
|
||||
|
||||
float xclamped = SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_LEFTX);
|
||||
if (xclamped < 0) {
|
||||
xclamped /= float(std::abs(SDL_JOYSTICK_AXIS_MAX));
|
||||
} else {
|
||||
xclamped /= SDL_JOYSTICK_AXIS_MAX;
|
||||
}
|
||||
|
||||
xclamped *= 86;
|
||||
|
||||
float yclamped = SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_LEFTY);
|
||||
if (yclamped < 0) {
|
||||
yclamped /= float(std::abs(SDL_JOYSTICK_AXIS_MIN));
|
||||
} else {
|
||||
yclamped /= SDL_JOYSTICK_AXIS_MAX;
|
||||
}
|
||||
|
||||
yclamped *= 86;
|
||||
|
||||
pif.UpdateAxis(0, n64::Controller::Axis::Y, -yclamped);
|
||||
pif.UpdateAxis(0, n64::Controller::Axis::X, xclamped);
|
||||
if (core->render) {
|
||||
core->parallel.UpdateScreen(core->cpu->GetMem().mmio.vi);
|
||||
}
|
||||
}
|
||||
|
||||
SetRender(false);
|
||||
Stop();
|
||||
}
|
||||
|
||||
void EmuThread::TogglePause() const noexcept {
|
||||
core->TogglePause();
|
||||
Util::RPC::GetInstance().Update(core->pause ? Util::RPC::Paused : Util::RPC::GetInstance().GetState(),
|
||||
core->cpu->GetMem().rom.gameNameDB,
|
||||
core->cpu->GetMem().mmio.si.pif.movie.GetFilename());
|
||||
}
|
||||
|
||||
void EmuThread::SetRender(bool v) const noexcept { core->render = v; }
|
||||
|
||||
void EmuThread::Reset() const noexcept {
|
||||
core->pause = true;
|
||||
core->Stop();
|
||||
core->LoadROM(core->rom);
|
||||
core->pause = false;
|
||||
}
|
||||
|
||||
void EmuThread::Stop() const noexcept {
|
||||
Util::RPC::GetInstance().Update(Util::RPC::Idling);
|
||||
core->rom = {};
|
||||
core->pause = true;
|
||||
core->Stop();
|
||||
}
|
||||
|
||||
@@ -1,46 +1,27 @@
|
||||
#pragma once
|
||||
#include <Core.hpp>
|
||||
#include <Discord.hpp>
|
||||
#include <QThread>
|
||||
#include <RenderWidget.hpp>
|
||||
#include <SDL3/SDL_gamepad.h>
|
||||
#include <SettingsWindow.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace n64 {
|
||||
struct Core;
|
||||
}
|
||||
|
||||
class EmuThread : public QThread {
|
||||
Q_OBJECT
|
||||
RenderWidget &renderWidget;
|
||||
|
||||
public:
|
||||
explicit EmuThread(RenderWidget &, SettingsWindow &) noexcept;
|
||||
explicit EmuThread(const std::shared_ptr<n64::Core> &, RenderWidget &, SettingsWindow &) noexcept;
|
||||
|
||||
[[noreturn]] void run() noexcept override;
|
||||
void TogglePause() const noexcept;
|
||||
void SetRender(bool v) const noexcept;
|
||||
void Reset() const noexcept;
|
||||
void Stop() const noexcept;
|
||||
|
||||
SDL_Gamepad *controller{};
|
||||
ParallelRDP parallel;
|
||||
n64::Core core;
|
||||
std::shared_ptr<n64::Core> core;
|
||||
SettingsWindow &settings;
|
||||
|
||||
void TogglePause() {
|
||||
core.TogglePause();
|
||||
Util::RPC::GetInstance().Update(core.pause ? Util::RPC::Paused : Util::RPC::GetInstance().GetState(),
|
||||
core.cpu->GetMem().rom.gameNameDB,
|
||||
core.cpu->GetMem().mmio.si.pif.movie.GetFilename());
|
||||
}
|
||||
|
||||
void SetRender(bool v) { core.render = v; }
|
||||
|
||||
void Reset() {
|
||||
core.pause = true;
|
||||
core.Stop();
|
||||
core.LoadROM(core.rom);
|
||||
core.pause = false;
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
Util::RPC::GetInstance().Update(Util::RPC::Idling);
|
||||
core.rom = {};
|
||||
core.pause = true;
|
||||
core.Stop();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
#include <Core.hpp>
|
||||
#include <KaizenQt.hpp>
|
||||
#include <QApplication>
|
||||
#include <QDropEvent>
|
||||
#include <QMessageBox>
|
||||
#include <QMimeData>
|
||||
#include <filesystem>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
KaizenQt::KaizenQt() noexcept : QWidget(nullptr) {
|
||||
mainWindow = std::make_unique<MainWindow>();
|
||||
core = std::make_shared<n64::Core>();
|
||||
mainWindow = std::make_unique<MainWindow>(core);
|
||||
settingsWindow = std::make_unique<SettingsWindow>();
|
||||
emuThread = std::make_unique<EmuThread>(*mainWindow->vulkanWidget, *settingsWindow);
|
||||
emuThread = std::make_unique<EmuThread>(core, *mainWindow->vulkanWidget, *settingsWindow);
|
||||
debugger = std::make_unique<Debugger>();
|
||||
|
||||
ConnectMainWindowSignalsToSlots();
|
||||
@@ -53,9 +54,9 @@ void KaizenQt::LoadROM(const QString &fileName) noexcept {
|
||||
mainWindow->actionReset->setEnabled(true);
|
||||
mainWindow->actionStop->setEnabled(true);
|
||||
emuThread->start();
|
||||
emuThread->core.LoadROM(fileName.toStdString());
|
||||
auto gameNameDB = emuThread->core.cpu->GetMem().rom.gameNameDB;
|
||||
mainWindow->setWindowTitle(emuThread->core.cpu->GetMem().rom.gameNameDB.c_str());
|
||||
emuThread->core->LoadROM(fileName.toStdString());
|
||||
auto gameNameDB = emuThread->core->cpu->GetMem().rom.gameNameDB;
|
||||
mainWindow->setWindowTitle(emuThread->core->cpu->GetMem().rom.gameNameDB.c_str());
|
||||
Util::RPC::GetInstance().Update(Util::RPC::Playing, gameNameDB);
|
||||
}
|
||||
|
||||
@@ -69,15 +70,19 @@ void KaizenQt::Quit() noexcept {
|
||||
}
|
||||
|
||||
void KaizenQt::LoadTAS(const QString &fileName) const noexcept {
|
||||
emuThread->core.LoadTAS(fs::path(fileName.toStdString()));
|
||||
auto gameNameDB = emuThread->core.cpu->GetMem().rom.gameNameDB;
|
||||
auto movieName = fs::path(fileName.toStdString()).stem().string();
|
||||
Util::RPC::GetInstance().Update(Util::RPC::MovieReplay, gameNameDB, movieName);
|
||||
if (emuThread->core->LoadTAS(fs::path(fileName.toStdString()))) {
|
||||
auto gameNameDB = emuThread->core->cpu->GetMem().rom.gameNameDB;
|
||||
auto movieName = fs::path(fileName.toStdString()).stem().string();
|
||||
Util::RPC::GetInstance().Update(Util::RPC::MovieReplay, gameNameDB, movieName);
|
||||
return;
|
||||
}
|
||||
|
||||
Util::panic("Could not load TAS movie {}!", fileName.toStdString());
|
||||
}
|
||||
|
||||
void KaizenQt::keyPressEvent(QKeyEvent *e) {
|
||||
emuThread->core.pause = true;
|
||||
n64::Mem &mem = emuThread->core.cpu->GetMem();
|
||||
emuThread->core->pause = true;
|
||||
n64::Mem &mem = emuThread->core->cpu->GetMem();
|
||||
n64::PIF &pif = mem.mmio.si.pif;
|
||||
|
||||
auto k = static_cast<Qt::Key>(e->key());
|
||||
@@ -95,13 +100,13 @@ void KaizenQt::keyPressEvent(QKeyEvent *e) {
|
||||
if (k == settingsWindow->keyMap[17])
|
||||
pif.UpdateAxis(0, n64::Controller::Axis::X, 86);
|
||||
|
||||
emuThread->core.pause = false;
|
||||
emuThread->core->pause = false;
|
||||
QWidget::keyPressEvent(e);
|
||||
}
|
||||
|
||||
void KaizenQt::keyReleaseEvent(QKeyEvent *e) {
|
||||
emuThread->core.pause = true;
|
||||
n64::Mem &mem = emuThread->core.cpu->GetMem();
|
||||
emuThread->core->pause = true;
|
||||
n64::Mem &mem = emuThread->core->cpu->GetMem();
|
||||
n64::PIF &pif = mem.mmio.si.pif;
|
||||
|
||||
auto k = static_cast<Qt::Key>(e->key());
|
||||
@@ -119,6 +124,6 @@ void KaizenQt::keyReleaseEvent(QKeyEvent *e) {
|
||||
if (k == settingsWindow->keyMap[17])
|
||||
pif.UpdateAxis(0, n64::Controller::Axis::X, 0);
|
||||
|
||||
emuThread->core.pause = false;
|
||||
emuThread->core->pause = false;
|
||||
QWidget::keyReleaseEvent(e);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <EmuThread.hpp>
|
||||
#include <MainWindow.hpp>
|
||||
#include <SettingsWindow.hpp>
|
||||
#include <log.hpp>
|
||||
|
||||
enum class CompositorCategory { Windows, MacOS, XCB, Wayland };
|
||||
|
||||
@@ -39,4 +40,5 @@ private:
|
||||
std::unique_ptr<SettingsWindow> settingsWindow;
|
||||
std::unique_ptr<EmuThread> emuThread;
|
||||
std::unique_ptr<Debugger> debugger;
|
||||
std::shared_ptr<n64::Core> core;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <MainWindow.hpp>
|
||||
|
||||
MainWindow::MainWindow() noexcept {
|
||||
MainWindow::MainWindow(const std::shared_ptr<n64::Core> &core) noexcept {
|
||||
if (objectName().isEmpty())
|
||||
setObjectName("MainWindow");
|
||||
resize(800, 646);
|
||||
@@ -26,7 +26,7 @@ MainWindow::MainWindow() noexcept {
|
||||
verticalLayout->setSpacing(0);
|
||||
verticalLayout->setObjectName("verticalLayout");
|
||||
verticalLayout->setContentsMargins(0, 0, 0, 0);
|
||||
vulkanWidget = std::make_unique<RenderWidget>();
|
||||
vulkanWidget = std::make_unique<RenderWidget>(core);
|
||||
vulkanWidget->setObjectName("vulkanWidget");
|
||||
|
||||
verticalLayout->addWidget(vulkanWidget.get());
|
||||
|
||||
@@ -16,7 +16,7 @@ class MainWindow : public QMainWindow {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow() noexcept;
|
||||
MainWindow(const std::shared_ptr<n64::Core> &) noexcept;
|
||||
|
||||
std::unique_ptr<QAction> actionOpenDebuggerWindow{};
|
||||
std::unique_ptr<QAction> actionAbout{};
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include <Core.hpp>
|
||||
#include <KaizenQt.hpp>
|
||||
#include <RenderWidget.hpp>
|
||||
#include <SDL3/SDL_events.h>
|
||||
|
||||
RenderWidget::RenderWidget() : QWidget(nullptr) {
|
||||
RenderWidget::RenderWidget(const std::shared_ptr<n64::Core> &core) : QWidget(nullptr) {
|
||||
setAttribute(Qt::WA_NativeWindow);
|
||||
setAttribute(Qt::WA_PaintOnScreen);
|
||||
if (GetOSCompositorCategory() == CompositorCategory::Wayland) {
|
||||
@@ -22,6 +24,76 @@ RenderWidget::RenderWidget() : QWidget(nullptr) {
|
||||
windowHandle()->setVulkanInstance(&qtVkInstanceFactory->handle);
|
||||
windowHandle()->create();
|
||||
|
||||
wsiPlatform = std::make_shared<QtWSIPlatform>(windowHandle());
|
||||
wsiPlatform = std::make_shared<QtWSIPlatform>(core, windowHandle());
|
||||
windowInfo = std::make_shared<QtParallelRdpWindowInfo>(windowHandle());
|
||||
}
|
||||
|
||||
void QtWSIPlatform::poll_input() {
|
||||
SDL_Event e;
|
||||
while (SDL_PollEvent(&e)) {
|
||||
switch (e.type) {
|
||||
case SDL_EVENT_GAMEPAD_ADDED:
|
||||
{
|
||||
const auto index = e.gdevice.which;
|
||||
gamepad = SDL_OpenGamepad(index);
|
||||
Util::info("Found controller!");
|
||||
const auto serial = SDL_GetGamepadSerial(gamepad);
|
||||
const auto name = SDL_GetGamepadName(gamepad);
|
||||
const auto path = SDL_GetGamepadPath(gamepad);
|
||||
Util::info("\tName: {}", name ? name : "Not available");
|
||||
Util::info("\tSerial: {}", serial ? serial : "Not available");
|
||||
Util::info("\tPath: {}", path ? path : "Not available");
|
||||
gamepadConnected = true;
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_GAMEPAD_REMOVED:
|
||||
{
|
||||
gamepadConnected = false;
|
||||
SDL_CloseGamepad(gamepad);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (gamepadConnected) {
|
||||
n64::PIF &pif = core->cpu->GetMem().mmio.si.pif;
|
||||
pif.UpdateButton(0, n64::Controller::Key::A, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_SOUTH));
|
||||
pif.UpdateButton(0, n64::Controller::Key::B, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_WEST));
|
||||
pif.UpdateButton(0, n64::Controller::Key::Z,
|
||||
SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFT_TRIGGER) == SDL_JOYSTICK_AXIS_MAX);
|
||||
pif.UpdateButton(0, n64::Controller::Key::Start, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_START));
|
||||
pif.UpdateButton(0, n64::Controller::Key::DUp, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_UP));
|
||||
pif.UpdateButton(0, n64::Controller::Key::DDown, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_DOWN));
|
||||
pif.UpdateButton(0, n64::Controller::Key::DLeft, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_LEFT));
|
||||
pif.UpdateButton(0, n64::Controller::Key::DRight, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_RIGHT));
|
||||
pif.UpdateButton(0, n64::Controller::Key::LT, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER));
|
||||
pif.UpdateButton(0, n64::Controller::Key::RT, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER));
|
||||
pif.UpdateButton(0, n64::Controller::Key::CUp, SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTY) <= -127);
|
||||
pif.UpdateButton(0, n64::Controller::Key::CDown, SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTY) >= 127);
|
||||
pif.UpdateButton(0, n64::Controller::Key::CLeft, SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTX) <= -127);
|
||||
pif.UpdateButton(0, n64::Controller::Key::CRight, SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTX) >= 127);
|
||||
|
||||
float xclamped = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTX);
|
||||
if (xclamped < 0) {
|
||||
xclamped /= float(std::abs(SDL_JOYSTICK_AXIS_MAX));
|
||||
} else {
|
||||
xclamped /= SDL_JOYSTICK_AXIS_MAX;
|
||||
}
|
||||
|
||||
xclamped *= 86;
|
||||
|
||||
float yclamped = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTY);
|
||||
if (yclamped < 0) {
|
||||
yclamped /= float(std::abs(SDL_JOYSTICK_AXIS_MIN));
|
||||
} else {
|
||||
yclamped /= SDL_JOYSTICK_AXIS_MAX;
|
||||
}
|
||||
|
||||
yclamped *= 86;
|
||||
|
||||
pif.UpdateAxis(0, n64::Controller::Axis::Y, -yclamped);
|
||||
pif.UpdateAxis(0, n64::Controller::Axis::X, xclamped);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
#include <QVulkanWindow>
|
||||
#include <QWidget>
|
||||
#include <QWindow>
|
||||
#include <SDL3/SDL_gamepad.h>
|
||||
|
||||
namespace n64 {
|
||||
struct Core;
|
||||
}
|
||||
|
||||
struct QtInstanceFactory : Vulkan::InstanceFactory {
|
||||
VkInstance create_instance(const VkInstanceCreateInfo *info) override {
|
||||
@@ -29,7 +34,7 @@ struct QtInstanceFactory : Vulkan::InstanceFactory {
|
||||
|
||||
class QtParallelRdpWindowInfo : public ParallelRDP::WindowInfo {
|
||||
public:
|
||||
explicit QtParallelRdpWindowInfo(QWindow* window) : window(window) {}
|
||||
explicit QtParallelRdpWindowInfo(QWindow *window) : window(window) {}
|
||||
CoordinatePair get_window_size() override {
|
||||
return CoordinatePair{static_cast<float>(window->width()), static_cast<float>(window->height())};
|
||||
}
|
||||
@@ -40,7 +45,7 @@ private:
|
||||
|
||||
class QtWSIPlatform final : public Vulkan::WSIPlatform {
|
||||
public:
|
||||
explicit QtWSIPlatform(QWindow* window) : window(window) {}
|
||||
explicit QtWSIPlatform(const std::shared_ptr<n64::Core> &core, QWindow *window) : window(window), core(core) {}
|
||||
|
||||
std::vector<const char *> get_instance_extensions() override {
|
||||
auto vec = std::vector<const char *>();
|
||||
@@ -64,7 +69,7 @@ public:
|
||||
|
||||
bool alive(Vulkan::WSI &) override { return true; }
|
||||
|
||||
void poll_input() override {}
|
||||
void poll_input() override;
|
||||
void poll_input_async(Granite::InputTrackerHandler *handler) override {}
|
||||
|
||||
void event_frame_tick(double frame, double elapsed) override {}
|
||||
@@ -74,15 +79,19 @@ public:
|
||||
VkApplicationInfo appInfo{.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .apiVersion = VK_API_VERSION_1_3};
|
||||
|
||||
std::shared_ptr<QWindow> window{};
|
||||
|
||||
private:
|
||||
std::shared_ptr<n64::Core> core;
|
||||
SDL_Gamepad *gamepad{};
|
||||
bool gamepadConnected = false;
|
||||
};
|
||||
|
||||
class RenderWidget : public QWidget {
|
||||
public:
|
||||
[[nodiscard]] VkInstance instance() const { return qtVkInstanceFactory->handle.vkInstance(); }
|
||||
explicit RenderWidget();
|
||||
explicit RenderWidget(const std::shared_ptr<n64::Core> &);
|
||||
|
||||
[[nodiscard]] QPaintEngine *paintEngine() const override { return nullptr; }
|
||||
|
||||
std::shared_ptr<ParallelRDP::WindowInfo> windowInfo;
|
||||
std::shared_ptr<Vulkan::WSIPlatform> wsiPlatform;
|
||||
std::shared_ptr<QtInstanceFactory> qtVkInstanceFactory;
|
||||
|
||||
Reference in New Issue
Block a user