Compiles!

This commit is contained in:
SimoZ64
2025-05-05 22:15:45 +02:00
parent 20e8e720a6
commit b4c5c7a3e4
25 changed files with 598 additions and 422 deletions

View File

@@ -4,4 +4,4 @@ file(GLOB HEADERS *.hpp)
add_subdirectory(core)
add_library(backend ${SOURCES} ${HEADERS})
target_link_libraries(backend PRIVATE core)
target_link_libraries(backend PRIVATE core)

View File

@@ -2,12 +2,13 @@
#include <File.hpp>
#include <GameDB.hpp>
#include <Registers.hpp>
#include <algorithm>
#include <backend/MemoryRegions.hpp>
#include <backend/core/MMIO.hpp>
#include <common.hpp>
#include <log.hpp>
#include <vector>
#include <algorithm>
#include <ranges>
namespace n64 {
struct ROMHeader {

View File

@@ -3,6 +3,7 @@ project(kaizen)
if (WIN32)
add_compile_definitions(NOMINMAX)
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
endif ()
if(APPLE)
@@ -10,9 +11,13 @@ if(APPLE)
enable_language(OBJC)
endif()
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include_directories(
.
../
../../
../utils
../backend
../backend/core
@@ -40,6 +45,7 @@ include_directories(
../../external/capstone/include
../../external/imgui
../../external/imgui/backends
../../external/nfd/src/include
../../external/cflags/include
ImGuiImpl/
)
@@ -65,22 +71,27 @@ else()
set(ARM64 FALSE)
endif()
set(SIMD_FLAG NULL)
if(ARM64 AND APPLE)
message("Defining USE_NEON...")
add_compile_definitions(USE_NEON)
set(HAS_SIMD TRUE)
add_compile_definitions(SIMD_SUPPORT)
elseif(NOT ARM64)
if(MSVC)
set(SIMD_FLAG /arch:AVX)
else()
set(SIMD_FLAG -msse4.1)
endif()
check_c_compiler_flag(${SIMD_FLAG} HAS_SIMD)
else()
message("Compiling on an unsupported Arm device! Good Luck!")
endif()
if(NOT ARM64)
check_c_compiler_flag(-msse4.1 HAS_SIMD)
endif ()
if (HAS_SIMD)
message("Defining SIMD_SUPPORT...")
add_compile_definitions(SIMD_SUPPORT)
if(NOT ARM64)
add_compile_options(-msse3 -msse4.1)
endif()
add_compile_options(${SIMD_FLAG})
endif ()
if (${CMAKE_BUILD_TYPE} MATCHES Debug)
@@ -97,6 +108,7 @@ add_subdirectory(../../external/unarr unarr)
add_subdirectory(../../external/SDL SDL)
add_subdirectory(../../external/cflags cflags)
add_subdirectory(../../external/imgui imgui)
add_subdirectory(../../external/nfd nfd)
set(CAPSTONE_ARCHITECTURE_DEFAULT OFF)
set(CAPSTONE_MIPS_SUPPORT ON)
set(CAPSTONE_X86_SUPPORT ON)
@@ -110,8 +122,6 @@ add_executable(kaizen
RenderWidget.hpp
EmuThread.hpp
EmuThread.cpp
MainWindow.hpp
MainWindow.cpp
SettingsWindow.hpp
SettingsWindow.cpp
CPUSettings.hpp
@@ -124,9 +134,8 @@ add_executable(kaizen
Debugger.hpp
Debugger.cpp)
target_link_libraries(kaizen PUBLIC imgui SDL3::SDL3 SDL3::SDL3-static cflags::cflags discord-rpc fmt mio nlohmann_json parallel-rdp capstone backend)
target_link_libraries(kaizen PUBLIC imgui nfd SDL3::SDL3 SDL3::SDL3-static cflags::cflags discord-rpc fmt mio nlohmann_json parallel-rdp capstone backend)
target_compile_definitions(kaizen PUBLIC SDL_MAIN_HANDLED)
set_target_properties(kaizen PROPERTIES CXX_STANDARD 20 CXX_STANDARD_REQUIRED ON)
file(COPY ../../resources/ DESTINATION ${PROJECT_BINARY_DIR}/resources/)
file(REMOVE

View File

@@ -1,7 +1,7 @@
#include <Core.hpp>
#include <EmuThread.hpp>
EmuThread::EmuThread(const std::shared_ptr<n64::Core> &core, std::string &fps, RenderWidget &renderWidget,
EmuThread::EmuThread(const std::shared_ptr<n64::Core> &core, double &fps, RenderWidget &renderWidget,
SettingsWindow &settings) noexcept :
renderWidget(renderWidget), core(core), settings(settings), fps(fps) {}
@@ -16,7 +16,7 @@ void EmuThread::start() noexcept {
auto sampledFps = 0;
static bool oneSecondPassed = false;
fps = fmt::format("{:.2f} FPS", 1000.0 / avgFps);
fps = 1000.0 / avgFps;
while (!interruptionRequested) {
const auto startFrameTime = std::chrono::high_resolution_clock::now();
@@ -44,7 +44,7 @@ void EmuThread::start() noexcept {
lastSample = endFrameTime;
avgFps /= sampledFps;
sampledFps = 0;
fps = fmt::format("{:.2f} FPS", 1000.0 / avgFps);
fps = 1000.0 / avgFps;
}
}
SetRender(false);

View File

@@ -12,7 +12,7 @@ class EmuThread final {
RenderWidget &renderWidget;
public:
explicit EmuThread(const std::shared_ptr<n64::Core> &, std::string &, RenderWidget &, SettingsWindow &) noexcept;
explicit EmuThread(const std::shared_ptr<n64::Core> &, double &, RenderWidget &, SettingsWindow &) noexcept;
void start() noexcept;
void TogglePause() const noexcept;
@@ -24,6 +24,6 @@ public:
bool interruptionRequested = false, isRunning = false;
std::shared_ptr<n64::Core> core;
SettingsWindow &settings;
std::string& fps;
double& fps;
std::thread thread;
};

View File

@@ -14,7 +14,7 @@ struct ComboItem {
return ret;
}
const std::string& getLabel() { return label; }
const std::string& getLabel() const { return label; }
void setLabel(const std::string& text) { label = text; }
private:
bool enabled = true;
@@ -24,9 +24,9 @@ private:
struct Combobox {
Combobox(std::string label, std::vector<ComboItem> items, std::string preview = "", bool enabled = true) : label(label), items(items), preview(preview), enabled(enabled) {}
void addItem(ComboItem& item) {
if(std::find(items.begin(), items.end(),
[&item](ComboItem& a) { return a.getLabel() == item.getLabel(); }) != items.end())
void addItem(const ComboItem& item) {
if(std::find_if(items.begin(), items.end(),
[&item](const ComboItem& a) { return a.getLabel() == item.getLabel(); }) != items.end())
return;
items.push_back(item);

View File

@@ -0,0 +1,74 @@
#pragma once
#include <imgui.h>
#include <string>
#include <ranges>
#include <functional>
namespace gui {
struct MenuItem {
MenuItem(const std::string& label, std::function<void()>&& func = nullptr, bool enabled = true) : label(label), exec(std::move(func)), enabled(enabled) {}
bool render() {
bool ret = false;
ImGui::BeginDisabled(!enabled);
if(ImGui::MenuItem(label.c_str())) {
if(exec)
exec();
ret = true;
}
ImGui::EndDisabled();
return ret;
}
void setEnabled(bool v) { enabled = v; }
private:
bool enabled = true;
std::string label;
std::function<void()> exec;
};
struct Menu {
Menu(const std::string& label, const std::vector<MenuItem>& items = {}, bool enabled = true) : label(label), items(items), enabled(enabled) {}
void addMenuItem(const MenuItem& item) { items.push_back(item); }
bool render() {
bool ret = false;
ImGui::BeginDisabled(!enabled);
if(ImGui::BeginMenu(label.c_str())) {
for(auto& item : items) {
ret |= item.render();
}
ImGui::EndMenu();
}
ImGui::EndDisabled();
return ret;
}
void setEnabled(bool v) { enabled = v; }
private:
std::vector<MenuItem> items{};
std::string label{};
bool enabled = true;
};
template <bool main = false>
struct MenuBar {
MenuBar(bool enabled = true) : enabled(enabled) {}
void addMenu(const Menu& menu) { menus.push_back(menu); }
bool render() {
bool ret = false;
ImGui::BeginDisabled(!enabled);
auto beginMenuBar = main ? &ImGui::BeginMainMenuBar : &ImGui::BeginMenuBar;
auto endMenuBar = main ? &ImGui::EndMainMenuBar : &ImGui::EndMenuBar;
if(beginMenuBar()) {
for(auto& menu : menus) {
ret |= menu.render();
}
endMenuBar();
}
ImGui::EndDisabled();
return ret;
}
void setEnabled(bool v) { enabled = v; }
private:
bool enabled = true;
std::vector<Menu> menus{};
};
}

View File

@@ -0,0 +1,33 @@
#include <imgui.h>
#include <string>
#include <functional>
namespace gui {
struct PopupWindow {
PopupWindow(const std::string& title, std::function<void()>&& func = nullptr, bool opened = true) : title(title), exec(func), opened(opened) {}
void setFunc(std::function<void()>&& func) {
exec = func;
}
bool render() {
ImGui::OpenPopup(title.c_str());
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
if (ImGui::BeginPopupModal(title.c_str(), &opened, ImGuiWindowFlags_AlwaysAutoResize))
{
if(exec)
exec();
ImGui::EndPopup();
return true;
}
return false;
}
private:
std::function<void()> exec;
std::string title;
bool opened = true;
};
}

View File

@@ -5,8 +5,8 @@
namespace gui {
template <typename T>
struct Slider {
Slider(const std::string& label, T min = 0, T max = 0, T default = 0)
: val(default), label(label), min(min), max(max) { }
Slider(const std::string& label, T min = 0, T max = 0, T initial_value = 0)
: val(initial_value), label(label), min(min), max(max) { }
void setValue(T v) { val = v; }
bool render() {

View File

@@ -0,0 +1,28 @@
#include <imgui.h>
#include <functional>
namespace gui {
struct StatusBar {
StatusBar(std::function<void()>&& func = nullptr, bool enabled = true) : exec(func), enabled(enabled) {}
bool render() {
float statusWindowHeight = ImGui::GetFrameHeight() * 1.4f;
ImGuiViewport* viewport = ImGui::GetMainViewport();
ImVec2 statusBarSize, statusBarPos;
ImGui::SetNextWindowPos(statusBarPos);
ImGui::SetNextWindowSize(statusBarSize);
ImGui::SetNextWindowViewport(viewport->ID);
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking;
ImGui::Begin("StatusBar", nullptr, windowFlags);
if(exec)
exec();
ImGui::End();
}
private:
std::function<void()> exec = nullptr;
bool enabled = true;
};
}

View File

@@ -2,18 +2,19 @@
#include <imgui.h>
#include <string>
#include <vector>
#include <functional>
namespace gui {
struct TabItem {
TabItem(std::string label, void(*func)(TabItem*, void* userData) = nullptr, void* userData = nullptr, bool enabled = true) : exec(func), enabled(enabled), userData(userData) {}
TabItem(std::string label, std::function<void()>&& func, bool enabled = true) : exec(std::move(func)), enabled(enabled) {}
bool render() {
bool ret = false;
ImGui::BeginDisabled(!enabled);
if(ImGui::BeginTabItem(label.c_str())) {
if(exec)
exec(this, userData);
exec();
ImGui::EndTabItem();
ret = true;
}
@@ -23,15 +24,12 @@ struct TabItem {
private:
bool enabled = true;
std::string label;
void(*exec)(TabItem*, void* userData);
void* userData;
std::function<void()> exec;
};
struct TabBar {
TabBar(std::string label) : label(label) {}
void addTab(TabItem tabItem) {
tabs.push_back(tabItem);
}
TabBar(std::string label, const std::vector<TabItem>& items = {}) : label(label), tabs(items) {}
void addTab(TabItem tabItem) { tabs.push_back(tabItem); }
bool render() {
bool ret = false;

View File

@@ -1,125 +1,105 @@
#include <Core.hpp>
#include <KaizenGui.hpp>
#include <nfd.hpp>
#include <backend/Core.hpp>
#include <ImGuiImpl/StatusBar.hpp>
namespace fs = std::filesystem;
KaizenGui::KaizenGui() noexcept : core(std::make_shared<n64::Core>()), vulkanWidget(core), emuThread(core, fpsCounter, vulkanWidget, settingsWindow) {
emuExitFunc = [&]() {
quit = true;
if (emuThread.isRunning) {
emuThread.requestInterruption();
while (emuThread.isRunning) {}
}
};
menuBar.addMenu({"File",
{
{"Open", [&]() {
NFD::Guard guard;
NFD::UniquePath path;
nfdfilteritem_t filterItem = {"Nintendo 64 roms", "n64,z64,v64,N64,Z64,V64"};
KaizenGui::KaizenGui() noexcept : mainWindow(core), emuThread(core, mainWindow.fpsCounter, mainWindow.vulkanWidget, settingsWindow) {
// debugger = std::make_unique<Debugger>();
auto result = NFD::OpenDialog(path, &filterItem, 1);
if(result == NFD_CANCEL) return;
if(result == NFD_ERROR)
Util::panic("Error: {}", NFD::GetError());
LoadROM(path.get());
}},
{"Exit", std::move(emuExitFunc)}
}
});
ConnectMainWindowSignalsToSlots();
Util::RPC::GetInstance().Update(Util::RPC::Idling);
menuBar.addMenu({"Emulation",
{
actionPause,
actionStop,
actionReset,
{"Settings", [&]() {
settingsWindow.render();
}},
}
});
menuBar.addMenu({"Help",
{
{"About", [&]() {
gui::PopupWindow about{"About Kaizen", [&]() {
ImGui::Text("Kaizen is a Nintendo 64 emulator that strives");
ImGui::Text("to offer a friendly user experience and compatibility.");
ImGui::Text("Kaizen is licensed under the BSD 3-clause license.");
ImGui::Text("Nintendo 64 is a registered trademarks of Nintendo Co., Ltd.");
}};
}},
}
});
}
void KaizenGui::ConnectMainWindowSignalsToSlots() noexcept {
connect(settingsWindow.get(), &SettingsWindow::regrabKeyboard, this, [&] { grabKeyboard(); });
void KaizenGui::LoadROM(const std::string &path) noexcept {
actionPause.setEnabled(true);
actionReset.setEnabled(true);
actionStop.setEnabled(true);
emuThread.start();
emuThread.core->LoadROM(path);
const auto gameNameDB = emuThread.core->cpu->GetMem().rom.gameNameDB;
Util::RPC::GetInstance().Update(Util::RPC::Playing, gameNameDB);
}
connect(settingsWindow.get(), &SettingsWindow::gotClosed, this,
[&] { mainWindow->vulkanWidget->wsiPlatform->EnableEventPolling(); });
connect(settingsWindow.get(), &SettingsWindow::gotOpened, this,
[&] { mainWindow->vulkanWidget->wsiPlatform->DisableEventPolling(); });
connect(mainWindow.get(), &MainWindow::OpenSettings, this, [this] { settingsWindow->show(); });
// connect(mainWindow.get(), &MainWindow::OpenDebugger, this, [this] { debugger->show(); });
connect(mainWindow.get(), &MainWindow::OpenROM, this, &KaizenGui::LoadROM);
connect(mainWindow.get(), &MainWindow::Exit, this, &KaizenGui::Quit);
connect(mainWindow.get(), &MainWindow::Reset, emuThread.get(), &EmuThread::Reset);
connect(mainWindow.get(), &MainWindow::Stop, this, [this] { emuThread->requestInterruption(); });
connect(mainWindow.get(), &MainWindow::Pause, emuThread.get(), &EmuThread::TogglePause);
void KaizenGui::handleEvents() {
SDL_Event e;
while(SDL_PollEvent(&e)) {
switch(e.type) {
case SDL_EVENT_QUIT:
emuExitFunc();
break;
}
}
}
int KaizenGui::run() {
bool inputForEmu = true;
while(!quit) {
handleEvents();
if(settingsWindow.render()) {
inputForEmu = false;
menuBar.render();
// TODO VULKAN CANVAS
gui::StatusBar statusBar{[&]() {
ImGui::Text("GUI FPS: %.2f, Emulation FPS: %.2f", ImGui::GetIO().Framerate, fpsCounter);
}};
statusBar.render();
}
mainWindow.render();
return 0;
}
void KaizenGui::LoadROM(const QString &path) const noexcept {
mainWindow->actionPause->setEnabled(true);
mainWindow->actionReset->setEnabled(true);
mainWindow->actionStop->setEnabled(true);
emuThread->start();
emuThread->core->LoadROM(path.toStdString());
const 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);
}
void KaizenGui::Quit() const noexcept {
if (emuThread) {
emuThread->requestInterruption();
while (emuThread->isRunning) {}
}
QApplication::quit();
}
void KaizenGui::LoadTAS(const QString &path) const noexcept {
if (emuThread->core->LoadTAS(fs::path(path.toStdString()))) {
const auto gameNameDB = emuThread->core->cpu->GetMem().rom.gameNameDB;
const auto movieName = fs::path(path.toStdString()).stem().string();
void KaizenGui::LoadTAS(const std::string &path) const noexcept {
if (emuThread.core->LoadTAS(fs::path(path))) {
const auto gameNameDB = emuThread.core->cpu->GetMem().rom.gameNameDB;
const auto movieName = fs::path(path).stem().string();
Util::RPC::GetInstance().Update(Util::RPC::MovieReplay, gameNameDB, movieName);
return;
}
Util::panic("Could not load TAS movie {}!", path.toStdString());
}
void KaizenGui::keyPressEvent(QKeyEvent *e) {
if (settingsWindow->inputSettings->selectedDeviceIsNotKeyboard)
return;
emuThread->core->pause = true;
n64::Mem &mem = emuThread->core->cpu->GetMem();
n64::PIF &pif = mem.mmio.si.pif;
const auto k = static_cast<Qt::Key>(e->key());
for (int i = 0; i < 14; i++) {
if (k == settingsWindow->keyMap[i])
pif.UpdateButton(0, static_cast<n64::Controller::Key>(i), true);
}
if (k == settingsWindow->keyMap[14])
pif.UpdateAxis(0, n64::Controller::Axis::Y, 86);
if (k == settingsWindow->keyMap[15])
pif.UpdateAxis(0, n64::Controller::Axis::Y, -86);
if (k == settingsWindow->keyMap[16])
pif.UpdateAxis(0, n64::Controller::Axis::X, -86);
if (k == settingsWindow->keyMap[17])
pif.UpdateAxis(0, n64::Controller::Axis::X, 86);
emuThread->core->pause = false;
QWidget::keyPressEvent(e);
}
void KaizenGui::keyReleaseEvent(QKeyEvent *e) {
if (settingsWindow->inputSettings->selectedDeviceIsNotKeyboard)
return;
emuThread->core->pause = true;
n64::Mem &mem = emuThread->core->cpu->GetMem();
n64::PIF &pif = mem.mmio.si.pif;
const auto k = static_cast<Qt::Key>(e->key());
for (int i = 0; i < 14; i++) {
if (k == settingsWindow->keyMap[i])
pif.UpdateButton(0, static_cast<n64::Controller::Key>(i), false);
}
if (k == settingsWindow->keyMap[14])
pif.UpdateAxis(0, n64::Controller::Axis::Y, 0);
if (k == settingsWindow->keyMap[15])
pif.UpdateAxis(0, n64::Controller::Axis::Y, 0);
if (k == settingsWindow->keyMap[16])
pif.UpdateAxis(0, n64::Controller::Axis::X, 0);
if (k == settingsWindow->keyMap[17])
pif.UpdateAxis(0, n64::Controller::Axis::X, 0);
emuThread->core->pause = false;
QWidget::keyReleaseEvent(e);
}
Util::panic("Could not load TAS movie {}!", path);
}

View File

@@ -1,24 +1,28 @@
#pragma once
#include <Discord.hpp>
#include <RenderWidget.hpp>
#include <Debugger.hpp>
#include <ImGuiImpl/Menu.hpp>
#include <EmuThread.hpp>
#include <MainWindow.hpp>
#include <SettingsWindow.hpp>
#include <log.hpp>
#include <memory>
#include <Discord.hpp>
class KaizenGui {
class KaizenGui final {
public:
KaizenGui() noexcept;
void LoadTAS(const std::string &path) const noexcept;
void LoadROM(const std::string &path) const noexcept;
int run();
private:
void Quit() const noexcept;
void ConnectMainWindowSignalsToSlots() noexcept;
MainWindow mainWindow;
SettingsWindow settingsWindow;
EmuThread emuThread;
// std::unique_ptr<Debugger> debugger;
explicit KaizenGui() noexcept;
double fpsCounter;
gui::MenuBar<true> menuBar;
gui::MenuItem actionPause{"Pause"}, actionStop{"Stop"}, actionReset{"Reset"};
std::shared_ptr<n64::Core> core;
EmuThread emuThread;
SettingsWindow settingsWindow;
RenderWidget vulkanWidget;
int run();
void LoadTAS(const std::string &path) const noexcept;
void LoadROM(const std::string &path) noexcept;
private:
bool quit = false;
void handleEvents();
std::function<void()> emuExitFunc;
bool textPauseToggle = false;
};

View File

@@ -1,153 +0,0 @@
#include <MainWindow.hpp>
MainWindow::MainWindow(const std::shared_ptr<n64::Core> &core) noexcept : vulkanWidget(core) {
/* if (objectName().isEmpty())
setObjectName("MainWindow");
resize(800, 646);
actionOpenDebuggerWindow = std::make_unique<QAction>(this);
actionOpenDebuggerWindow->setObjectName("actionOpenDebuggerWindow");
actionAbout = std::make_unique<QAction>(this);
actionAbout->setObjectName("actionAbout");
actionOpen = std::make_unique<QAction>(this);
actionOpen->setObjectName("actionOpen");
actionExit = std::make_unique<QAction>(this);
actionExit->setObjectName("actionExit");
actionPause = std::make_unique<QAction>(this);
actionPause->setObjectName("actionPause");
actionReset = std::make_unique<QAction>(this);
actionReset->setObjectName("actionReset");
actionStop = std::make_unique<QAction>(this);
actionStop->setObjectName("actionStop");
actionSettings = std::make_unique<QAction>(this);
actionSettings->setObjectName("actionSettings");
centralwidget = std::make_unique<QWidget>(this);
centralwidget->setObjectName("centralwidget");
verticalLayout = std::make_unique<QVBoxLayout>();
verticalLayout->setSpacing(0);
verticalLayout->setObjectName("verticalLayout");
verticalLayout->setContentsMargins(0, 0, 0, 0);
verticalLayout->addWidget(vulkanWidget.get());
centralwidget->setLayout(verticalLayout.get());
setCentralWidget(centralwidget.get());
menubar = std::make_unique<QMenuBar>(this);
menubar->setObjectName("menubar");
menubar->setGeometry(QRect(0, 0, 800, 22));
menuFile = std::make_unique<QMenu>(menubar.get());
menuFile->setObjectName("menuFile");
menuEmulation = std::make_unique<QMenu>(menubar.get());
menuEmulation->setObjectName("menuEmulation");
menuTools = std::make_unique<QMenu>(menubar.get());
menuTools->setObjectName("menuTools");
menuAbout = std::make_unique<QMenu>(menubar.get());
menuAbout->setObjectName("menuAbout");
setMenuBar(menubar.get());
statusbar = std::make_unique<QStatusBar>(this);
statusbar->setObjectName("statusbar");
fpsCounter = std::make_unique<QLabel>("Not playing");
statusbar->addPermanentWidget(fpsCounter.get());
setStatusBar(statusbar.get());
menubar->addAction(menuFile->menuAction());
menubar->addAction(menuEmulation->menuAction());
menubar->addAction(menuTools->menuAction());
menubar->addAction(menuAbout->menuAction());
menuFile->addAction(actionOpen.get());
menuFile->addAction(actionExit.get());
menuEmulation->addAction(actionSettings.get());
menuEmulation->addAction(actionPause.get());
menuEmulation->addAction(actionReset.get());
menuEmulation->addAction(actionStop.get());
menuTools->addAction(actionOpenDebuggerWindow.get());
menuAbout->addAction(actionAbout.get());
Retranslate();
QMetaObject::connectSlotsByName(this);
actionPause->setDisabled(true);
actionReset->setDisabled(true);
actionStop->setDisabled(true);
vulkanWidget->hide();
ConnectSignalsToSlots();*/
}
void MainWindow::Retranslate() {
/*setWindowTitle(QCoreApplication::translate("MainWindow", "Kaizen", nullptr));
actionOpenDebuggerWindow->setText(QCoreApplication::translate("MainWindow", "CPU Debugger", nullptr));
actionOpenDebuggerWindow->setStatusTip(QCoreApplication::translate(
"MainWindow", "Open the CPU debugger window which allows you see registers, memory and disassembled code",
nullptr));
actionAbout->setText(QCoreApplication::translate("MainWindow", "About Kaizen", nullptr));
actionAbout->setStatusTip(QCoreApplication::translate("MainWindow", "About this emulator", nullptr));
actionOpen->setText(QCoreApplication::translate("MainWindow", "Open...", nullptr));
actionOpen->setStatusTip(QCoreApplication::translate("MainWindow", "Open a ROM", nullptr));
actionOpen->setShortcut(QCoreApplication::translate("MainWindow", "Ctrl+O", nullptr));
actionExit->setText(QCoreApplication::translate("MainWindow", "Exit", nullptr));
actionExit->setStatusTip(QCoreApplication::translate("MainWindow", "Quit the emulator", nullptr));
actionPause->setText(QCoreApplication::translate("MainWindow", "Pause", nullptr));
actionPause->setStatusTip(QCoreApplication::translate("MainWindow", "Pause the emulation", nullptr));
actionReset->setText(QCoreApplication::translate("MainWindow", "Reset", nullptr));
actionReset->setStatusTip(QCoreApplication::translate("MainWindow", "Reset the emulation", nullptr));
actionStop->setText(QCoreApplication::translate("MainWindow", "Stop", nullptr));
actionStop->setStatusTip(QCoreApplication::translate("MainWindow", "Stop the emulation", nullptr));
actionSettings->setText(QCoreApplication::translate("MainWindow", "Settings", nullptr));
actionSettings->setToolTip(QCoreApplication::translate("MainWindow", "Settings", nullptr));
actionSettings->setStatusTip(QCoreApplication::translate("MainWindow", "Open the settings window", nullptr));
menuFile->setTitle(QCoreApplication::translate("MainWindow", "File", nullptr));
menuEmulation->setTitle(QCoreApplication::translate("MainWindow", "Emulation", nullptr));
menuTools->setTitle(QCoreApplication::translate("MainWindow", "Tools", nullptr));
menuAbout->setTitle(QCoreApplication::translate("MainWindow", "Help", nullptr));
*/
} // retranslateUi
void MainWindow::ConnectSignalsToSlots() noexcept {
/* connect(actionOpen.get(), &QAction::triggered, this, [this]() {
const QString file_name = QFileDialog::getOpenFileName(
this, "Nintendo 64 executable", QString(),
"All supported types (*.zip *.ZIP *.7z *.7Z *.rar *.RAR *.tar *.TAR *.n64 *.N64 *.v64 *.V64 *.z64 *.Z64)");
if (!file_name.isEmpty()) {
emit OpenROM(file_name);
vulkanWidget->show();
}
});
connect(actionExit.get(), &QAction::triggered, this, [this]() { emit Exit(); });
connect(this, &MainWindow::destroyed, this, [this]() { emit Exit(); });
connect(actionReset.get(), &QAction::triggered, this, [this]() { emit Reset(); });
connect(actionStop.get(), &QAction::triggered, this, [this]() {
setWindowTitle("Kaizen");
vulkanWidget->hide();
actionPause->setDisabled(true);
actionReset->setDisabled(true);
actionStop->setDisabled(true);
emit Stop();
});
connect(actionPause.get(), &QAction::triggered, this, [this]() {
textPauseToggle = !textPauseToggle;
actionPause->setText(textPauseToggle ? "Resume" : "Pause");
emit Pause();
});
connect(actionAbout.get(), &QAction::triggered, this, [this]() {
QMessageBox::about(this, tr("About Kaizen"),
tr("Kaizen is a Nintendo 64 emulator that strives to offer a friendly user "
"experience and great compatibility.\n"
"Kaizen is licensed under the BSD 3-clause license.\n"
"Nintendo 64 is a registered trademarks of Nintendo Co., Ltd."));
});
connect(actionSettings.get(), &QAction::triggered, this, [this]() { emit OpenSettings(); });
connect(actionOpenDebuggerWindow.get(), &QAction::triggered, this, [this]() { emit OpenDebugger(); });
*/
}
bool MainWindow::render() {
}

View File

@@ -1,37 +0,0 @@
#pragma once
#include <RenderWidget.hpp>
#include <Debugger.hpp>
class MainWindow final {
public:
explicit MainWindow(const std::shared_ptr<n64::Core> &) noexcept;
std::string fpsCounter;
RenderWidget vulkanWidget;
bool render();
//std::unique_ptr<QAction> actionOpenDebuggerWindow{};
//std::unique_ptr<QAction> actionAbout{};
//std::unique_ptr<QAction> actionOpen{};
//std::unique_ptr<QAction> actionExit{};
//std::unique_ptr<QAction> actionPause{};
//std::unique_ptr<QAction> actionReset{};
//std::unique_ptr<QAction> actionStop{};
//std::unique_ptr<QAction> actionSettings{};
//std::unique_ptr<QWidget> centralwidget{};
//std::unique_ptr<QVBoxLayout> verticalLayout{};
//std::unique_ptr<RenderWidget> vulkanWidget{};
//std::unique_ptr<QMenuBar> menubar{};
//std::unique_ptr<QMenu> menuFile{};
//std::unique_ptr<QMenu> menuEmulation{};
//std::unique_ptr<QMenu> menuTools{};
//std::unique_ptr<QMenu> menuAbout{};
//std::unique_ptr<QStatusBar> statusbar{};
//std::unique_ptr<QLabel> fpsCounter{};
private:
void Retranslate();
void ConnectSignalsToSlots() noexcept;
bool textPauseToggle = false;
};

View File

@@ -9,11 +9,11 @@ RenderWidget::RenderWidget(const std::shared_ptr<n64::Core> &core) {
}
imGuiVkInstanceFactory = std::make_shared<ImGuiInstanceFactory>();
windowHandle()->setVulkanInstance(&imGuiVkInstanceFactory->handle);
windowHandle()->create();
//windowHandle()->setVulkanInstance(&imGuiVkInstanceFactory->create_instance());
//windowHandle()->create();
wsiPlatform = std::make_shared<ImGuiWSIPlatform>(core, windowHandle());
windowInfo = std::make_shared<ImGuiParallelRdpWindowInfo>(windowHandle());
//wsiPlatform = std::make_shared<ImGuiWSIPlatform>(core, windowHandle());
// windowInfo = std::make_shared<ImGuiParallelRdpWindowInfo>(windowHandle());
}
void ImGuiWSIPlatform::poll_input() {

View File

@@ -1,76 +1,76 @@
#include <SettingsWindow.hpp>
#include <fmt/core.h>
#include <nfd.hpp>
#include <log.hpp>
#include <JSONUtils.hpp>
std::string savePath;
SettingsWindow::SettingsWindow() {
settings = JSONOpenOrCreate("resources/settings.json");
savePath = JSONGetField<std::string>(settings, "general", "savePath");
SettingsWindow::SettingsWindow() : settings{JSONOpenOrCreate("resources/settings.json")} {
keyMap = inputSettings.GetMappedKeys();
savesFolder.setName(fmt::format(savesFolder.getName(), savePath));
savesFolder.setName(fmt::format("Save path: {}",
JSONGetField<std::string>(settings, "general", "savePath")));
tabs.addTab({"General", [](gui::TabItem* tab, void* userData) {
SettingsWindow* sW = (SettingsWindow*)userData;
if(sW->savesFolder.render()) {
// TODO: HANDLE FILE DIALOG savePath = QFileDialog::getExistingDirectory(this, tr("Select directory")).toStdString();
sW->savesFolder.setName(fmt::format(sW->savesFolder.getName(), savePath));
JSONSetField(sW->settings, "general", "savePath", savePath);
sW->apply.setEnabled(true);
tabs.addTab({"General", [&]() {
if(savesFolder.render()) {
NFD::Guard guard;
NFD::UniquePath outPath;
auto result = NFD::PickFolder(outPath);
if(result == NFD_CANCEL)
return;
if(result == NFD_ERROR)
Util::panic("Error: {}", NFD::GetError());
savesFolder.setName(fmt::format("Save path: {}", outPath.get()));
JSONSetField(settings, "general", "savePath", outPath.get());
apply.setEnabled(true);
}
}, this});
}});
tabs.addTab({"CPU", [](gui::TabItem* tab, void* userData) {
SettingsWindow* sW = (SettingsWindow*)userData;
CPUSettings& cS = sW->cpuSettings;
gui::PushButton& apply = sW->apply;
if(cS.render()) {
if(cS.getModified())
sW->apply.setEnabled(true);
}
}, this});
tabs.addTab({"Audio", [](gui::TabItem* tab, void* userData) {
SettingsWindow* sW = (SettingsWindow*)userData;
AudioSettings& aS = sW->audioSettings;
gui::PushButton& apply = sW->apply;
if(aS.render()) {
if(aS.getModified())
tabs.addTab({"CPU", [&]() {
if(cpuSettings.render()) {
if(cpuSettings.getModified())
apply.setEnabled(true);
}
}, this});
}});
tabs.addTab({"Input", [](gui::TabItem* tab, void* userData) {
SettingsWindow* sW = (SettingsWindow*)userData;
sW->inputSettings.render();
InputSettings& iS = sW->inputSettings;
gui::PushButton& apply = sW->apply;
if(iS.render()) {
if(iS.getModified())
tabs.addTab({"Audio", [&]() {
if(audioSettings.render()) {
if(audioSettings.getModified())
apply.setEnabled(true);
}
}, this});
}});
tabs.addTab({"Input", [&]() {
if(inputSettings.render()) {
if(inputSettings.getModified())
apply.setEnabled(true);
}
}});
apply.setEnabled(false);
canvas.setFunc([&]() {
tabs.render();
if(apply.render()) {
auto newMap = inputSettings.GetMappedKeys();
if (keyMap != newMap)
keyMap = newMap;
apply.setEnabled(false);
std::ofstream file("resources/settings.json");
file << settings;
file.close();
}
});
}
bool SettingsWindow::render() {
tabs.render();
if(apply.render()) {
auto newMap = inputSettings.GetMappedKeys();
if (keyMap != newMap)
keyMap = newMap;
apply.setEnabled(false);
std::ofstream file("resources/settings.json");
file << settings;
file.close();
}
if(canvas.render())
return true;
return false;
}

View File

@@ -3,25 +3,17 @@
#include <CPUSettings.hpp>
#include <InputSettings.hpp>
#include <ImGuiImpl/TabBar.hpp>
#include <ImGuiImpl/PopupWindow.hpp>
#include <SDL3/SDL_keycode.h>
#include <memory>
class SettingsWindow final {
gui::PushButton cancel{"Cancel"}, apply{"Apply", "", false}, savesFolder{"Open", "Save path: {}"};
gui::PopupWindow canvas{"Settings"};
nlohmann::json settings;
CPUSettings cpuSettings{settings};
AudioSettings audioSettings{settings};
InputSettings inputSettings{settings};
//std::unique_ptr<QPushButton> cancel = std::make_unique<QPushButton>("Cancel");
//std::unique_ptr<QPushButton> apply = std::make_unique<QPushButton>("Apply");
//std::unique_ptr<QFileIconProvider> iconProv = std::make_unique<QFileIconProvider>();
//std::unique_ptr<QPushButton> folderBtn = std::make_unique<QPushButton>(iconProv->icon(QFileIconProvider::Folder), "");
//std::unique_ptr<QLabel> folderLabelPrefix = std::make_unique<QLabel>("Save files' path: ");
//std::unique_ptr<QLabel> folderLabel;
//std::unique_ptr<QHBoxLayout> generalLayout = std::make_unique<QHBoxLayout>();
//std::unique_ptr<QVBoxLayout> generalLayoutV = std::make_unique<QVBoxLayout>();
//std::unique_ptr<QTabWidget> tabs = std::make_unique<QTabWidget>();
//std::unique_ptr<QVBoxLayout> mainLayout = std::make_unique<QVBoxLayout>();
//std::unique_ptr<QHBoxLayout> buttonsLayout = std::make_unique<QHBoxLayout>();
public:
bool render();
SettingsWindow();
@@ -29,7 +21,5 @@ public:
[[nodiscard]] float getVolumeR() const { return audioSettings.volumeR.getValue() / 100.f; }
std::array<SDL_Keycode, 18> keyMap{};
nlohmann::json settings;
gui::TabBar tabs{"SettingsTabs"};
//std::unique_ptr<QWidget> generalSettings{};
};

View File

@@ -2,7 +2,7 @@
#include <cflags.hpp>
int main(int argc, char **argv) {
KaizenGui kaizenGui;
KaizenGui kaizenGui;
cflags::cflags flags;
std::string romPath;
std::string moviePath;

View File

@@ -3,6 +3,8 @@
#include <cstring>
#include <functional>
#include <byteswap.hpp>
#include <algorithm>
#include <vector>
namespace Util {
template <typename T>