oops
This commit is contained in:
+231
-205
@@ -8,7 +8,9 @@
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
KaizenGui::KaizenGui() noexcept : window("Kaizen " KAIZEN_VERSION_STR, 1280, 720), settingsWindow(window), emuThread(fpsCounter, settingsWindow), vulkanWidget(window.getHandle(), emuThread.rdramCopy.data()) {
|
||||
KaizenGui::KaizenGui() noexcept :
|
||||
window("Kaizen " KAIZEN_VERSION_STR, 1280, 720), settingsWindow(window), emuThread(fpsCounter, settingsWindow),
|
||||
vulkanWidget(window.getHandle(), emuThread.rdramCopy.data()) {
|
||||
gui::Initialize(n64::Core::GetInstance().parallel.wsi, window.getHandle());
|
||||
SDL_InitSubSystem(SDL_INIT_GAMEPAD);
|
||||
|
||||
@@ -36,203 +38,210 @@ void KaizenGui::QueryDevices(const SDL_Event &event) {
|
||||
if (gamepad)
|
||||
SDL_CloseGamepad(gamepad);
|
||||
break;
|
||||
default: break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void KaizenGui::HandleInput(const SDL_Event &event) {
|
||||
const n64::Core& core = n64::Core::GetInstance();
|
||||
const n64::Core &core = n64::Core::GetInstance();
|
||||
n64::PIF &pif = n64::Core::GetMem().mmio.si.pif;
|
||||
switch(event.type) {
|
||||
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
|
||||
if(!gamepad)
|
||||
break;
|
||||
{
|
||||
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::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);
|
||||
switch (event.type) {
|
||||
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
|
||||
if (!gamepad)
|
||||
break;
|
||||
{
|
||||
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::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 /= static_cast<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 /= static_cast<float>(std::abs(SDL_JOYSTICK_AXIS_MIN));
|
||||
} else {
|
||||
yclamped /= SDL_JOYSTICK_AXIS_MAX;
|
||||
}
|
||||
|
||||
yclamped *= 86;
|
||||
|
||||
pif.UpdateAxis(0, n64::Controller::Axis::Y, static_cast<s8>(-yclamped));
|
||||
pif.UpdateAxis(0, n64::Controller::Axis::X, static_cast<s8>( xclamped));
|
||||
float xclamped = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTX);
|
||||
if (xclamped < 0) {
|
||||
xclamped /= static_cast<float>(std::abs(SDL_JOYSTICK_AXIS_MAX));
|
||||
} else {
|
||||
xclamped /= SDL_JOYSTICK_AXIS_MAX;
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
|
||||
case SDL_EVENT_GAMEPAD_BUTTON_UP:
|
||||
if(!gamepad)
|
||||
break;
|
||||
|
||||
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::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));
|
||||
break;
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
case SDL_EVENT_KEY_UP:
|
||||
{
|
||||
const auto keys = SDL_GetKeyboardState(nullptr);
|
||||
if((keys[SDL_SCANCODE_LCTRL] || keys[SDL_SCANCODE_RCTRL]) && keys[SDL_SCANCODE_O]) {
|
||||
fileDialogOpen = true;
|
||||
}
|
||||
|
||||
fastForward = keys[SDL_SCANCODE_SPACE];
|
||||
if(!unlockFramerate)
|
||||
core.parallel.SetFramerateUnlocked(fastForward);
|
||||
xclamped *= 86;
|
||||
|
||||
if(core.romLoaded) {
|
||||
if(keys[SDL_SCANCODE_P]) {
|
||||
emuThread.TogglePause();
|
||||
}
|
||||
|
||||
if(keys[SDL_SCANCODE_R]) {
|
||||
emuThread.Reset();
|
||||
}
|
||||
|
||||
if(keys[SDL_SCANCODE_Q]) {
|
||||
emuThread.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
if(gamepad)
|
||||
break;
|
||||
|
||||
pif.UpdateButton(0, n64::Controller::Key::Z, keys[SDL_SCANCODE_Z]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::CUp, keys[SDL_SCANCODE_HOME]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::CDown, keys[SDL_SCANCODE_END]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::CLeft, keys[SDL_SCANCODE_DELETE]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::CRight, keys[SDL_SCANCODE_PAGEDOWN]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::A, keys[SDL_SCANCODE_X]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::B, keys[SDL_SCANCODE_C]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::Start, keys[SDL_SCANCODE_RETURN]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::DUp, keys[SDL_SCANCODE_I]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::DDown, keys[SDL_SCANCODE_K]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::DLeft, keys[SDL_SCANCODE_J]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::DRight, keys[SDL_SCANCODE_L]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::LT, keys[SDL_SCANCODE_A]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::RT, keys[SDL_SCANCODE_S]);
|
||||
|
||||
float x = 0, y = 0;
|
||||
|
||||
if (keys[SDL_SCANCODE_UP]) y = 86;
|
||||
if (keys[SDL_SCANCODE_DOWN]) y = -86;
|
||||
if (keys[SDL_SCANCODE_LEFT]) x = -86;
|
||||
if (keys[SDL_SCANCODE_RIGHT]) x = 86;
|
||||
|
||||
pif.UpdateAxis(0, n64::Controller::Axis::X, x);
|
||||
pif.UpdateAxis(0, n64::Controller::Axis::Y, y);
|
||||
float yclamped = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTY);
|
||||
if (yclamped < 0) {
|
||||
yclamped /= static_cast<float>(std::abs(SDL_JOYSTICK_AXIS_MIN));
|
||||
} else {
|
||||
yclamped /= SDL_JOYSTICK_AXIS_MAX;
|
||||
}
|
||||
|
||||
yclamped *= 86;
|
||||
|
||||
pif.UpdateAxis(0, n64::Controller::Axis::Y, static_cast<s8>(-yclamped));
|
||||
pif.UpdateAxis(0, n64::Controller::Axis::X, static_cast<s8>(xclamped));
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
|
||||
case SDL_EVENT_GAMEPAD_BUTTON_UP:
|
||||
if (!gamepad)
|
||||
break;
|
||||
default: break;
|
||||
|
||||
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::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));
|
||||
break;
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
case SDL_EVENT_KEY_UP:
|
||||
{
|
||||
const auto keys = SDL_GetKeyboardState(nullptr);
|
||||
if ((keys[SDL_SCANCODE_LCTRL] || keys[SDL_SCANCODE_RCTRL]) && keys[SDL_SCANCODE_O]) {
|
||||
fileDialogOpen = true;
|
||||
}
|
||||
|
||||
fastForward = keys[SDL_SCANCODE_SPACE];
|
||||
if (!unlockFramerate)
|
||||
core.parallel.SetFramerateUnlocked(fastForward);
|
||||
|
||||
if (core.romLoaded) {
|
||||
if (keys[SDL_SCANCODE_P]) {
|
||||
emuThread.TogglePause();
|
||||
}
|
||||
|
||||
if (keys[SDL_SCANCODE_R]) {
|
||||
emuThread.Reset();
|
||||
}
|
||||
|
||||
if (keys[SDL_SCANCODE_Q]) {
|
||||
emuThread.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
if (gamepad)
|
||||
break;
|
||||
|
||||
pif.UpdateButton(0, n64::Controller::Key::Z, keys[SDL_SCANCODE_Z]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::CUp, keys[SDL_SCANCODE_HOME]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::CDown, keys[SDL_SCANCODE_END]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::CLeft, keys[SDL_SCANCODE_DELETE]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::CRight, keys[SDL_SCANCODE_PAGEDOWN]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::A, keys[SDL_SCANCODE_X]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::B, keys[SDL_SCANCODE_C]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::Start, keys[SDL_SCANCODE_RETURN]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::DUp, keys[SDL_SCANCODE_I]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::DDown, keys[SDL_SCANCODE_K]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::DLeft, keys[SDL_SCANCODE_J]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::DRight, keys[SDL_SCANCODE_L]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::LT, keys[SDL_SCANCODE_A]);
|
||||
pif.UpdateButton(0, n64::Controller::Key::RT, keys[SDL_SCANCODE_S]);
|
||||
|
||||
float x = 0, y = 0;
|
||||
|
||||
if (keys[SDL_SCANCODE_UP])
|
||||
y = 86;
|
||||
if (keys[SDL_SCANCODE_DOWN])
|
||||
y = -86;
|
||||
if (keys[SDL_SCANCODE_LEFT])
|
||||
x = -86;
|
||||
if (keys[SDL_SCANCODE_RIGHT])
|
||||
x = 86;
|
||||
|
||||
pif.UpdateAxis(0, n64::Controller::Axis::X, x);
|
||||
pif.UpdateAxis(0, n64::Controller::Axis::Y, y);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<std::optional<s64>, std::optional<Util::Error::MemoryAccess>> RenderErrorMessageDetails() {
|
||||
auto lastPC = Util::Error::GetLastPC();
|
||||
if(lastPC.has_value()) {
|
||||
if (lastPC.has_value()) {
|
||||
ImGui::Text("%s", std::format("Occurred @ PC = {:016X}", Util::Error::GetLastPC().value()).c_str());
|
||||
}
|
||||
|
||||
auto memoryAccess = Util::Error::GetMemoryAccess();
|
||||
if(memoryAccess.has_value()) {
|
||||
if (memoryAccess.has_value()) {
|
||||
const auto [is_write, size, address, written_val] = memoryAccess.value();
|
||||
ImGui::Text("%s", std::format("{} {}-bit value @ {:08X}{}", is_write ? "Writing" : "Reading",
|
||||
static_cast<u8>(size), address,
|
||||
is_write ? std::format(" (value = 0x{:X})", written_val) : "")
|
||||
.c_str());
|
||||
ImGui::Text("%s",
|
||||
std::format("{} {}-bit value @ {:08X}{}", is_write ? "Writing" : "Reading", static_cast<u8>(size),
|
||||
address, is_write ? std::format(" (value = 0x{:X})", written_val) : "")
|
||||
.c_str());
|
||||
}
|
||||
|
||||
return {lastPC, memoryAccess};
|
||||
}
|
||||
|
||||
void KaizenGui::RenderUI() {
|
||||
n64::Core& core = n64::Core::GetInstance();
|
||||
n64::Core &core = n64::Core::GetInstance();
|
||||
gui::StartFrame();
|
||||
|
||||
if(ImGui::BeginMainMenuBar()) {
|
||||
if(ImGui::BeginMenu("File")) {
|
||||
if(ImGui::MenuItem("Open", "Ctrl-O")) {
|
||||
if (ImGui::BeginMainMenuBar()) {
|
||||
if (ImGui::BeginMenu("File")) {
|
||||
if (ImGui::MenuItem("Open", "Ctrl-O")) {
|
||||
fileDialogOpen = true;
|
||||
}
|
||||
if(ImGui::MenuItem("Exit")) {
|
||||
if (ImGui::MenuItem("Exit")) {
|
||||
quit = true;
|
||||
emuThread.Stop();
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if(ImGui::BeginMenu("Emulation")) {
|
||||
if (ImGui::BeginMenu("Emulation")) {
|
||||
ImGui::BeginDisabled(!core.romLoaded);
|
||||
|
||||
if(ImGui::MenuItem(core.pause ? "Resume" : "Pause", "P")) {
|
||||
|
||||
if (ImGui::MenuItem(core.pause ? "Resume" : "Pause", "P")) {
|
||||
emuThread.TogglePause();
|
||||
}
|
||||
|
||||
if(ImGui::MenuItem("Reset", "R")) {
|
||||
|
||||
if (ImGui::MenuItem("Reset", "R")) {
|
||||
emuThread.Reset();
|
||||
}
|
||||
|
||||
if(ImGui::MenuItem("Stop", "Q")) {
|
||||
|
||||
if (ImGui::MenuItem("Stop", "Q")) {
|
||||
emuThread.Stop();
|
||||
core.romLoaded = false;
|
||||
}
|
||||
|
||||
if(ImGui::Checkbox("Unlock framerate", &unlockFramerate)) {
|
||||
|
||||
if (ImGui::Checkbox("Unlock framerate", &unlockFramerate)) {
|
||||
core.parallel.SetFramerateUnlocked(unlockFramerate);
|
||||
}
|
||||
|
||||
if(ImGui::MenuItem("Open Debugger")) {
|
||||
if (ImGui::MenuItem("Open Debugger")) {
|
||||
debugger.Open();
|
||||
}
|
||||
|
||||
ImGui::EndDisabled();
|
||||
|
||||
if(ImGui::MenuItem("Options")) {
|
||||
if (ImGui::MenuItem("Options")) {
|
||||
settingsWindow.isOpen = true;
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if(ImGui::BeginMenu("Help")) {
|
||||
if(ImGui::MenuItem("About")) {
|
||||
if (ImGui::BeginMenu("Help")) {
|
||||
if (ImGui::MenuItem("About")) {
|
||||
aboutOpen = true;
|
||||
}
|
||||
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::EndMainMenuBar();
|
||||
}
|
||||
|
||||
if(!Util::Error::IsHandled()) {
|
||||
if (!Util::Error::IsHandled()) {
|
||||
ImGui::OpenPopup(Util::Error::GetSeverity().as_c_str());
|
||||
}
|
||||
|
||||
if(settingsWindow.isOpen) {
|
||||
|
||||
if (settingsWindow.isOpen) {
|
||||
ImGui::OpenPopup("Settings", ImGuiPopupFlags_None);
|
||||
}
|
||||
|
||||
if(aboutOpen) {
|
||||
if (aboutOpen) {
|
||||
ImGui::OpenPopup("About Kaizen");
|
||||
}
|
||||
|
||||
@@ -250,11 +259,11 @@ void KaizenGui::RenderUI() {
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Kaizen %s%s", KAIZEN_USE_HASH ? "dev build " : "", KAIZEN_VERSION_STR);
|
||||
ImGui::Separator();
|
||||
if(ImGui::Button("OK")) {
|
||||
if (ImGui::Button("OK")) {
|
||||
aboutOpen = false;
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
@@ -262,43 +271,48 @@ void KaizenGui::RenderUI() {
|
||||
|
||||
if (ImGui::BeginPopupModal(Util::Error::GetSeverity().as_c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
emuThread.TogglePause();
|
||||
switch(Util::Error::GetSeverity().as_enum) {
|
||||
case Util::Error::Severity::WARN: {
|
||||
switch (Util::Error::GetSeverity().as_enum) {
|
||||
case Util::Error::Severity::WARN:
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_TitleBg, 0x8054eae5);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, 0xff7be4e1);
|
||||
ImGui::Text("Warning of type: %s", Util::Error::GetType().as_c_str());
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::Text(R"(Warning message: "%s")", Util::Error::GetError().c_str());
|
||||
RenderErrorMessageDetails();
|
||||
|
||||
if(n64::Core::GetInstance().romLoaded && !n64::Core::GetInstance().pause) {
|
||||
const bool ignore = ImGui::Button("Try continuing"); ImGui::SameLine();
|
||||
const bool stop = ImGui::Button("Stop emulation"); ImGui::SameLine();
|
||||
if (n64::Core::GetInstance().romLoaded && !n64::Core::GetInstance().pause) {
|
||||
const bool ignore = ImGui::Button("Try continuing");
|
||||
ImGui::SameLine();
|
||||
const bool stop = ImGui::Button("Stop emulation");
|
||||
ImGui::SameLine();
|
||||
const bool chooseAnother = ImGui::Button("Choose another ROM");
|
||||
if(ignore || stop || chooseAnother) {
|
||||
if (ignore || stop || chooseAnother) {
|
||||
Util::Error::SetHandled();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
if(ignore) {
|
||||
if (ignore) {
|
||||
emuThread.TogglePause();
|
||||
}
|
||||
|
||||
if(stop || chooseAnother) {
|
||||
if (stop || chooseAnother) {
|
||||
emuThread.Stop();
|
||||
}
|
||||
|
||||
if(chooseAnother) {
|
||||
|
||||
if (chooseAnother) {
|
||||
fileDialogOpen = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(ImGui::Button("OK"))
|
||||
if (ImGui::Button("OK"))
|
||||
ImGui::CloseCurrentPopup();
|
||||
} break;
|
||||
case Util::Error::Severity::UNRECOVERABLE: {
|
||||
}
|
||||
break;
|
||||
case Util::Error::Severity::UNRECOVERABLE:
|
||||
{
|
||||
emuThread.Stop();
|
||||
ImGui::PushStyleColor(ImGuiCol_TitleBg, 0x800000ff);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, 0xff3b3bbf);
|
||||
@@ -308,10 +322,12 @@ void KaizenGui::RenderUI() {
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::Text(R"(Error message: "%s")", Util::Error::GetError().c_str());
|
||||
RenderErrorMessageDetails();
|
||||
if(ImGui::Button("OK"))
|
||||
if (ImGui::Button("OK"))
|
||||
ImGui::CloseCurrentPopup();
|
||||
} break;
|
||||
case Util::Error::Severity::NON_FATAL: {
|
||||
}
|
||||
break;
|
||||
case Util::Error::Severity::NON_FATAL:
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_TitleBg, 0x800000ff);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, 0xff3b3bbf);
|
||||
ImGui::Text("An error has occurred!");
|
||||
@@ -321,48 +337,54 @@ void KaizenGui::RenderUI() {
|
||||
ImGui::Text(R"(Error message: "%s")", Util::Error::GetError().c_str());
|
||||
auto [lastPC, memoryAccess] = RenderErrorMessageDetails();
|
||||
|
||||
const bool ignore = ImGui::Button("Try continuing"); ImGui::SameLine();
|
||||
const bool stop = ImGui::Button("Stop emulation"); ImGui::SameLine();
|
||||
const bool ignore = ImGui::Button("Try continuing");
|
||||
ImGui::SameLine();
|
||||
const bool stop = ImGui::Button("Stop emulation");
|
||||
ImGui::SameLine();
|
||||
const bool chooseAnother = ImGui::Button("Choose another ROM");
|
||||
const bool openInDebugger = lastPC.has_value() ? ImGui::Button("Add breakpoint at this PC and open the debugger") : false;
|
||||
if(ignore || stop || chooseAnother || openInDebugger) {
|
||||
const bool openInDebugger =
|
||||
lastPC.has_value() ? ImGui::Button("Add breakpoint at this PC and open the debugger") : false;
|
||||
if (ignore || stop || chooseAnother || openInDebugger) {
|
||||
Util::Error::SetHandled();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
if(ignore) {
|
||||
if (ignore) {
|
||||
emuThread.TogglePause();
|
||||
}
|
||||
|
||||
if(stop || chooseAnother) {
|
||||
if (stop || chooseAnother) {
|
||||
emuThread.Stop();
|
||||
}
|
||||
|
||||
if(chooseAnother) {
|
||||
|
||||
if (chooseAnother) {
|
||||
fileDialogOpen = true;
|
||||
}
|
||||
|
||||
if(openInDebugger) {
|
||||
if(!n64::Core::GetInstance().breakpoints.contains(lastPC.value()))
|
||||
if (openInDebugger) {
|
||||
if (!n64::Core::GetInstance().breakpoints.contains(lastPC.value()))
|
||||
n64::Core::GetInstance().ToggleBreakpoint(lastPC.value());
|
||||
|
||||
|
||||
debugger.Open();
|
||||
emuThread.Reset();
|
||||
}
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if(ImGui::BeginMainStatusBar()) {
|
||||
|
||||
if (ImGui::BeginMainStatusBar()) {
|
||||
ImGui::Text("FPS: %.2f", ImGui::GetIO().Framerate);
|
||||
ImGui::EndMainStatusBar();
|
||||
}
|
||||
|
||||
if (shouldDisplaySpinner) {
|
||||
ImGui::SetNextWindowPos({static_cast<float>(width) * 0.5f, static_cast<float>(height) * 0.5f}, 0, ImVec2(0.5f, 0.5f));
|
||||
ImGui::SetNextWindowPos({static_cast<float>(width) * 0.5f, static_cast<float>(height) * 0.5f}, 0,
|
||||
ImVec2(0.5f, 0.5f));
|
||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, IM_COL32_BLACK_TRANS);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
||||
|
||||
@@ -387,47 +409,51 @@ void KaizenGui::RenderUI() {
|
||||
ImGui::RenderPlatformWindowsDefault();
|
||||
}
|
||||
|
||||
if(fileDialogOpen) {
|
||||
if (fileDialogOpen) {
|
||||
fileDialogOpen = false;
|
||||
constexpr SDL_DialogFileFilter filters[] = {{"All files", "*"}, {"Nintendo 64 executable", "n64;z64;v64"}, {"Nintendo 64 executable archive", "rar;tar;zip;7z"}};
|
||||
SDL_ShowOpenFileDialog([](void *userdata, const char * const *filelist, int) {
|
||||
auto kaizen = static_cast<KaizenGui*>(userdata);
|
||||
|
||||
if (!filelist) {
|
||||
panic("An error occured: {}", SDL_GetError());
|
||||
}
|
||||
constexpr SDL_DialogFileFilter filters[] = {{"All files", "*"},
|
||||
{"Nintendo 64 executable", "n64;z64;v64"},
|
||||
{"Nintendo 64 executable archive", "rar;tar;zip;7z"}};
|
||||
SDL_ShowOpenFileDialog(
|
||||
[](void *userdata, const char *const *filelist, int) {
|
||||
auto kaizen = static_cast<KaizenGui *>(userdata);
|
||||
|
||||
if (!*filelist) {
|
||||
warn("The user did not select any file.");
|
||||
warn("Most likely, the dialog was canceled.");
|
||||
return;
|
||||
}
|
||||
if (!filelist) {
|
||||
panic("An error occured: {}", SDL_GetError());
|
||||
}
|
||||
|
||||
kaizen->fileToLoad = *filelist;
|
||||
kaizen->shouldDisplaySpinner = true;
|
||||
if (!*filelist) {
|
||||
warn("The user did not select any file.");
|
||||
warn("Most likely, the dialog was canceled.");
|
||||
return;
|
||||
}
|
||||
|
||||
std::thread fileWorker(&KaizenGui::FileWorker, kaizen);
|
||||
fileWorker.detach();
|
||||
}, this, window.getHandle(), filters, 3, nullptr, false);
|
||||
kaizen->fileToLoad = *filelist;
|
||||
kaizen->shouldDisplaySpinner = true;
|
||||
|
||||
std::thread fileWorker(&KaizenGui::FileWorker, kaizen);
|
||||
fileWorker.detach();
|
||||
},
|
||||
this, window.getHandle(), filters, 3, nullptr, false);
|
||||
}
|
||||
|
||||
if(minimized)
|
||||
if (minimized)
|
||||
return;
|
||||
|
||||
if(core.romLoaded) {
|
||||
if (core.romLoaded) {
|
||||
std::unique_lock<std::mutex> lk(emuThread.presentMutex);
|
||||
if(emuThread.readyForPresentation.wait_for(lk, 16.6667ms) == std::cv_status::no_timeout)
|
||||
if (emuThread.readyForPresentation.wait_for(lk, 16.6667ms) == std::cv_status::no_timeout)
|
||||
core.parallel.UpdateScreen<true>();
|
||||
else
|
||||
core.parallel.UpdateScreen<false>();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
core.parallel.UpdateScreen<false>();
|
||||
}
|
||||
|
||||
void KaizenGui::LoadROM(const std::string &path) noexcept {
|
||||
n64::Core& core = n64::Core::GetInstance();
|
||||
n64::Core &core = n64::Core::GetInstance();
|
||||
core.LoadROM(path);
|
||||
emuThread.create();
|
||||
const auto gameNameDB = n64::Core::GetMem().rom.gameNameDB;
|
||||
@@ -435,22 +461,23 @@ void KaizenGui::LoadROM(const std::string &path) noexcept {
|
||||
}
|
||||
|
||||
void KaizenGui::run() {
|
||||
while(!quit) {
|
||||
while (!quit) {
|
||||
SDL_Event e;
|
||||
while (SDL_PollEvent(&e)) {
|
||||
ImGui_ImplSDL3_ProcessEvent(&e);
|
||||
switch(e.type) {
|
||||
case SDL_EVENT_QUIT:
|
||||
quit = true;
|
||||
emuThread.Stop();
|
||||
break;
|
||||
case SDL_EVENT_WINDOW_MINIMIZED:
|
||||
minimized = true;
|
||||
break;
|
||||
case SDL_EVENT_WINDOW_RESTORED:
|
||||
minimized = false;
|
||||
break;
|
||||
default:
|
||||
switch (e.type) {
|
||||
case SDL_EVENT_QUIT:
|
||||
quit = true;
|
||||
emuThread.Stop();
|
||||
break;
|
||||
case SDL_EVENT_WINDOW_MINIMIZED:
|
||||
minimized = true;
|
||||
break;
|
||||
case SDL_EVENT_WINDOW_RESTORED:
|
||||
minimized = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
QueryDevices(e);
|
||||
HandleInput(e);
|
||||
@@ -461,6 +488,5 @@ void KaizenGui::run() {
|
||||
}
|
||||
}
|
||||
|
||||
void KaizenGui::LoadTAS(const std::string &path) noexcept {
|
||||
n64::Core::GetInstance().LoadTAS(fs::path(path));
|
||||
}
|
||||
void KaizenGui::LoadTAS(const std::string &path) noexcept { n64::Core::GetInstance().LoadTAS(fs::path(path)); }
|
||||
|
||||
|
||||
+33
-32
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <common.hpp>
|
||||
#include <mini/ini.h>
|
||||
#include <log.hpp>
|
||||
@@ -8,39 +7,41 @@
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
struct Options {
|
||||
Options() : file{"resources/options.ini"} {
|
||||
auto fileExists = fs::exists("resources/options.ini");
|
||||
if(fileExists) {
|
||||
file.read(structure);
|
||||
return;
|
||||
}
|
||||
|
||||
structure["general"]["savePath"] = "saves";
|
||||
fs::create_directory("saves");
|
||||
structure["audio"]["volumeL"] = "0.5";
|
||||
structure["audio"]["volumeR"] = "0.5";
|
||||
structure["audio"]["lock"] = "true";
|
||||
structure["cpu"]["type"] = "interpreter";
|
||||
|
||||
if(!file.generate(structure))
|
||||
panic("Couldn't generate settings' INI!");
|
||||
Options() : file{"resources/options.ini"} {
|
||||
auto fileExists = fs::exists("resources/options.ini");
|
||||
if (fileExists) {
|
||||
file.read(structure);
|
||||
return;
|
||||
}
|
||||
|
||||
static Options &GetInstance() {
|
||||
static Options instance;
|
||||
return instance;
|
||||
}
|
||||
structure["general"]["savePath"] = "saves";
|
||||
fs::create_directory("saves");
|
||||
structure["audio"]["volumeL"] = "0.5";
|
||||
structure["audio"]["volumeR"] = "0.5";
|
||||
structure["audio"]["lock"] = "true";
|
||||
structure["cpu"]["type"] = "interpreter";
|
||||
|
||||
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);
|
||||
if (!file.generate(structure))
|
||||
panic("Couldn't generate settings' INI!");
|
||||
}
|
||||
|
||||
static Options &GetInstance() {
|
||||
static Options instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
void Apply() {
|
||||
if (!file.write(structure))
|
||||
panic("Could not modify options on disk!");
|
||||
}
|
||||
|
||||
void Apply() {
|
||||
if(!file.write(structure))
|
||||
panic("Could not modify options on disk!");
|
||||
}
|
||||
private:
|
||||
mINI::INIFile file;
|
||||
mINI::INIStructure structure;
|
||||
};
|
||||
mINI::INIFile file;
|
||||
mINI::INIStructure structure;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user