From e11ff24ac718626dec8e6acf79f3c71129370347 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 22 Jun 2025 01:51:51 -0400 Subject: [PATCH] Usando un widget de imgui para renderizar el display de chip-8 --- src/Chip8.cpp | 2 +- src/Graphics.cpp | 109 +++++++++++++++++++++++++++++++++++++++-------- src/Graphics.h | 24 ++++++++--- src/main.cpp | 5 +++ 4 files changed, 115 insertions(+), 25 deletions(-) diff --git a/src/Chip8.cpp b/src/Chip8.cpp index ff2a68d..4f19492 100644 --- a/src/Chip8.cpp +++ b/src/Chip8.cpp @@ -13,7 +13,7 @@ Chip8::Chip8(): machine_state{std::make_shared()}, target_cycle_time{1.0 / 700.0}, last_update_time{0}, accumulator{0}, - run{false}, + run{true}, step{false} {} bool Chip8::init() { diff --git a/src/Graphics.cpp b/src/Graphics.cpp index 10fb299..1ecdf21 100644 --- a/src/Graphics.cpp +++ b/src/Graphics.cpp @@ -7,6 +7,10 @@ #include #include +#include "imgui.h" +#include "imgui_impl_sdl3.h" +#include "imgui_impl_sdlrenderer3.h" + void SDLWindowDestroyer::operator()(SDL_Window* window) const { std::cout << "Destroying window" << std::endl; SDL_DestroyWindow(window); @@ -23,12 +27,13 @@ void SDLTextureDestroyer::operator()(SDL_Texture* texture) const { } Graphics::Graphics(std::shared_ptr machine_state): machine_state{std::move(machine_state)}, - width{64 * 30}, - height{32 * 30}, - scale{30} {} + window_width{1920}, + window_height{1080}, + chip8_width(64), + chip8_height(32), + main_scale(1.0f) {} - -bool Graphics::init() { +bool Graphics::init_sdl() { SDL_SetAppMetadata("CHIP-8 Emulator", "0.0.1", "fun.skrd.chip8"); if (!SDL_Init(SDL_INIT_VIDEO)) { @@ -38,7 +43,11 @@ bool Graphics::init() { SDL_Window* raw_window = nullptr; SDL_Renderer* raw_renderer = nullptr; - if (!SDL_CreateWindowAndRenderer("CHIP-8 Emulator", width, height, 0, &raw_window, &raw_renderer)) { + + main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()); + SDL_WindowFlags window_flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY; + + if (!SDL_CreateWindowAndRenderer("CHIP-8 Emulator", window_width * main_scale, window_height * main_scale, window_flags, &raw_window, &raw_renderer)) { SDL_Log("Couldn't create window/renderer: %s", SDL_GetError()); return false; } @@ -46,22 +55,74 @@ bool Graphics::init() { this->window = std::unique_ptr(raw_window); this->renderer = std::unique_ptr(raw_renderer); - SDL_Texture* raw_texture = SDL_CreateTexture(renderer.get(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, 64 * scale, 32 * scale); + SDL_SetRenderVSync(renderer.get(), 1); + SDL_SetWindowPosition(window.get(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); + SDL_ShowWindow(window.get()); + + SDL_Texture* raw_texture = SDL_CreateTexture(renderer.get(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, chip8_width, chip8_height); this->texture = std::unique_ptr(raw_texture); + SDL_SetTextureScaleMode(texture.get(), SDL_SCALEMODE_NEAREST); + + return true; +} + +bool Graphics::init_imgui() { + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + + ImGuiIO& io = ImGui::GetIO(); + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; + + ImGui::StyleColorsDark(); + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); + style.FontScaleDpi = main_scale; + + ImGui_ImplSDL3_InitForSDLRenderer(window.get(), renderer.get()); + ImGui_ImplSDLRenderer3_Init(renderer.get()); + + return true; +} + + +bool Graphics::init() { + if (!init_sdl()) { + return false; + } + + if (!init_imgui()) { + return false; + } return true; } void Graphics::draw() { - SDL_SetRenderDrawColor(renderer.get(), 0, 0, 0, SDL_ALPHA_OPAQUE); + if (SDL_GetWindowFlags(window.get()) & SDL_WINDOW_MINIMIZED) { + SDL_Delay(10); + } + + build_chip8_texture(); + + + ImGuiIO& io = ImGui::GetIO(); + + ImGui_ImplSDLRenderer3_NewFrame(); + ImGui_ImplSDL3_NewFrame(); + ImGui::NewFrame(); + + draw_chip8_widget(); + + ImGui::Render(); + SDL_SetRenderScale(renderer.get(), io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y); + SDL_SetRenderDrawColor(renderer.get(), 0, 0, 0, 0xFF); SDL_RenderClear(renderer.get()); - draw_display(); - + ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), renderer.get()); SDL_RenderPresent(renderer.get()); } -void Graphics::draw_display() { +void Graphics::build_chip8_texture() { SDL_Surface* surface = nullptr; auto& display = machine_state->display; @@ -70,10 +131,10 @@ void Graphics::draw_display() { for (int i = 0; i < display.size(); i++) { if (display[i]) { - int x = (i % 64) * scale; - int y = (i / 64) * scale; + int x = (i % chip8_width); + int y = (i / chip8_width); - SDL_Rect rect = {x, y, scale, scale}; + SDL_Rect rect = {x, y, 1, 1}; Uint32 color = SDL_MapRGB( SDL_GetPixelFormatDetails(surface->format), nullptr, @@ -88,8 +149,22 @@ void Graphics::draw_display() { } SDL_UnlockTexture(texture.get()); } - - SDL_FRect destination_rect{0.0, 0.0, static_cast(64 * scale), static_cast(32 * scale)}; - SDL_RenderTexture(renderer.get(), texture.get(), nullptr, &destination_rect); } +void Graphics::draw_chip8_widget() { + ImGui::Begin("CHIP-8"); + + const ImVec2 available_size = ImGui::GetContentRegionAvail(); + + int scale_x = static_cast(available_size.x / chip8_width); + int scale_y = static_cast(available_size.y / chip8_height); + int scale = std::max(1, std::min(scale_x, scale_y)); + ImVec2 scaled_size(chip8_width * scale, chip8_height * scale); + + ImVec2 cursor_pos = ImGui::GetCursorPos(); + ImVec2 center_offset((available_size.x - scaled_size.x) / 2, (available_size.y - scaled_size.y) / 2); + ImGui::SetCursorPos(ImVec2(cursor_pos.x + center_offset.x, cursor_pos.y + center_offset.y)); + + ImGui::Image((ImTextureID)(intptr_t)texture.get(), scaled_size); + ImGui::End(); +} diff --git a/src/Graphics.h b/src/Graphics.h index 4ee4959..7c143b5 100644 --- a/src/Graphics.h +++ b/src/Graphics.h @@ -7,6 +7,7 @@ #include #include +#include "imgui.h" #include "MachineState.h" #include "SDL3/SDL.h" @@ -23,15 +24,24 @@ struct SDLTextureDestroyer { class Graphics { std::shared_ptr machine_state; - std::shared_ptr window; - std::shared_ptr renderer; - std::shared_ptr texture; + std::unique_ptr window; + std::unique_ptr renderer; + std::unique_ptr texture; - int width; - int height; - int scale; + int window_width; + int window_height; + + int chip8_width; + int chip8_height; + + float main_scale; + + bool init_sdl(); + bool init_imgui(); + + void build_chip8_texture(); + void draw_chip8_widget(); - void draw_display(); public: Graphics(std::shared_ptr machine_state); diff --git a/src/main.cpp b/src/main.cpp index 87c1fbf..9ec76bf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,6 +4,8 @@ #include #include "Chip8.h" +#include "imgui.h" +#include "imgui_impl_sdl3.h" SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) { const auto chip8 = new Chip8(); @@ -31,6 +33,8 @@ SDL_AppResult SDL_AppIterate(void* appstate) { SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) { const auto chip8 = static_cast(appstate); + ImGui_ImplSDL3_ProcessEvent(event); + if (event->type == SDL_EVENT_QUIT) { return SDL_APP_SUCCESS; } @@ -39,6 +43,7 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) { chip8->on_keydown(event->key.scancode); } + return SDL_APP_CONTINUE; }