switch to INI for settings (easier), make settings a singleton thingy, slightly simplify core pause/stop/reset. Drop support for remappable inputs for now
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -6,7 +6,7 @@ saves/
|
|||||||
.vscode/
|
.vscode/
|
||||||
out/
|
out/
|
||||||
*.toml
|
*.toml
|
||||||
*.ini
|
imgui.ini
|
||||||
*.z64
|
*.z64
|
||||||
*.n64
|
*.n64
|
||||||
*.v64
|
*.v64
|
||||||
|
|||||||
2168
resources/gamecontrollerdb.h
Normal file
2168
resources/gamecontrollerdb.h
Normal file
File diff suppressed because it is too large
Load Diff
8
resources/options.ini
Normal file
8
resources/options.ini
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[general]
|
||||||
|
savepath=
|
||||||
|
[audio]
|
||||||
|
volumel=0.74
|
||||||
|
volumer=0.74
|
||||||
|
lock=true
|
||||||
|
[cpu]
|
||||||
|
type=interpreter
|
||||||
@@ -8,16 +8,16 @@ Core::Core() : cpu(std::make_unique<Interpreter>(parallel)) {}
|
|||||||
void Core::Stop() {
|
void Core::Stop() {
|
||||||
pause = true;
|
pause = true;
|
||||||
romLoaded = false;
|
romLoaded = false;
|
||||||
|
rom = {};
|
||||||
cpu->Reset();
|
cpu->Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Core::LoadTAS(const fs::path &path) const { return cpu->GetMem().mmio.si.pif.movie.Load(path); }
|
bool Core::LoadTAS(const fs::path &path) const { return cpu->GetMem().mmio.si.pif.movie.Load(path); }
|
||||||
|
|
||||||
void Core::LoadROM(const std::string &rom_) {
|
void Core::LoadROM(const std::string &rom_) {
|
||||||
pause = true;
|
Stop();
|
||||||
rom = rom_;
|
rom = rom_;
|
||||||
cpu->Reset();
|
cpu->Reset();
|
||||||
romLoaded = true;
|
|
||||||
|
|
||||||
std::string archive_types[] = {".zip", ".7z", ".rar", ".tar"};
|
std::string archive_types[] = {".zip", ".7z", ".rar", ".tar"};
|
||||||
|
|
||||||
@@ -37,6 +37,7 @@ void Core::LoadROM(const std::string &rom_) {
|
|||||||
cpu->GetMem().LoadSRAM(cpu->GetMem().saveType, rom);
|
cpu->GetMem().LoadSRAM(cpu->GetMem().saveType, rom);
|
||||||
cpu->GetMem().mmio.si.pif.Execute();
|
cpu->GetMem().mmio.si.pif.Execute();
|
||||||
pause = false;
|
pause = false;
|
||||||
|
romLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Run(float volumeL, float volumeR) {
|
void Core::Run(float volumeL, float volumeR) {
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
#include <AudioSettings.hpp>
|
#include <AudioSettings.hpp>
|
||||||
|
|
||||||
AudioSettings::AudioSettings(nlohmann::json &settings) : settings(settings) {
|
AudioSettings::AudioSettings() {
|
||||||
lockChannels.setChecked(JSONGetField<bool>(settings, "audio", "lock"));
|
lockChannels.setChecked(Options::GetInstance().GetValue<bool>("audio", "lock"));
|
||||||
volumeL.setValue(JSONGetField<float>(settings, "audio", "volumeL") * 100);
|
volumeL.setValue(Options::GetInstance().GetValue<float>("audio", "volumeL") * 100);
|
||||||
volumeR.setValue(JSONGetField<float>(settings, "audio", "volumeR") * 100);
|
volumeR.setValue(Options::GetInstance().GetValue<float>("audio", "volumeR") * 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioSettings::render() {
|
bool AudioSettings::render() {
|
||||||
if(lockChannels.render()) {
|
if(lockChannels.render()) {
|
||||||
auto isChecked = lockChannels.isChecked();
|
auto isChecked = lockChannels.isChecked();
|
||||||
JSONSetField(settings, "audio", "lock", isChecked);
|
Options::GetInstance().SetValue("audio", "lock", isChecked);
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
volumeR.setValue(volumeL.getValue());
|
volumeR.setValue(volumeL.getValue());
|
||||||
}
|
}
|
||||||
@@ -21,10 +21,10 @@ bool AudioSettings::render() {
|
|||||||
|
|
||||||
if(volumeL.render()) {
|
if(volumeL.render()) {
|
||||||
float valueL = volumeL.getValue();
|
float valueL = volumeL.getValue();
|
||||||
JSONSetField(settings, "audio", "volumeL", float(valueL) / 100.f);
|
Options::GetInstance().SetValue("audio", "volumeL", float(valueL) / 100.f);
|
||||||
if (lockChannels.isChecked()) {
|
if (lockChannels.isChecked()) {
|
||||||
volumeR.setValue(valueL);
|
volumeR.setValue(valueL);
|
||||||
JSONSetField(settings, "audio", "volumeR", float(valueL) / 100.f);
|
Options::GetInstance().SetValue("audio", "volumeR", float(valueL) / 100.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
modified = true;
|
modified = true;
|
||||||
@@ -34,7 +34,7 @@ bool AudioSettings::render() {
|
|||||||
|
|
||||||
if(volumeR.render()) {
|
if(volumeR.render()) {
|
||||||
if (!lockChannels.isChecked()) {
|
if (!lockChannels.isChecked()) {
|
||||||
JSONSetField(settings, "audio", "volumeR", float(volumeR.getValue()) / 100.f);
|
Options::GetInstance().SetValue("audio", "volumeR", float(volumeR.getValue()) / 100.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
modified = true;
|
modified = true;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <JSONUtils.hpp>
|
#include <Options.hpp>
|
||||||
#include <ImGuiImpl/Checkbox.hpp>
|
#include <ImGuiImpl/Checkbox.hpp>
|
||||||
#include <ImGuiImpl/Slider.hpp>
|
#include <ImGuiImpl/Slider.hpp>
|
||||||
|
|
||||||
@@ -9,9 +9,8 @@ class AudioSettings final {
|
|||||||
public:
|
public:
|
||||||
gui::SliderFloat volumeL{"Volume L", 0.f, 100.f, 0.f};
|
gui::SliderFloat volumeL{"Volume L", 0.f, 100.f, 0.f};
|
||||||
gui::SliderFloat volumeR{"Volume R", 0.f, 100.f, 0.f};
|
gui::SliderFloat volumeR{"Volume R", 0.f, 100.f, 0.f};
|
||||||
explicit AudioSettings(nlohmann::json &);
|
explicit AudioSettings();
|
||||||
bool render();
|
bool render();
|
||||||
void setModified(bool v) { modified = v; }
|
void setModified(bool v) { modified = v; }
|
||||||
bool getModified() { return modified; }
|
bool getModified() { return modified; }
|
||||||
nlohmann::json &settings;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ include_directories(
|
|||||||
../../external/imgui/backends
|
../../external/imgui/backends
|
||||||
../../external/nfd/src/include
|
../../external/nfd/src/include
|
||||||
../../external/cflags/include
|
../../external/cflags/include
|
||||||
|
../../external/mINI/src/
|
||||||
ImGuiImpl/
|
ImGuiImpl/
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -109,6 +110,7 @@ add_subdirectory(../../external/unarr unarr)
|
|||||||
add_subdirectory(../../external/SDL SDL)
|
add_subdirectory(../../external/SDL SDL)
|
||||||
add_subdirectory(../../external/cflags cflags)
|
add_subdirectory(../../external/cflags cflags)
|
||||||
add_subdirectory(../../external/imgui imgui)
|
add_subdirectory(../../external/imgui imgui)
|
||||||
|
add_subdirectory(../../external/mINI mINI)
|
||||||
add_subdirectory(../../external/nfd nfd)
|
add_subdirectory(../../external/nfd nfd)
|
||||||
set(CAPSTONE_ARCHITECTURE_DEFAULT OFF)
|
set(CAPSTONE_ARCHITECTURE_DEFAULT OFF)
|
||||||
set(CAPSTONE_MIPS_SUPPORT ON)
|
set(CAPSTONE_MIPS_SUPPORT ON)
|
||||||
@@ -127,10 +129,10 @@ add_executable(kaizen
|
|||||||
SettingsWindow.cpp
|
SettingsWindow.cpp
|
||||||
CPUSettings.hpp
|
CPUSettings.hpp
|
||||||
CPUSettings.cpp
|
CPUSettings.cpp
|
||||||
JSONUtils.hpp
|
|
||||||
AudioSettings.hpp
|
AudioSettings.hpp
|
||||||
AudioSettings.cpp
|
AudioSettings.cpp
|
||||||
NativeWindow.hpp
|
NativeWindow.hpp
|
||||||
|
../utils/Options.cpp
|
||||||
Debugger.hpp
|
Debugger.hpp
|
||||||
Debugger.cpp)
|
Debugger.cpp)
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
#include <CPUSettings.hpp>
|
#include <CPUSettings.hpp>
|
||||||
#include <JSONUtils.hpp>
|
#include <Options.hpp>
|
||||||
#include <log.hpp>
|
#include <log.hpp>
|
||||||
|
|
||||||
CPUSettings::CPUSettings(nlohmann::json &settings) : settings(settings) {
|
CPUSettings::CPUSettings() {
|
||||||
if (JSONGetField<std::string>(settings, "cpu_type") == "jit") {
|
if (Options::GetInstance().GetValue<std::string>("cpu", "type") == "jit") {
|
||||||
cpuTypes.setCurrentIndex(1);
|
cpuTypes.setCurrentIndex(1);
|
||||||
} else {
|
} else {
|
||||||
cpuTypes.setCurrentIndex(0);
|
cpuTypes.setCurrentIndex(0);
|
||||||
@@ -13,7 +13,7 @@ CPUSettings::CPUSettings(nlohmann::json &settings) : settings(settings) {
|
|||||||
bool CPUSettings::render() {
|
bool CPUSettings::render() {
|
||||||
if(cpuTypes.render()) {
|
if(cpuTypes.render()) {
|
||||||
if(cpuTypes.getCurrentIndex() == 0) {
|
if(cpuTypes.getCurrentIndex() == 0) {
|
||||||
JSONSetField(settings, "cpu_type", "interpreter");
|
Options::GetInstance().SetValue<std::string>("cpu", "type", "interpreter");
|
||||||
} else {
|
} else {
|
||||||
Util::panic("JIT should not be selectable??");
|
Util::panic("JIT should not be selectable??");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <JSONUtils.hpp>
|
#include <Options.hpp>
|
||||||
#include <ImGuiImpl/Combobox.hpp>
|
#include <ImGuiImpl/Combobox.hpp>
|
||||||
|
|
||||||
class CPUSettings final {
|
class CPUSettings final {
|
||||||
@@ -7,8 +7,7 @@ class CPUSettings final {
|
|||||||
bool modified = false;
|
bool modified = false;
|
||||||
public:
|
public:
|
||||||
bool render();
|
bool render();
|
||||||
explicit CPUSettings(nlohmann::json &);
|
explicit CPUSettings();
|
||||||
void setModified(bool v) { modified = v; }
|
void setModified(bool v) { modified = v; }
|
||||||
bool getModified() { return modified; }
|
bool getModified() { return modified; }
|
||||||
nlohmann::json &settings;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ EmuThread::EmuThread(const std::shared_ptr<n64::Core> &core, double &fps, Render
|
|||||||
renderWidget(renderWidget), core(core), settings(settings), fps(fps) {}
|
renderWidget(renderWidget), core(core), settings(settings), fps(fps) {}
|
||||||
|
|
||||||
void EmuThread::run() noexcept {
|
void EmuThread::run() noexcept {
|
||||||
isRunning = true;
|
if(!core->romLoaded) return;
|
||||||
|
|
||||||
auto lastSample = std::chrono::high_resolution_clock::now();
|
auto lastSample = std::chrono::high_resolution_clock::now();
|
||||||
auto avgFps = 16.667;
|
auto avgFps = 16.667;
|
||||||
@@ -49,15 +49,11 @@ void EmuThread::TogglePause() const noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EmuThread::Reset() const noexcept {
|
void EmuThread::Reset() const noexcept {
|
||||||
core->pause = true;
|
|
||||||
core->Stop();
|
core->Stop();
|
||||||
core->LoadROM(core->rom);
|
core->LoadROM(core->rom);
|
||||||
core->pause = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuThread::Stop() const noexcept {
|
void EmuThread::Stop() const noexcept {
|
||||||
Util::RPC::GetInstance().Update(Util::RPC::Idling);
|
Util::RPC::GetInstance().Update(Util::RPC::Idling);
|
||||||
core->rom = {};
|
|
||||||
core->pause = true;
|
|
||||||
core->Stop();
|
core->Stop();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public:
|
|||||||
void Reset() const noexcept;
|
void Reset() const noexcept;
|
||||||
void Stop() const noexcept;
|
void Stop() const noexcept;
|
||||||
|
|
||||||
bool interruptionRequested = false, isRunning = false, parallelRDPInitialized = false;
|
bool interruptionRequested = false, parallelRDPInitialized = false;
|
||||||
std::shared_ptr<n64::Core> core;
|
std::shared_ptr<n64::Core> core;
|
||||||
SettingsWindow &settings;
|
SettingsWindow &settings;
|
||||||
double& fps;
|
double& fps;
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <filesystem>
|
|
||||||
#include <fstream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
#include <common.hpp>
|
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
|
||||||
|
|
||||||
static FORCE_INLINE nlohmann::json JSONOpenOrCreate(const std::string &path) {
|
|
||||||
auto fileExists = fs::exists(path);
|
|
||||||
|
|
||||||
std::fstream file;
|
|
||||||
nlohmann::json json;
|
|
||||||
|
|
||||||
if (fileExists) {
|
|
||||||
file = std::fstream(path, std::fstream::in | std::fstream::out);
|
|
||||||
json = nlohmann::json::parse(file);
|
|
||||||
file.close();
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
file = std::fstream(path, std::fstream::in | std::fstream::out | std::fstream::trunc);
|
|
||||||
json["general"]["savePath"] = "";
|
|
||||||
json["audio"]["volumeL"] = 0.5;
|
|
||||||
json["audio"]["volumeR"] = 0.5;
|
|
||||||
json["audio"]["lock"] = true;
|
|
||||||
json["cpu_type"] = "interpreter";
|
|
||||||
|
|
||||||
file << json;
|
|
||||||
file.close();
|
|
||||||
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static FORCE_INLINE void JSONSetField(nlohmann::json &json, const std::string &key, const std::string &field,
|
|
||||||
const T &value) {
|
|
||||||
json[key][field] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static FORCE_INLINE T JSONGetField(nlohmann::json &json, const std::string &key, const std::string &field) {
|
|
||||||
return json[key][field].get<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static FORCE_INLINE void JSONSetField(nlohmann::json &json, const std::string &key, const T &value) {
|
|
||||||
json[key] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static FORCE_INLINE T JSONGetField(nlohmann::json &json, const std::string &key) {
|
|
||||||
return json[key].get<T>();
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <backend/Core.hpp>
|
#include <backend/Core.hpp>
|
||||||
#include <ImGuiImpl/StatusBar.hpp>
|
#include <ImGuiImpl/StatusBar.hpp>
|
||||||
#include <ImGuiImpl/GUI.hpp>
|
#include <ImGuiImpl/GUI.hpp>
|
||||||
|
#include <resources/gamecontrollerdb.h>
|
||||||
|
|
||||||
bool HandleInput(void *userdata, SDL_Event *event);
|
bool HandleInput(void *userdata, SDL_Event *event);
|
||||||
bool QueryDevices(void *userdata, SDL_Event *event);
|
bool QueryDevices(void *userdata, SDL_Event *event);
|
||||||
@@ -10,6 +11,7 @@ bool QueryDevices(void *userdata, SDL_Event *event);
|
|||||||
KaizenGui::KaizenGui() noexcept : window("Kaizen", 800, 600), core(std::make_shared<n64::Core>()), vulkanWidget(core, window.getHandle()), emuThread(core, fpsCounter, vulkanWidget, settingsWindow) {
|
KaizenGui::KaizenGui() noexcept : window("Kaizen", 800, 600), core(std::make_shared<n64::Core>()), vulkanWidget(core, window.getHandle()), emuThread(core, fpsCounter, vulkanWidget, settingsWindow) {
|
||||||
gui::Initialize(core->parallel.wsi, window.getHandle());
|
gui::Initialize(core->parallel.wsi, window.getHandle());
|
||||||
|
|
||||||
|
SDL_AddGamepadMapping(gamecontrollerdb_str);
|
||||||
SDL_AddEventWatch(HandleInput, this);
|
SDL_AddEventWatch(HandleInput, this);
|
||||||
SDL_AddEventWatch(QueryDevices, this);
|
SDL_AddEventWatch(QueryDevices, this);
|
||||||
|
|
||||||
@@ -59,6 +61,7 @@ KaizenGui::KaizenGui() noexcept : window("Kaizen", 800, 600), core(std::make_sha
|
|||||||
if(result == NFD_CANCEL) return;
|
if(result == NFD_CANCEL) return;
|
||||||
if(result == NFD_ERROR)
|
if(result == NFD_ERROR)
|
||||||
Util::panic("Error: {}", NFD::GetError());
|
Util::panic("Error: {}", NFD::GetError());
|
||||||
|
|
||||||
LoadROM(path.get());
|
LoadROM(path.get());
|
||||||
}},
|
}},
|
||||||
{"Exit", [&]() {
|
{"Exit", [&]() {
|
||||||
@@ -233,7 +236,6 @@ void KaizenGui::LoadROM(const std::string &path) noexcept {
|
|||||||
|
|
||||||
void KaizenGui::run() {
|
void KaizenGui::run() {
|
||||||
while(!quit) {
|
while(!quit) {
|
||||||
emuThread.run();
|
|
||||||
SDL_Event e;
|
SDL_Event e;
|
||||||
while (SDL_PollEvent(&e)) {
|
while (SDL_PollEvent(&e)) {
|
||||||
ImGui_ImplSDL3_ProcessEvent(&e);
|
ImGui_ImplSDL3_ProcessEvent(&e);
|
||||||
@@ -245,6 +247,7 @@ void KaizenGui::run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emuThread.run();
|
||||||
RenderUI();
|
RenderUI();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,10 +25,7 @@ private:
|
|||||||
class SDLWSIPlatform final : public Vulkan::WSIPlatform {
|
class SDLWSIPlatform final : public Vulkan::WSIPlatform {
|
||||||
public:
|
public:
|
||||||
explicit SDLWSIPlatform(const std::shared_ptr<n64::Core> &core, SDL_Window* window) : window(window), core(core) {}
|
explicit SDLWSIPlatform(const std::shared_ptr<n64::Core> &core, SDL_Window* window) : window(window), core(core) {}
|
||||||
~SDLWSIPlatform() {
|
~SDLWSIPlatform() = default;
|
||||||
if(gamepadConnected)
|
|
||||||
SDL_CloseGamepad(gamepad);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<const char *> get_instance_extensions() override {
|
std::vector<const char *> get_instance_extensions() override {
|
||||||
auto vec = std::vector<const char *>();
|
auto vec = std::vector<const char *>();
|
||||||
@@ -71,7 +68,6 @@ public:
|
|||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<n64::Core> core;
|
std::shared_ptr<n64::Core> core;
|
||||||
SDL_Gamepad *gamepad{};
|
|
||||||
bool gamepadConnected = false;
|
bool gamepadConnected = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include <nfd.hpp>
|
#include <nfd.hpp>
|
||||||
#include <log.hpp>
|
#include <log.hpp>
|
||||||
#include <JSONUtils.hpp>
|
#include <Options.hpp>
|
||||||
|
|
||||||
std::string savePath;
|
std::string savePath;
|
||||||
|
|
||||||
SettingsWindow::SettingsWindow() : settings{JSONOpenOrCreate("resources/settings.json")}, cpuSettings{settings}, audioSettings{settings} {
|
SettingsWindow::SettingsWindow() {
|
||||||
savesFolder.setName(fmt::format("Save path: {}",
|
savesFolder.setName(fmt::format("Save path: {}",
|
||||||
JSONGetField<std::string>(settings, "general", "savePath")));
|
Options::GetInstance().GetValue<std::string>("general", "savePath")));
|
||||||
|
|
||||||
tabs.addTab({"General", [&]() {
|
tabs.addTab({"General", [&]() {
|
||||||
if(savesFolder.render()) {
|
if(savesFolder.render()) {
|
||||||
@@ -22,7 +22,7 @@ SettingsWindow::SettingsWindow() : settings{JSONOpenOrCreate("resources/settings
|
|||||||
Util::panic("Error: {}", NFD::GetError());
|
Util::panic("Error: {}", NFD::GetError());
|
||||||
|
|
||||||
savesFolder.setName(fmt::format("Save path: {}", outPath.get()));
|
savesFolder.setName(fmt::format("Save path: {}", outPath.get()));
|
||||||
JSONSetField(settings, "general", "savePath", outPath.get());
|
Options::GetInstance().SetValue<std::string>("general", "savePath", outPath.get());
|
||||||
apply.setEnabled(true);
|
apply.setEnabled(true);
|
||||||
}
|
}
|
||||||
}});
|
}});
|
||||||
@@ -48,9 +48,7 @@ SettingsWindow::SettingsWindow() : settings{JSONOpenOrCreate("resources/settings
|
|||||||
|
|
||||||
if(apply.render()) {
|
if(apply.render()) {
|
||||||
apply.setEnabled(false);
|
apply.setEnabled(false);
|
||||||
std::ofstream file("resources/settings.json");
|
Options::GetInstance().Apply();
|
||||||
file << settings;
|
|
||||||
file.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
class SettingsWindow final {
|
class SettingsWindow final {
|
||||||
gui::PushButton apply{"Apply", "", false}, savesFolder{"Open", "Save path: {}"};
|
gui::PushButton apply{"Apply", "", false}, savesFolder{"Open", "Save path: {}"};
|
||||||
nlohmann::json settings;
|
|
||||||
CPUSettings cpuSettings;
|
CPUSettings cpuSettings;
|
||||||
AudioSettings audioSettings;
|
AudioSettings audioSettings;
|
||||||
public:
|
public:
|
||||||
|
|||||||
31
src/utils/Options.cpp
Normal file
31
src/utils/Options.cpp
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#include <Options.hpp>
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void Options::SetValue<std::string>(const std::string &key, const std::string &field, const std::string &value) {
|
||||||
|
structure[key][field] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void Options::SetValue<float>(const std::string &key, const std::string &field, const float &value) {
|
||||||
|
structure[key][field] = fmt::format("{:.2f}", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void Options::SetValue<bool>(const std::string &key, const std::string &field, const bool &value) {
|
||||||
|
structure[key][field] = value ? "true" : "false";
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
std::string Options::GetValue<std::string>(const std::string &key, const std::string &field) {
|
||||||
|
return structure[key][field];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
float Options::GetValue<float>(const std::string &key, const std::string &field) {
|
||||||
|
return std::stof(structure[key][field]);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
bool Options::GetValue<bool>(const std::string &key, const std::string &field) {
|
||||||
|
return structure[key][field] == "true" ? true : false;
|
||||||
|
}
|
||||||
@@ -2,48 +2,44 @@
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <common.hpp>
|
#include <common.hpp>
|
||||||
|
#include <mini/ini.h>
|
||||||
|
#include <log.hpp>
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
static FORCE_INLINE mINI::INIStructure JSONOpenOrCreate(const std::string &path) {
|
struct Options {
|
||||||
auto fileExists = fs::exists(path);
|
Options() : file{"resources/options.ini"} {
|
||||||
|
auto fileExists = fs::exists("resources/options.ini");
|
||||||
|
if(fileExists) {
|
||||||
|
file.read(structure);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mINI::INIStructure options;
|
structure["general"]["savePath"] = "";
|
||||||
mINI::INIFile file(path);
|
structure["audio"]["volumeL"] = "0.5";
|
||||||
|
structure["audio"]["volumeR"] = "0.5";
|
||||||
|
structure["audio"]["lock"] = "true";
|
||||||
|
structure["cpu"]["type"] = "interpreter";
|
||||||
|
|
||||||
if (fileExists) {
|
if(!file.generate(structure))
|
||||||
file.read(options);
|
Util::panic("Couldn't generate settings' INI!");
|
||||||
return options;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
options["general"]["savePath"] = "";
|
static Options &GetInstance() {
|
||||||
options["audio"]["volumeL"] = 0.5;
|
static Options instance;
|
||||||
options["audio"]["volumeR"] = 0.5;
|
return instance;
|
||||||
options["audio"]["lock"] = true;
|
}
|
||||||
options["cpu"]["type"] = "interpreter";
|
|
||||||
|
|
||||||
file.write(options);
|
template <typename T>
|
||||||
|
void SetValue(const std::string &key, const std::string &field, const T &value);
|
||||||
|
template <typename T>
|
||||||
|
T GetValue(const std::string &key, const std::string &field);
|
||||||
|
|
||||||
return options;
|
void Apply() {
|
||||||
}
|
if(!file.write(structure))
|
||||||
|
Util::panic("Could not modify options on disk!");
|
||||||
template <typename T>
|
}
|
||||||
static FORCE_INLINE void JSONSetField(mINI::INIStructure &options, const std::string &key, const std::string &field,
|
private:
|
||||||
const T &value) {
|
mINI::INIFile file;
|
||||||
options[key][field] = value;
|
mINI::INIStructure structure;
|
||||||
}
|
};
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static FORCE_INLINE T JSONGetField(mINI::INIStructure &options, const std::string &key, const std::string &field) {
|
|
||||||
return options[key][field];
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static FORCE_INLINE void JSONSetField(mINI::INIStructure &options, const std::string &key, const T &value) {
|
|
||||||
options[key] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static FORCE_INLINE T JSONGetField(mINI::INIStructure &options, const std::string &key) {
|
|
||||||
return options[key];
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user