diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fdee724..c169ad0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,13 +1,15 @@ add_executable(${PROJECT_NAME}) + +file(GLOB CHIP8_SOURCES "*.cpp" "**/*.cpp") +file(GLOB CHIP8_HEADERS "*.h" "**/*.h") +message(CHIP8_SOURCES="${CHIP8_SOURCES}") +message(CHIP8_HEADERS="${CHIP8_HEADERS}") + target_sources( ${PROJECT_NAME} PRIVATE - main.cpp - Machine.h Machine.cpp - Interpreter/Interpreter.h Interpreter/Interpreter.cpp - Graphics/Graphics.h Graphics/Graphics.cpp - UI/UIManager.h UI/UIManager.cpp - UI/Display.h UI/Display.cpp - UI/ControlPanel.h UI/ControlPanel.cpp + ${CHIP8_SOURCES} + ${CHIP8_HEADERS} ) + target_link_libraries(${PROJECT_NAME} PRIVATE vendor) \ No newline at end of file diff --git a/src/Graphics/Graphics.cpp b/src/Graphics/Graphics.cpp index 37d8d92..87eb942 100644 --- a/src/Graphics/Graphics.cpp +++ b/src/Graphics/Graphics.cpp @@ -8,10 +8,6 @@ #include "imgui_impl_sdl3.h" #include "imgui_impl_sdlrenderer3.h" -void SDLWindowDestroyer::operator()(SDL_Window* window) const { - SDL_DestroyWindow(window); -} - Graphics::Graphics(): window_width{1366}, window_height{768}, main_scale{1.0f} { create_sdl(); create_imgui(); @@ -41,7 +37,7 @@ void Graphics::create_sdl() { throw std::runtime_error(std::format("Couldn't create window/renderer: {}", SDL_GetError())); } - this->window = std::unique_ptr(raw_window); + this->window = std::shared_ptr(raw_window, SDL_DestroyWindow); this->renderer = std::shared_ptr(raw_renderer, SDL_DestroyRenderer); SDL_SetRenderVSync(this->renderer.get(), 1); @@ -69,6 +65,9 @@ void Graphics::create_imgui() const { std::shared_ptr Graphics::get_renderer() { return this->renderer; } +std::shared_ptr Graphics::get_window() { + return this->window; +} void Graphics::start() const { ImGui_ImplSDLRenderer3_NewFrame(); diff --git a/src/Graphics/Graphics.h b/src/Graphics/Graphics.h index ce2cba8..480acec 100644 --- a/src/Graphics/Graphics.h +++ b/src/Graphics/Graphics.h @@ -13,7 +13,7 @@ class Graphics { int window_height; float main_scale; - std::unique_ptr window; + std::shared_ptr window; std::shared_ptr renderer; void create_sdl(); @@ -24,6 +24,7 @@ public: void start() const; void end() const; std::shared_ptr get_renderer(); + std::shared_ptr get_window(); }; #endif //GRAPHICS_H diff --git a/src/Interpreter/MachineState.cpp b/src/Interpreter/MachineState.cpp new file mode 100644 index 0000000..426e47b --- /dev/null +++ b/src/Interpreter/MachineState.cpp @@ -0,0 +1,27 @@ +#include "MachineState.h" + +MachineState::MachineState(): + memory{}, + v{}, + stack{}, + display{}, + keyboard{0}, + pc{0x200}, + sp{0}, + i{0}, + dt{0}, + st{0} +{} + +void MachineState::reset() { + this->memory.fill(0); + this->v.fill(0); + this->stack.fill(0); + this->display.fill(false); + this->keyboard = 0; + this->pc = 0x200; + this->sp = 0; + this->i = 0; + this->dt = 0; + this->st = 0; +} diff --git a/src/Interpreter/MachineState.h b/src/Interpreter/MachineState.h index 1aeebce..90433de 100644 --- a/src/Interpreter/MachineState.h +++ b/src/Interpreter/MachineState.h @@ -4,16 +4,20 @@ #include struct MachineState { - std::array memory{}; - std::array v{}; - std::array stack{}; - std::array display{}; - uint16_t keyboard = 0; - uint16_t pc = 0x200; - uint8_t sp = 0; - uint16_t i = 0; - uint8_t dt = 0; - uint8_t st = 0; + std::array memory; + std::array v; + std::array stack; + std::array display; + uint16_t keyboard; + uint16_t pc; + uint8_t sp; + uint16_t i; + uint8_t dt; + uint8_t st; + + MachineState(); + + void reset(); }; #endif //MACHINESTATE_H diff --git a/src/Machine.cpp b/src/Machine.cpp index 96a4fd8..037d509 100644 --- a/src/Machine.cpp +++ b/src/Machine.cpp @@ -1,5 +1,8 @@ #include "Machine.h" +#include +#include + #include "Graphics/Graphics.h" #include "Interpreter/Interpreter.h" #include "SDL3/SDL.h" @@ -18,7 +21,20 @@ Machine::Machine(): ips{700}, last_update_time{0}, accumulator{0}, - target_cycle_time{1.0 / this->ips} {} + target_cycle_time{1.0 / this->ips} { + + ui_manager->control_panel->set_rom_load_callback(std::bind( + &Machine::on_rom_load, + this, + std::placeholders::_1 + )); + + ui_manager->control_panel->set_reset_callback(std::bind( + &Machine::on_reset, + this + )); +} + void Machine::iterate() { this->execute_interpreter(); @@ -49,3 +65,10 @@ void Machine::execute_interpreter() { this->accumulator -= this->target_cycle_time; } } + +void Machine::on_rom_load(const std::string& path) const { + std::cout << path << std::endl; +} +void Machine::on_reset() const { + this->machine_state->reset(); +} diff --git a/src/Machine.h b/src/Machine.h index e48bc79..86edcea 100644 --- a/src/Machine.h +++ b/src/Machine.h @@ -19,7 +19,9 @@ class Machine { double accumulator; double target_cycle_time; -void execute_interpreter(); + void execute_interpreter(); + void on_rom_load(const std::string& path) const; + void on_reset() const; public: Machine(); diff --git a/src/UI/ControlPanel.cpp b/src/UI/ControlPanel.cpp index c0f9d56..14bb9ed 100644 --- a/src/UI/ControlPanel.cpp +++ b/src/UI/ControlPanel.cpp @@ -3,17 +3,29 @@ #include #include "imgui.h" + ControlPanel::ControlPanel( std::shared_ptr graphics, std::shared_ptr machine_state ): graphics{std::move(graphics)}, machine_state{std::move(machine_state)} {} +void ControlPanel::set_rom_load_callback(const std::function& callback) { + this->rom_load_callback = callback; +} + +void ControlPanel::set_reset_callback(const std::function& callback) { + this->reset_callback = callback; +} + void ControlPanel::render() { constexpr auto full_width = ImVec2(-FLT_MIN, 0.0f); if (ImGui::Begin("Chip-8 - Controls")) { - ImGui::Button("Load Rom", full_width); + if (ImGui::Button("Load Rom", full_width)) { + this->on_click_load_rom(); + } + if (ImGui::Button(run ? "Pause" : "Run", full_width)) { this->run = !run; } @@ -37,10 +49,36 @@ void ControlPanel::render() { ImGui::SeparatorText(""); - ImGui::Button("Reset", full_width); + if (ImGui::Button("Reset", full_width)) { + if (this->reset_callback) { + this->reset_callback(); + } + } ImGui::Button("Reload ROM", full_width); } - ImGui::End(); } + +void ControlPanel::on_click_load_rom() { + constexpr SDL_DialogFileFilter filters[] = { + {"CHIP8 ROMs", "ch8"}, + {"All files", "*"} + }; + + SDL_ShowOpenFileDialog(on_callback_load_rom, this, graphics->get_window().get(), filters, std::size(filters), nullptr, false); +} + +void ControlPanel::on_callback_load_rom(void* userdata, const char* const* filelist, int filter) { + const auto control_panel = static_cast(userdata); + + if (!control_panel->rom_load_callback) { + return; + } + + if (!filelist || !*filelist) { + return; + } + + control_panel->rom_load_callback(*filelist); +} diff --git a/src/UI/ControlPanel.h b/src/UI/ControlPanel.h index 3c1273a..d9115fd 100644 --- a/src/UI/ControlPanel.h +++ b/src/UI/ControlPanel.h @@ -1,5 +1,6 @@ #ifndef CONTROLPANEL_H #define CONTROLPANEL_H +#include #include #include "../Graphics/Graphics.h" @@ -13,13 +14,23 @@ class ControlPanel { bool run = false; int steps = 1; int speed = 100; + + std::function rom_load_callback; + std::function reset_callback; + + static SDLCALL void on_callback_load_rom(void* userdata, const char* const* filelist, int filter); + public: ControlPanel( std::shared_ptr graphics, std::shared_ptr machine_state ); - void render() ; + void set_rom_load_callback(const std::function& callback); + void set_reset_callback(const std::function& callback); + + void render(); + void on_click_load_rom(); }; diff --git a/src/UI/UIManager.h b/src/UI/UIManager.h index 12d28b7..4e97d3b 100644 --- a/src/UI/UIManager.h +++ b/src/UI/UIManager.h @@ -9,7 +9,7 @@ class UIManager { std::shared_ptr graphics; std::shared_ptr machine_state; - +public: std::unique_ptr display; std::unique_ptr control_panel;