start this from scratch

This commit is contained in:
Simone
2024-01-18 12:31:53 +01:00
parent c4f021cb9d
commit af7a6c004b
24 changed files with 116 additions and 921 deletions

View File

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

View File

@@ -1,4 +1,11 @@
file(GLOB SOURCES *.cpp)
file(GLOB HEADERS *.hpp)
add_library(core ${SOURCES} ${HEADERS})
add_subdirectory(interpreter)
add_subdirectory(mem)
add_subdirectory(mmio)
add_subdirectory(registers)
add_subdirectory(rsp)
add_library(core ${SOURCES} ${HEADERS})
target_link_libraries(core PRIVATE interpreter mem mmio unarr registers rsp)

View File

@@ -2,7 +2,7 @@
#include <log.hpp>
#include <core/Mem.hpp>
#include <core/registers/Registers.hpp>
#include <core/Audio.hpp>
#include <Audio.hpp>
namespace n64 {
void AI::Reset() {

View File

@@ -1,5 +1,5 @@
#include <PIF.hpp>
#include <MupenMovie.hpp>
#include <PIF/MupenMovie.hpp>
#include <Netplay.hpp>
#include <log.hpp>
#include <SDL2/SDL_keyboard.h>

View File

@@ -1,4 +1,4 @@
#include <MupenMovie.hpp>
#include <PIF/MupenMovie.hpp>
#include <log.hpp>
struct TASMovieHeader {

View File

@@ -2,3 +2,4 @@ file(GLOB_RECURSE SOURCES *.cpp)
file(GLOB_RECURSE HEADERS *.cpp)
add_library(registers ${SOURCES} ${HEADERS})
target_link_libraries(registers PRIVATE interpreter)

View File

@@ -1,127 +0,0 @@
#include <App.hpp>
#include <nfd.hpp>
App::App() : window(core) {
DiscordEventHandlers handlers{};
Discord_Initialize("1049669178124148806", &handlers, 1, nullptr);
Util::UpdateRPC(Util::Idling);
}
void App::Run() {
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
n64::SI& si = core.cpu->mem.mmio.si;
while (!window.done) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
ImGui_ImplSDL2_ProcessEvent(&event);
switch(event.type) {
case SDL_QUIT:
window.done = true;
break;
case SDL_WINDOWEVENT:
window.handleEvents(event, core);
break;
case SDL_CONTROLLERDEVICEADDED: {
const int index = event.cdevice.which;
si.pif.gamepad = SDL_GameControllerOpen(index);
si.pif.gamepadConnected = false;
if (!si.pif.gamepad) {
Util::warn("[WARN]: Could not initialize gamepad: {}", SDL_GetError());
} else {
si.pif.gamepadConnected = true;
}
} break;
case SDL_CONTROLLERDEVICEREMOVED:
SDL_GameControllerClose(si.pif.gamepad);
si.pif.gamepadConnected = false;
break;
case SDL_KEYDOWN:
switch (event.key.keysym.sym) {
case SDLK_o: {
OpenROMDialog(window, core);
} break;
case SDLK_F1: {
if(core.romLoaded && event.key.keysym.mod == KMOD_SHIFT) {
core.slot = 0;
}
} break;
case SDLK_F2: {
if(core.romLoaded && event.key.keysym.mod == KMOD_SHIFT) {
core.slot = 1;
}
} break;
case SDLK_F3: {
if(core.romLoaded && event.key.keysym.mod == KMOD_SHIFT) {
core.slot = 2;
}
} break;
case SDLK_F4: {
if(core.romLoaded && event.key.keysym.mod == KMOD_SHIFT) {
core.slot = 3;
}
} break;
case SDLK_F5: {
if(core.romLoaded) {
if(event.key.keysym.mod == KMOD_SHIFT) {
core.slot = 4;
} else {
core.Deserialize();
}
}
} break;
case SDLK_F6: {
if(core.romLoaded) {
if(event.key.keysym.mod == KMOD_SHIFT) {
core.slot = 5;
} else {
core.Serialize();
}
}
} break;
case SDLK_F7: {
if(core.romLoaded && event.key.keysym.mod == KMOD_SHIFT) {
core.slot = 6;
}
} break;
case SDLK_F8: {
if(core.romLoaded && event.key.keysym.mod == KMOD_SHIFT) {
core.slot = 7;
}
} break;
case SDLK_F9: {
if(core.romLoaded && event.key.keysym.mod == KMOD_SHIFT) {
core.slot = 8;
}
} break;
case SDLK_F10: {
if(core.romLoaded && event.key.keysym.mod == KMOD_SHIFT) {
core.slot = 9;
}
} break;
}
break;
case SDL_DROPFILE: {
char *droppedDir = event.drop.file;
if (droppedDir) {
window.LoadROM(core, droppedDir);
SDL_free(droppedDir);
}
} break;
}
}
if(core.romLoaded) {
if(!core.pause) {
core.Run(window.settings.GetVolumeL(), window.settings.GetVolumeR());
}
if(core.render) {
UpdateScreenParallelRdp(core, window, core.GetVI());
}
} else {
if(core.render) {
UpdateScreenParallelRdpNoGame(core, window);
}
}
}
}

View File

@@ -1,11 +0,0 @@
#pragma once
#include <imgui/Window.hpp>
#include <Discord.hpp>
struct App {
App();
~App() { Util::ClearRPC(); }
void Run();
n64::Core core;
Window window;
};

View File

@@ -1,4 +1,62 @@
file(GLOB SOURCES *.cpp)
file(GLOB HEADERS *.hpp)
cmake_minimum_required(VERSION 3.20)
project(kaizen-qt)
add_library(frontend ${SOURCES} ${HEADERS})
set(CMAKE_CXX_STANDARD 17)
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
find_package(SDL2 REQUIRED)
find_package(fmt REQUIRED)
find_package(mio REQUIRED)
find_package(nlohmann_json REQUIRED)
include_directories(
.
../
../utils
../backend
../backend/core
../backend/core/mmio
../backend/core/registers
../backend/core/rsp
../../external/
../../external/xbyak
../../external/parallel-rdp
../../external/parallel-rdp/parallel-rdp-standalone/parallel-rdp
../../external/parallel-rdp/parallel-rdp-standalone/volk
../../external/parallel-rdp/parallel-rdp-standalone/spirv-cross
../../external/parallel-rdp/parallel-rdp-standalone/vulkan
../../external/parallel-rdp/parallel-rdp-standalone/vulkan-headers/include
../../external/parallel-rdp/parallel-rdp-standalone/util
../../external/nativefiledialog-extended/src/include
../../external/imgui/imgui
../../external/imgui/imgui/backends
../../external/discord-rpc/include
../../external/unarr
${SDL2_INCLUDE_DIRS}
)
add_subdirectory(../backend backend)
add_subdirectory(../../external/discord-rpc discord-rpc)
add_subdirectory(../../external/nativefiledialog-extended nfd)
add_subdirectory(../../external/parallel-rdp parallel-rdp)
add_subdirectory(../../external/unarr unarr)
option(RAPIDJSON_BUILD_DOC "Build rapidjson documentation." OFF)
option(RAPIDJSON_BUILD_EXAMPLES "Build rapidjson examples." OFF)
option(RAPIDJSON_BUILD_TESTS "Build rapidjson perftests and unittests." OFF)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
add_executable(kaizen-qt
main.cpp)
target_link_libraries(kaizen-qt PUBLIC Qt6::Core Qt6::Gui Qt6::Widgets SDL2::SDL2 fmt::fmt mio::mio nlohmann_json::nlohmann_json
discord-rpc nfd parallel-rdp backend)
file(COPY ../../resources/ DESTINATION ${PROJECT_BINARY_DIR}/resources/)
file(REMOVE
${PROJECT_BINARY_DIR}/resources/mario.png
${PROJECT_BINARY_DIR}/resources/shader.frag
${PROJECT_BINARY_DIR}/resources/shader.vert)

View File

@@ -1,105 +0,0 @@
#pragma once
#include <log.hpp>
#include <map>
#include <array>
namespace Language {
enum StringID {
MENU_FILE,
FILE_ITEM_OPEN,
FILE_ITEM_EXIT,
MENU_EMULATION,
EMULATION_ITEM_RESET,
EMULATION_ITEM_STOP,
EMULATION_ITEM_PAUSE,
EMULATION_ITEM_RESUME,
EMULATION_ITEM_SETTINGS,
EMULATION_ITEM_LOAD_STATE,
EMULATION_ITEM_SAVE_STATE,
EMULATION_MENU_STATES,
STATES_ITEM_SLOT,
SETTINGS_CATEGORY_CPU,
SETTINGS_CATEGORY_AUDIO,
SETTINGS_CATEGORY_INTERFACE,
SETTINGS_OPTION_MUTE,
SETTINGS_OPTION_VOLUME_L,
SETTINGS_OPTION_VOLUME_R,
SETTINGS_OPTION_LOCK_CHANNELS,
SETTINGS_OPTION_ENABLE_JIT,
SETTINGS_OPTION_LANGUAGE,
SETTINGS_CLOSE,
STRING_COUNT
};
static const std::map <StringID, const char*> english = {
{MENU_FILE, "File"},
{FILE_ITEM_OPEN, "Open"},
{FILE_ITEM_EXIT, "Exit"},
{MENU_EMULATION, "Emulation"},
{EMULATION_ITEM_RESET, "Reset"},
{EMULATION_ITEM_STOP, "Stop"},
{EMULATION_ITEM_PAUSE, "Pause"},
{EMULATION_ITEM_RESUME, "Resume"},
{EMULATION_ITEM_SETTINGS, "Settings"},
{EMULATION_ITEM_LOAD_STATE, "Load state..."},
{EMULATION_ITEM_SAVE_STATE, "Save state..."},
{EMULATION_MENU_STATES, "Select save slot"},
{STATES_ITEM_SLOT, "Slot {}"},
{SETTINGS_CATEGORY_CPU, "CPU"},
{SETTINGS_CATEGORY_AUDIO, "Audio"},
{SETTINGS_CATEGORY_INTERFACE, "Interface"},
{SETTINGS_OPTION_MUTE, "Mute"},
{SETTINGS_OPTION_VOLUME_L, "Volume L"},
{SETTINGS_OPTION_VOLUME_R, "Volume R"},
{SETTINGS_OPTION_LOCK_CHANNELS, "Lock channels"},
{SETTINGS_OPTION_ENABLE_JIT, "Enable JIT"},
{SETTINGS_OPTION_LANGUAGE, "Language"},
{SETTINGS_CLOSE, "Close"}
};
static const std::map <StringID, const char*> italian = {
{MENU_FILE, "File"},
{FILE_ITEM_OPEN, "Apri"},
{FILE_ITEM_EXIT, "Esci"},
{MENU_EMULATION, "Emulazione"},
{EMULATION_ITEM_RESET, "Reset"},
{EMULATION_ITEM_STOP, "Stop"},
{EMULATION_ITEM_PAUSE, "Pausa"},
{EMULATION_ITEM_RESUME, "Riprendi"},
{EMULATION_ITEM_SETTINGS, "Opzioni"},
{EMULATION_ITEM_LOAD_STATE, "Carica stato..."},
{EMULATION_ITEM_SAVE_STATE, "Salva stato..."},
{EMULATION_MENU_STATES, "Seleziona slot"},
{STATES_ITEM_SLOT, "Slot {}"},
{SETTINGS_CATEGORY_CPU, "CPU"},
{SETTINGS_CATEGORY_AUDIO, "Audio"},
{SETTINGS_CATEGORY_INTERFACE, "Interfaccia"},
{SETTINGS_OPTION_MUTE, "Muta"},
{SETTINGS_OPTION_VOLUME_L, "Volume L"},
{SETTINGS_OPTION_VOLUME_R, "Volume R"},
{SETTINGS_OPTION_LOCK_CHANNELS, "Blocca canali"},
{SETTINGS_OPTION_ENABLE_JIT, "Abilita JIT"},
{SETTINGS_OPTION_LANGUAGE, "Lingua"},
{SETTINGS_CLOSE, "Chiudi"}
};
enum AvailableLangs {
ENGLISH,
ITALIAN,
AVAILABLE_LANGS_COUNT
};
static const std::array<const char*, AVAILABLE_LANGS_COUNT> languages = {
"English",
"Italiano"
};
static FORCE_INLINE void SetLanguage(std::map<StringID, const char*>& lang, int selectedLang) {
switch (selectedLang) {
case AvailableLangs::ENGLISH: lang = english; break;
case AvailableLangs::ITALIAN: lang = italian; break;
default: Util::panic("Language not supported, index {}\n", selectedLang);
}
}
}

View File

@@ -1,8 +0,0 @@
file(GLOB SOURCES *.cpp)
file(GLOB HEADERS *.hpp)
if(WIN32)
add_compile_definitions(SDL_MAIN_HANDLED)
endif()
add_library(frontend-imgui ${SOURCES} ${HEADERS})

View File

@@ -1,183 +0,0 @@
#include <Settings.hpp>
#include <fstream>
#include <filesystem>
#include <Widgets.hpp>
#include <Core.hpp>
namespace fs = std::filesystem;
#define GET_TRANSLATED_STRING(x) languageStrings[(x)]
#define checknestedjsonentry(name, type, param1, param2, defaultVal) \
do { \
auto name##Entry = settings[param1][param2]; \
if(!name##Entry.empty()) { \
auto value = name##Entry.get<type>(); \
(name) = value; \
} else { \
settingsFile.clear(); \
settings[param1][param2] = defaultVal; \
settingsFile << settings; \
(name) = defaultVal; \
} \
} while(0)
#define checkjsonentry(name, type, param, defaultVal) \
do { \
auto name##Entry = settings[param]; \
if(!name##Entry.empty()) { \
auto value = name##Entry.get<type>(); \
(name) = value; \
} else { \
settingsFile.clear(); \
settings[param] = defaultVal; \
settingsFile << settings; \
(name) = defaultVal; \
} \
} while(0)
Settings::Settings(n64::Core& core) {
auto fileExists = fs::exists("resources/settings.json");
std::fstream settingsFile;
if(fileExists) {
settingsFile = std::fstream("resources/settings.json", std::fstream::in | std::fstream::out);
settings = json::parse(settingsFile);
checknestedjsonentry(oldVolumeL, float, "audio", "volumeL", 0.5);
checknestedjsonentry(oldVolumeR, float, "audio", "volumeR", 0.5);
checknestedjsonentry(mute, bool, "audio", "mute", false);
volumeL = mute ? 0 : oldVolumeL;
volumeR = mute ? 0 : oldVolumeR;
checknestedjsonentry(lockChannels, bool, "audio", "lockChannels", true);
checknestedjsonentry(jit, bool, "cpu", "enableJIT", false);
checkjsonentry(selectedLanguage, int, "language", Language::ENGLISH);
} else {
settingsFile = std::fstream("resources/settings.json", std::fstream::trunc | std::fstream::in | std::fstream::out);
settings["audio"]["volumeR"] = 0.5;
settings["audio"]["volumeL"] = 0.5;
settings["audio"]["lockChannels"] = true;
settings["audio"]["mute"] = false;
settings["cpu"]["enableJIT"] = false;
settings["language"] = Language::ENGLISH;
oldVolumeR = volumeR = 0.5;
oldVolumeL = volumeL = 0.5;
lockChannels = true;
mute = false;
jit = false;
settingsFile << settings;
}
Language::SetLanguage(languageStrings, selectedLanguage);
if(jit) {
core.cpu = std::make_unique<n64::JIT>();
} else {
core.cpu = std::make_unique<n64::Interpreter>();
}
settingsFile.close();
}
Settings::~Settings() {
auto fileExists = fs::exists("resources/settings.json");
std::fstream settingsFile;
if(fileExists) {
settingsFile = std::fstream("resources/settings.json", std::fstream::trunc | std::fstream::out);
} else {
settingsFile = std::fstream("resources/settings.json", std::fstream::out);
}
settings["audio"]["volumeR"] = oldVolumeR;
settings["audio"]["volumeL"] = oldVolumeL;
settings["audio"]["lockChannels"] = lockChannels;
settings["audio"]["mute"] = mute;
settings["cpu"]["enableJIT"] = jit;
settings["language"] = selectedLanguage;
settingsFile << settings;
settingsFile.close();
}
void Settings::RenderWidget(const int& mWw, const int& mWh, bool& show) {
if(show) {
ImGui::OpenPopup("##settings");
const float posX = (float)mWw * (1.f / 32.f), posY = (float)mWh * (1.f / 32.f) + 20;
const float sizeX = (float)mWw * (30.f / 32.f), sizeY = (float)mWh * (30.f / 32.f) - 20;
ImGui::SetNextWindowPos({ posX, posY });
ImGui::SetNextWindowSize({ sizeX, sizeY });
if(ImGui::BeginPopupModal("##settings", &show, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove)) {
if (ImGui::BeginTabBar("##categories")) {
if (ImGui::BeginTabItem(GET_TRANSLATED_STRING(Language::SETTINGS_CATEGORY_CPU))) {
ImGui::Checkbox(GET_TRANSLATED_STRING(Language::SETTINGS_OPTION_ENABLE_JIT), &jit);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem(GET_TRANSLATED_STRING(Language::SETTINGS_CATEGORY_AUDIO))) {
ImGui::Checkbox(GET_TRANSLATED_STRING(Language::SETTINGS_OPTION_LOCK_CHANNELS), &lockChannels);
ImGui::Checkbox(GET_TRANSLATED_STRING(Language::SETTINGS_OPTION_MUTE), &mute);
if (mute) {
volumeL = 0;
volumeR = 0;
ImGui::BeginDisabled();
ImGui::SliderFloat(GET_TRANSLATED_STRING(Language::SETTINGS_OPTION_VOLUME_L), &oldVolumeL, 0, 1, "%.2f", ImGuiSliderFlags_NoInput);
if (lockChannels) {
oldVolumeR = oldVolumeL;
}
ImGui::SliderFloat(GET_TRANSLATED_STRING(Language::SETTINGS_OPTION_VOLUME_R), &oldVolumeR, 0, 1, "%.2f", ImGuiSliderFlags_NoInput);
ImGui::EndDisabled();
}
else {
volumeL = oldVolumeL;
volumeR = oldVolumeR;
ImGui::SliderFloat(GET_TRANSLATED_STRING(Language::SETTINGS_OPTION_VOLUME_L), &volumeL, 0, 1, "%.2f", ImGuiSliderFlags_NoInput);
if (!lockChannels) {
ImGui::SliderFloat(GET_TRANSLATED_STRING(Language::SETTINGS_OPTION_VOLUME_R), &volumeR, 0, 1, "%.2f", ImGuiSliderFlags_NoInput);
}
else {
volumeR = volumeL;
ImGui::BeginDisabled();
ImGui::SliderFloat(GET_TRANSLATED_STRING(Language::SETTINGS_OPTION_VOLUME_R), &volumeR, 0, 1, "%.2f", ImGuiSliderFlags_NoInput);
ImGui::EndDisabled();
}
oldVolumeL = volumeL;
oldVolumeR = volumeR;
}
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem(GET_TRANSLATED_STRING(Language::SETTINGS_CATEGORY_INTERFACE))) {
static auto currentLang = selectedLanguage;
const char* languages[Language::AVAILABLE_LANGS_COUNT] = {
Language::languages[Language::ENGLISH],
Language::languages[Language::ITALIAN]
};
ImGui::Text("%s:", GET_TRANSLATED_STRING(Language::SETTINGS_OPTION_LANGUAGE));
CreateComboList("##language", (int*)&selectedLanguage, languages, (int)Language::AVAILABLE_LANGS_COUNT);
ImGui::Separator();
if (currentLang != selectedLanguage) {
currentLang = selectedLanguage;
Language::SetLanguage(languageStrings, selectedLanguage);
}
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
const auto style = ImGui::GetStyle();
ImGui::SetCursorPos({
ImGui::GetWindowWidth() - ImGui::CalcTextSize(GET_TRANSLATED_STRING(Language::SETTINGS_CLOSE)).x - style.FramePadding.x * 5,
ImGui::GetWindowHeight() - ImGui::CalcTextSize(GET_TRANSLATED_STRING(Language::SETTINGS_CLOSE)).y - style.FramePadding.y * 5,
});
if (ImGui::Button(GET_TRANSLATED_STRING(Language::SETTINGS_CLOSE))) show = false;
ImGui::EndPopup();
}
}
}

View File

@@ -1,25 +0,0 @@
#pragma once
#include <nlohmann/json.hpp>
#include <Language.hpp>
namespace n64 { struct Core; }
using namespace nlohmann;
struct Settings {
explicit Settings(n64::Core& core);
~Settings();
[[nodiscard]] FORCE_INLINE float GetVolumeL() const { return volumeL; };
[[nodiscard]] FORCE_INLINE float GetVolumeR() const { return volumeR; };
void RenderWidget(const int& mWw, const int& mWh, bool& show);
std::map<Language::StringID, const char*> languageStrings{};
private:
bool jit = false;
float volumeL, volumeR;
float oldVolumeL, oldVolumeR;
bool lockChannels = true;
bool mute = false;
int selectedLanguage = Language::ENGLISH;
json settings;
};

View File

@@ -1,21 +0,0 @@
#pragma once
#include <imgui.h>
FORCE_INLINE bool CreateComboList(const char* label, int* index, const char** items, int items_count) {
if (ImGui::BeginCombo(label, items[*index])) {
for (int n = 0; n < items_count; n++) {
const bool is_selected = (*index == n);
if (ImGui::Selectable(items[n], is_selected)) {
*index = n;
}
if (is_selected) {
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
return true;
}
return false;
}

View File

@@ -1,274 +0,0 @@
#include <filesystem>
#include <Window.hpp>
#include <Core.hpp>
#include <Audio.hpp>
#include <SDL2/SDL.h>
#include <Discord.hpp>
VkInstance instance{};
namespace fs = std::filesystem;
#define GET_TRANSLATED_STRING(x) settings.languageStrings[(x)]
Window::Window(n64::Core& core) : settings(core) {
InitSDL();
InitParallelRDP(core.cpu->mem.GetRDRAM(), window);
InitImgui();
NFD::Init();
}
void Window::handleEvents(SDL_Event event, n64::Core& core) {
done = event.window.event == (u8)SDL_WINDOWEVENT_CLOSE
&& event.window.windowID == SDL_GetWindowID(window);
bool minimized = SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED;
core.pause = event.window.event == (u8)SDL_WINDOWEVENT_FOCUS_LOST || minimized;
core.render = !minimized;
}
static void check_vk_result(VkResult err) {
if (err != VK_SUCCESS) {
Util::panic("[vulkan] Error: VkResult = {}", static_cast<int>(err));
}
}
void Window::InitSDL() {
SDL_Init(SDL_INIT_EVERYTHING);
n64::InitAudio();
windowTitle = "Kaizen";
window = SDL_CreateWindow(
"Kaizen",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
1024, 768,
SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI
);
if(!window) {
Util::panic("Could not create SDL window: {}", SDL_GetError());
}
check_vk_result(volkInitialize());
}
void Window::InitImgui() {
VkResult err;
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
(void)io;
// Setup Dear ImGui style
ImGui::StyleColorsDark();
instance = GetVkInstance();
physicalDevice = GetVkPhysicalDevice();
device = GetVkDevice();
queueFamily = GetVkGraphicsQueueFamily();
queue = GetGraphicsQueue();
pipelineCache = nullptr;
descriptorPool = nullptr;
allocator = nullptr;
minImageCount = 2;
ImGui_ImplVulkan_LoadFunctions([](const char* function_name, void*) { return vkGetInstanceProcAddr(instance, function_name); });
{
VkDescriptorPoolSize poolSizes[] = {
{ VK_DESCRIPTOR_TYPE_SAMPLER, 1000 },
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000 },
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000 },
{ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000 },
{ VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000 },
{ VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000 },
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000 },
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000 },
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000 },
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000 },
{ VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000 }
};
VkDescriptorPoolCreateInfo poolInfo{};
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
poolInfo.maxSets = 1000 * IM_ARRAYSIZE(poolSizes);
poolInfo.poolSizeCount = (uint32_t)IM_ARRAYSIZE(poolSizes);
poolInfo.pPoolSizes = poolSizes;
err = vkCreateDescriptorPool(device, &poolInfo, allocator, &descriptorPool);
check_vk_result(err);
}
// Setup Platform/Renderer backends
ImGui_ImplSDL2_InitForVulkan(window);
ImGui_ImplVulkan_InitInfo initInfo = {};
initInfo.Instance = instance;
initInfo.PhysicalDevice = physicalDevice;
initInfo.Device = device;
initInfo.QueueFamily = queueFamily;
initInfo.Queue = queue;
initInfo.PipelineCache = pipelineCache;
initInfo.DescriptorPool = descriptorPool;
initInfo.Allocator = allocator;
initInfo.MinImageCount = minImageCount;
initInfo.ImageCount = 2;
initInfo.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
initInfo.CheckVkResultFn = check_vk_result;
ImGui_ImplVulkan_Init(&initInfo, GetVkRenderPass());
int displayIndex = SDL_GetWindowDisplayIndex(window);
float ddpi, hdpi, vdpi;
SDL_GetDisplayDPI(displayIndex, &ddpi, &hdpi, &vdpi);
ddpi /= 96.f;
uiFont = io.Fonts->AddFontFromFileTTF("resources/OpenSans.ttf", 16.f * ddpi);
ImGui::GetStyle().ScaleAllSizes(ddpi);
{
VkCommandBuffer commandBuffer = GetVkCommandBuffer();
ImGui_ImplVulkan_CreateFontsTexture(commandBuffer);
SubmitRequestedVkCommandBuffer();
}
}
Window::~Window() {
auto err = vkDeviceWaitIdle(device);
check_vk_result(err);
ImGui_ImplVulkan_Shutdown();
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
SDL_DestroyWindow(window);
SDL_DestroyWindow(g_Window);
SDL_Quit();
}
ImDrawData* Window::Present(n64::Core& core) {
ImGui_ImplVulkan_NewFrame();
ImGui_ImplSDL2_NewFrame(window);
ImGui::NewFrame();
Render(core);
ImGui::Render();
return ImGui::GetDrawData();
}
void Window::LoadROM(n64::Core& core, const std::string &path) {
if(!path.empty()) {
core.LoadROM(path);
gameName = core.cpu->mem.rom.gameNameDB;
if(gameName.empty()) {
gameName = fs::path(path).stem().string();
}
Util::UpdateRPC(Util::Playing, gameName);
windowTitle = "Kaizen - " + gameName;
shadowWindowTitle = windowTitle;
SDL_SetWindowTitle(window, windowTitle.c_str());
}
}
void Window::RenderMainMenuBar(n64::Core &core) {
ImGui::BeginMainMenuBar();
if (ImGui::BeginMenu(GET_TRANSLATED_STRING(Language::MENU_FILE))) {
if (ImGui::MenuItem(GET_TRANSLATED_STRING(Language::FILE_ITEM_OPEN), "O")) {
OpenROMDialog(*this, core);
}
if (ImGui::MenuItem("Dump RDRAM")) {
core.cpu->mem.DumpRDRAM();
}
if (ImGui::MenuItem("Dump IMEM")) {
core.cpu->mem.DumpIMEM();
}
if (ImGui::MenuItem("Dump DMEM")) {
core.cpu->mem.DumpDMEM();
}
if (ImGui::MenuItem(GET_TRANSLATED_STRING(Language::FILE_ITEM_EXIT))) {
done = true;
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu(GET_TRANSLATED_STRING(Language::MENU_EMULATION))) {
if (ImGui::MenuItem(GET_TRANSLATED_STRING(Language::EMULATION_ITEM_RESET))) {
LoadROM(core, core.rom);
}
if (ImGui::MenuItem(GET_TRANSLATED_STRING(Language::EMULATION_ITEM_STOP))) {
windowTitle = "Kaizen";
core.rom.clear();
Util::UpdateRPC(Util::Idling);
SDL_SetWindowTitle(window, windowTitle.c_str());
core.Stop();
}
if (ImGui::MenuItem(core.pause ? GET_TRANSLATED_STRING(Language::EMULATION_ITEM_RESUME)
: GET_TRANSLATED_STRING(Language::EMULATION_ITEM_PAUSE), nullptr, false, core.romLoaded)) {
core.TogglePause();
if(core.pause) {
shadowWindowTitle = windowTitle;
windowTitle += " | Paused";
Util::UpdateRPC(Util::Paused, gameName);
} else {
windowTitle = shadowWindowTitle;
Util::UpdateRPC(Util::Playing, gameName);
}
SDL_SetWindowTitle(window, windowTitle.c_str());
}
if(ImGui::BeginMenu(GET_TRANSLATED_STRING(Language::EMULATION_MENU_STATES))) {
if(ImGui::MenuItem(fmt::format(GET_TRANSLATED_STRING(Language::STATES_ITEM_SLOT), 0).c_str())) { core.slot = 0; }
if(ImGui::MenuItem(fmt::format(GET_TRANSLATED_STRING(Language::STATES_ITEM_SLOT), 1).c_str())) { core.slot = 1; }
if(ImGui::MenuItem(fmt::format(GET_TRANSLATED_STRING(Language::STATES_ITEM_SLOT), 2).c_str())) { core.slot = 2; }
if(ImGui::MenuItem(fmt::format(GET_TRANSLATED_STRING(Language::STATES_ITEM_SLOT), 3).c_str())) { core.slot = 3; }
if(ImGui::MenuItem(fmt::format(GET_TRANSLATED_STRING(Language::STATES_ITEM_SLOT), 4).c_str())) { core.slot = 4; }
if(ImGui::MenuItem(fmt::format(GET_TRANSLATED_STRING(Language::STATES_ITEM_SLOT), 5).c_str())) { core.slot = 5; }
if(ImGui::MenuItem(fmt::format(GET_TRANSLATED_STRING(Language::STATES_ITEM_SLOT), 6).c_str())) { core.slot = 6; }
if(ImGui::MenuItem(fmt::format(GET_TRANSLATED_STRING(Language::STATES_ITEM_SLOT), 7).c_str())) { core.slot = 7; }
if(ImGui::MenuItem(fmt::format(GET_TRANSLATED_STRING(Language::STATES_ITEM_SLOT), 8).c_str())) { core.slot = 8; }
if(ImGui::MenuItem(fmt::format(GET_TRANSLATED_STRING(Language::STATES_ITEM_SLOT), 9).c_str())) { core.slot = 9; }
ImGui::EndMenu();
}
if(ImGui::MenuItem(GET_TRANSLATED_STRING(Language::EMULATION_ITEM_LOAD_STATE), "F5", false, core.romLoaded)) {
core.Deserialize();
}
if(ImGui::MenuItem(GET_TRANSLATED_STRING(Language::EMULATION_ITEM_SAVE_STATE), "F6", false, core.romLoaded)) {
core.Serialize();
}
if (ImGui::MenuItem(GET_TRANSLATED_STRING(Language::EMULATION_ITEM_SETTINGS))) {
showSettings = true;
}
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
}
void Window::Render(n64::Core& core) {
ImGui::PushFont(uiFont);
u32 ticks = SDL_GetTicks();
static u32 lastFrame = 0;
if(!core.pause && core.romLoaded && lastFrame < ticks - 1000) {
lastFrame = ticks;
windowTitle += fmt::format(" | {:02d} VI/s", core.cpu->mem.mmio.vi.swaps);
core.cpu->mem.mmio.vi.swaps = 0;
SDL_SetWindowTitle(window, windowTitle.c_str());
windowTitle = shadowWindowTitle;
}
if(SDL_GetMouseFocus()) {
RenderMainMenuBar(core);
}
int w, h;
SDL_GetWindowSize(window, &w, &h);
settings.RenderWidget(w, h, showSettings);
ImGui::PopFont();
}

View File

@@ -1,52 +0,0 @@
#pragma once
#include <ParallelRDPWrapper.hpp>
#include <imgui.h>
#include <imgui_impl_sdl2.h>
#include <imgui_impl_vulkan.h>
#include <SDL2/SDL.h>
#include <vector>
#include <frontend/imgui/Settings.hpp>
#include <nfd.hpp>
#include "Discord.hpp"
struct Window {
explicit Window(n64::Core& core);
~Window();
ImDrawData* Present(n64::Core& core);
void handleEvents(SDL_Event event, n64::Core&);
ImFont *uiFont{};
Settings settings;
void LoadROM(n64::Core& core, const std::string& path);
bool done = false;
std::string gameName{};
private:
bool showSettings = false;
SDL_Window* window{};
std::string windowTitle{"Kaizen"};
std::string shadowWindowTitle{windowTitle};
void InitSDL();
void InitImgui();
void Render(n64::Core& core);
void RenderMainMenuBar(n64::Core& core);
VkPhysicalDevice physicalDevice{};
VkDevice device{};
uint32_t queueFamily{uint32_t(-1)};
VkQueue queue{};
VkPipelineCache pipelineCache{};
VkDescriptorPool descriptorPool{};
VkAllocationCallbacks* allocator{};
u32 minImageCount = 2;
};
static void FORCE_INLINE OpenROMDialog(Window& window, n64::Core& core) {
nfdchar_t *outpath;
const nfdu8filteritem_t filter{"Nintendo 64 roms/archives", "n64,z64,v64,N64,Z64,V64,zip,tar,rar,7z"};
nfdresult_t result = NFD_OpenDialog(&outpath, &filter, 1, nullptr);
if (result == NFD_OKAY) {
window.LoadROM(core, outpath);
NFD_FreePath(outpath);
}
}

16
src/frontend/main.cpp Normal file
View File

@@ -0,0 +1,16 @@
#include <QApplication>
#include <QCommandLineParser>
#include <QCommandLineOption>
int main(int argc, char** argv) {
QApplication app(argc, argv);
app.setStyle("fusion");
QCoreApplication::setOrganizationName("kaizen");
QCoreApplication::setApplicationName("Kaizen");
QCommandLineParser parser;
parser.setApplicationDescription(QCoreApplication::applicationName());
parser.addHelpOption();
parser.addPositionalArgument("rom", "Rom to launch from command-line");
parser.process(app);
return app.exec();
}