We do a little saving (Widget + json serialization)

This commit is contained in:
CocoSimone
2022-12-17 02:33:09 +01:00
parent c1b57403cd
commit aff00bdca3
9 changed files with 211 additions and 74 deletions

3
.gitignore vendored
View File

@@ -15,4 +15,5 @@ disasm.txt
log.txt log.txt
.vs/ .vs/
CMakeSettings.json CMakeSettings.json
out/ out/
settings.json

View File

@@ -12,7 +12,7 @@ void App::Run() {
SDL_EventState(SDL_DROPFILE, SDL_ENABLE); SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
while (!core.done) { while (!core.done) {
core.Run(window, window.volumeL, window.volumeR); core.Run(window, window.settings.GetVolumeL(), window.settings.GetVolumeL());
core.UpdateController(state); core.UpdateController(state);
SDL_Event event; SDL_Event event;

158
src/frontend/Settings.cpp Normal file
View File

@@ -0,0 +1,158 @@
#include <Settings.hpp>
#include <fstream>
#include <filesystem>
#include <imgui.h>
using namespace std::filesystem;
Settings::Settings(n64::Core& core) {
auto modes = std::fstream::in | std::fstream::out;
auto fileExists = exists("resources/settings.json");
if(!fileExists) {
modes |= std::fstream::trunc;
}
std::fstream settingsFile{"resources/settings.json", modes};
if(fileExists) {
settings = json::parse(settingsFile);
auto entryCpuType = settings["cpu"]["type"];
if(!entryCpuType.empty()) {
cpuType = entryCpuType.get<std::string>();
if(cpuType == "dynarec") {
core.cpuType = n64::CpuType::Dynarec;
} else if(cpuType == "interpreter") {
core.cpuType = n64::CpuType::Interpreter;
} else {
util::panic("Unrecognized cpu type: {}\n", cpuType);
}
} else {
settingsFile.clear();
settings["cpu"]["type"] = "dynarec";
settingsFile << settings;
core.cpuType = n64::CpuType::Dynarec;
}
auto volumeREntry = settings["audio"]["volumeR"];
if(!volumeREntry.empty()) {
auto value = volumeREntry.get<float>();
volumeR = value;
} else {
settingsFile.clear();
settings["audio"]["volumeR"] = 0.5;
settingsFile << settings;
volumeR = 0.5;
}
auto volumeLEntry = settings["audio"]["volumeL"];
if(!volumeLEntry.empty()) {
auto value = volumeLEntry.get<float>();
volumeL = value;
} else {
settingsFile.clear();
settings["audio"]["volumeL"] = 0.5;
settingsFile << settings;
volumeL = 0.5;
}
auto lockChannelsEntry = settings["audio"]["lockChannels"];
if(!lockChannelsEntry.empty()) {
auto value = lockChannelsEntry.get<bool>();
lockChannels = value;
} else {
settingsFile.clear();
settings["audio"]["lockChannels"] = true;
settingsFile << settings;
lockChannels = true;
}
} else {
settings["cpu"]["type"] = "dynarec";
settings["audio"]["volumeR"] = 0.5;
settings["audio"]["volumeL"] = 0.5;
settings["audio"]["lockChannels"] = true;
core.cpuType = n64::CpuType::Dynarec;
volumeR = 0.5;
volumeL = 0.5;
lockChannels = true;
settingsFile << settings;
}
settingsFile.close();
}
Settings::~Settings() {
auto modes = std::fstream::out;
auto fileExists = exists("resources/settings.json");
if(fileExists) {
modes |= std::fstream::trunc;
std::fstream settingsFile{"resources/settings.json", modes};
settings["cpu"]["type"] = cpuType;
settings["audio"]["volumeR"] = volumeR;
settings["audio"]["volumeL"] = volumeL;
settings["audio"]["lockChannels"] = lockChannels;
settingsFile << settings;
settingsFile.close();
}
}
void Settings::RenderWidget(bool& show) {
if(show) {
ImGui::OpenPopup("Settings");
if(ImGui::BeginPopupModal("Settings", &show)) {
static enum { CPU, Audio } category = CPU;
if(ImGui::Button("CPU")) {
category = CPU;
}
ImGui::SameLine();
if(ImGui::Button("Audio")) {
category = Audio;
}
ImGui::Separator();
if(category == Audio) {
ImGui::Checkbox("Lock channels", &lockChannels);
ImGui::SliderFloat("Volume L", &volumeL, 0, 1, "%.2f", ImGuiSliderFlags_NoInput);
if (!lockChannels) {
ImGui::SliderFloat("Volume R", &volumeR, 0, 1, "%.2f", ImGuiSliderFlags_NoInput);
} else {
volumeR = volumeL;
ImGui::BeginDisabled();
ImGui::SliderFloat("Volume R", &volumeR, 0, 1, "%.2f", ImGuiSliderFlags_NoInput);
ImGui::EndDisabled();
}
} else if(category == CPU) {
const char* items[] = { "JIT", "Interpreter" };
static int currentIndex = [this]() {
if(cpuType == "dynarec") return 0;
else if(cpuType == "interpreter") return 1;
return 0;
}();
if(ImGui::BeginCombo("CPU type", items[currentIndex])) {
for (int n = 0; n < 2; n++) {
const bool is_selected = (currentIndex == n);
if (ImGui::Selectable(items[n], is_selected)) {
currentIndex = n;
}
if (is_selected) {
ImGui::SetItemDefaultFocus();
}
}
if(currentIndex == 0) {
cpuType = "dynarec";
}
if(currentIndex == 1) {
cpuType = "interpreter";
}
ImGui::EndCombo();
}
}
ImGui::EndPopup();
}
SetLockChannels(lockChannels);
SetVolumeL(volumeL);
SetVolumeR(volumeR);
}
}

27
src/frontend/Settings.hpp Normal file
View File

@@ -0,0 +1,27 @@
#pragma once
#include <nlohmann/json.hpp>
#include <Core.hpp>
using namespace nlohmann;
struct Settings {
Settings(n64::Core&);
~Settings();
float GetVolumeL() const { return volumeL; };
float GetVolumeR() const { return volumeR; };
bool GetLockChannels() const { return lockChannels; }
std::string GetCpuType() const { return cpuType; }
void SetVolumeL(float v) { volumeL = v; };
void SetVolumeR(float v) { volumeR = v; };
void SetLockChannels(bool v) { lockChannels = v; }
void SetCpuType(std::string v) { cpuType = v; }
void RenderWidget(bool& show);
private:
std::string cpuType = "interpreter";
float volumeL = 0.0, volumeR = 0.0;
bool lockChannels = true;
json settings;
};

View File

@@ -1,17 +1,14 @@
#include <filesystem>
#include <Window.hpp> #include <Window.hpp>
#include <nfd.hpp> #include <nfd.hpp>
#include <Core.hpp> #include <Core.hpp>
#include <Audio.hpp> #include <Audio.hpp>
#include <nlohmann/json.hpp>
#include <filesystem>
#include <SDL.h> #include <SDL.h>
VkInstance instance{}; VkInstance instance{};
using json = nlohmann::json;
Window::Window(n64::Core& core) { Window::Window(n64::Core& core) : settings(core) {
InitSDL(); InitSDL();
LoadSettings(core);
InitParallelRDP(core.mem.GetRDRAM(), window); InitParallelRDP(core.mem.GetRDRAM(), window);
InitImgui(); InitImgui();
NFD::Init(); NFD::Init();
@@ -22,34 +19,6 @@ Window::Window(n64::Core& core) {
&& event.window.windowID == SDL_GetWindowID(window); && event.window.windowID == SDL_GetWindowID(window);
} }
void Window::LoadSettings(n64::Core &core) {
settingsFile.open("settings.json", std::fstream::in | std::fstream::out);
if(settingsFile.is_open()) {
settings = json::parse(settingsFile);
auto entryCpuType = settings["cpu_type"];
if(!entryCpuType.empty()) {
auto cpuType = entryCpuType.get<std::string>();
if(cpuType == "dynarec") {
core.cpuType = n64::CpuType::Dynarec;
} else if(cpuType == "interpreter") {
core.cpuType = n64::CpuType::Interpreter;
} else {
util::panic("Unrecognized cpu type: {}\n", cpuType);
}
} else {
settings["cpu_type"] = "dynarec";
settingsFile << settings;
core.cpuType = n64::CpuType::Dynarec;
}
} else {
settings["cpu_type"] = "dynarec";
settingsFile << settings;
core.cpuType = n64::CpuType::Dynarec;
}
settingsFile.close();
}
void Window::InitSDL() { void Window::InitSDL() {
SDL_Init(SDL_INIT_EVERYTHING); SDL_Init(SDL_INIT_EVERYTHING);
n64::InitAudio(); n64::InitAudio();
@@ -217,6 +186,7 @@ void Window::Render(n64::Core& core) {
SDL_SetWindowTitle(window, windowTitle.c_str()); SDL_SetWindowTitle(window, windowTitle.c_str());
windowTitle = shadowWindowTitle; windowTitle = shadowWindowTitle;
} }
static bool showSettings = false; static bool showSettings = false;
bool showMainMenuBar = windowID == SDL_GetWindowID(SDL_GetMouseFocus()); bool showMainMenuBar = windowID == SDL_GetWindowID(SDL_GetMouseFocus());
if(showMainMenuBar) { if(showMainMenuBar) {
@@ -277,21 +247,7 @@ void Window::Render(n64::Core& core) {
ImGui::EndMainMenuBar(); ImGui::EndMainMenuBar();
} }
if(showSettings) { settings.RenderWidget(showSettings);
ImGui::OpenPopup("Settings");
if(ImGui::BeginPopupModal("Settings", &showSettings)) {
ImGui::Checkbox("Lock channels", &lockVolume);
ImGui::SliderFloat("Volume L", &volumeL, 0, 1, "%.2f", ImGuiSliderFlags_NoInput);
if (!lockVolume) {
ImGui::SliderFloat("Volume R", &volumeR, 0, 1, "%.2f", ImGuiSliderFlags_NoInput);
} else {
volumeR = volumeL;
ImGui::BeginDisabled();
ImGui::SliderFloat("Volume R", &volumeR, 0, 1, "%.2f", ImGuiSliderFlags_NoInput);
ImGui::EndDisabled();
}
ImGui::EndPopup();
}
}
ImGui::PopFont(); ImGui::PopFont();
} }

View File

@@ -6,9 +6,7 @@
#include <SDL.h> #include <SDL.h>
#include <Core.hpp> #include <Core.hpp>
#include <vector> #include <vector>
#include <nlohmann/json.hpp> #include <Settings.hpp>
using namespace nlohmann;
struct Window { struct Window {
explicit Window(n64::Core& core); explicit Window(n64::Core& core);
@@ -18,12 +16,9 @@ struct Window {
[[nodiscard]] bool gotClosed(SDL_Event event); [[nodiscard]] bool gotClosed(SDL_Event event);
ImFont *uiFont{}, *codeFont{}; ImFont *uiFont{}, *codeFont{};
u32 windowID{}; u32 windowID{};
float volumeL = 0.0, volumeR = 0.0; Settings settings;
void LoadROM(n64::Core& core, const std::string& path); void LoadROM(n64::Core& core, const std::string& path);
private: private:
json settings;
std::fstream settingsFile;
bool lockVolume = true;
SDL_Window* window{}; SDL_Window* window{};
std::string windowTitle{"Gadolinium"}; std::string windowTitle{"Gadolinium"};
std::string shadowWindowTitle{windowTitle}; std::string shadowWindowTitle{windowTitle};
@@ -31,7 +26,6 @@ private:
void InitSDL(); void InitSDL();
void InitImgui(); void InitImgui();
void Render(n64::Core& core); void Render(n64::Core& core);
void LoadSettings(n64::Core&);
VkPhysicalDevice physicalDevice{}; VkPhysicalDevice physicalDevice{};
VkDevice device{}; VkDevice device{};

View File

@@ -33,6 +33,7 @@ CartInfo Core::LoadROM(const std::string& rom_) {
void Core::Run(Window& window, float volumeL, float volumeR) { void Core::Run(Window& window, float volumeL, float volumeR) {
MMIO& mmio = mem.mmio; MMIO& mmio = mem.mmio;
Controller& controller = mmio.si.controller; Controller& controller = mmio.si.controller;
Registers& regs = CpuGetRegs();
for(int field = 0; field < mmio.vi.numFields; field++) { for(int field = 0; field < mmio.vi.numFields; field++) {
int frameCycles = 0; int frameCycles = 0;
@@ -41,33 +42,33 @@ void Core::Run(Window& window, float volumeL, float volumeR) {
mmio.vi.current = (i << 1) + field; mmio.vi.current = (i << 1) + field;
if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) { if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) {
InterruptRaise(mmio.mi, CpuGetRegs(), Interrupt::VI); InterruptRaise(mmio.mi, regs, Interrupt::VI);
} }
for(;cycles <= mmio.vi.cyclesPerHalfline; cycles++, frameCycles++) { for(;cycles <= mmio.vi.cyclesPerHalfline; cycles++, frameCycles++) {
CpuStep(mem); CpuStep(mem);
if(!mmio.rsp.spStatus.halt) { if(!mmio.rsp.spStatus.halt) {
cpu.regs.steps++; regs.steps++;
if(cpu.regs.steps > 2) { if(regs.steps > 2) {
mmio.rsp.steps += 2; mmio.rsp.steps += 2;
cpu.regs.steps -= 3; regs.steps -= 3;
} }
while(mmio.rsp.steps > 0) { while(mmio.rsp.steps > 0) {
mmio.rsp.steps--; mmio.rsp.steps--;
mmio.rsp.Step(CpuGetRegs(), mem); mmio.rsp.Step(regs, mem);
} }
} }
mmio.ai.Step(mem, CpuGetRegs(), 1, volumeL, volumeR); mmio.ai.Step(mem, regs, 1, volumeL, volumeR);
scheduler.tick(1, mem, CpuGetRegs()); scheduler.tick(1, mem, regs);
} }
cycles -= mmio.vi.cyclesPerHalfline; cycles -= mmio.vi.cyclesPerHalfline;
} }
if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) { if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) {
InterruptRaise(mmio.mi, CpuGetRegs(), Interrupt::VI); InterruptRaise(mmio.mi, regs, Interrupt::VI);
} }
UpdateScreenParallelRdp(*this, window, GetVI()); UpdateScreenParallelRdp(*this, window, GetVI());

View File

@@ -1,7 +1,7 @@
#include <n64/core/RSP.hpp> #include <n64/core/RSP.hpp>
#include <util.hpp> #include <util.hpp>
#include <n64/core/Mem.hpp> #include <n64/core/Mem.hpp>
#include <n64/core/cpu/Registers.hpp> #include <n64/core/registers/Registers.hpp>
namespace n64 { namespace n64 {
RSP::RSP() { RSP::RSP() {

View File

@@ -778,28 +778,28 @@ void Interpreter::trap(bool cond) {
} }
} }
void Cpu::mtc2(u32 instr) { void Interpreter::mtc2(u32 instr) {
cop2Latch = regs.gpr[RT(instr)]; cop2Latch = regs.gpr[RT(instr)];
} }
void Cpu::mfc2(u32 instr) { void Interpreter::mfc2(u32 instr) {
s32 value = cop2Latch; s32 value = cop2Latch;
regs.gpr[RT(instr)] = value; regs.gpr[RT(instr)] = value;
} }
void Cpu::dmtc2(u32 instr) { void Interpreter::dmtc2(u32 instr) {
cop2Latch = regs.gpr[RT(instr)]; cop2Latch = regs.gpr[RT(instr)];
} }
void Cpu::dmfc2(u32 instr) { void Interpreter::dmfc2(u32 instr) {
regs.gpr[RT(instr)] = cop2Latch; regs.gpr[RT(instr)] = cop2Latch;
} }
void Cpu::ctc2(u32) { void Interpreter::ctc2(u32) {
} }
void Cpu::cfc2(u32) { void Interpreter::cfc2(u32) {
} }