Usando un widget de imgui para renderizar el display de chip-8

This commit is contained in:
2025-06-22 01:51:51 -04:00
parent 928b203ef5
commit e11ff24ac7
4 changed files with 115 additions and 25 deletions

View File

@@ -13,7 +13,7 @@ Chip8::Chip8(): machine_state{std::make_shared<MachineState>()},
target_cycle_time{1.0 / 700.0}, target_cycle_time{1.0 / 700.0},
last_update_time{0}, last_update_time{0},
accumulator{0}, accumulator{0},
run{false}, run{true},
step{false} {} step{false} {}
bool Chip8::init() { bool Chip8::init() {

View File

@@ -7,6 +7,10 @@
#include <array> #include <array>
#include <iostream> #include <iostream>
#include "imgui.h"
#include "imgui_impl_sdl3.h"
#include "imgui_impl_sdlrenderer3.h"
void SDLWindowDestroyer::operator()(SDL_Window* window) const { void SDLWindowDestroyer::operator()(SDL_Window* window) const {
std::cout << "Destroying window" << std::endl; std::cout << "Destroying window" << std::endl;
SDL_DestroyWindow(window); SDL_DestroyWindow(window);
@@ -23,12 +27,13 @@ void SDLTextureDestroyer::operator()(SDL_Texture* texture) const {
} }
Graphics::Graphics(std::shared_ptr<MachineState> machine_state): machine_state{std::move(machine_state)}, Graphics::Graphics(std::shared_ptr<MachineState> machine_state): machine_state{std::move(machine_state)},
width{64 * 30}, window_width{1920},
height{32 * 30}, window_height{1080},
scale{30} {} chip8_width(64),
chip8_height(32),
main_scale(1.0f) {}
bool Graphics::init_sdl() {
bool Graphics::init() {
SDL_SetAppMetadata("CHIP-8 Emulator", "0.0.1", "fun.skrd.chip8"); SDL_SetAppMetadata("CHIP-8 Emulator", "0.0.1", "fun.skrd.chip8");
if (!SDL_Init(SDL_INIT_VIDEO)) { if (!SDL_Init(SDL_INIT_VIDEO)) {
@@ -38,7 +43,11 @@ bool Graphics::init() {
SDL_Window* raw_window = nullptr; SDL_Window* raw_window = nullptr;
SDL_Renderer* raw_renderer = 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()); SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
return false; return false;
} }
@@ -46,22 +55,74 @@ bool Graphics::init() {
this->window = std::unique_ptr<SDL_Window, SDLWindowDestroyer>(raw_window); this->window = std::unique_ptr<SDL_Window, SDLWindowDestroyer>(raw_window);
this->renderer = std::unique_ptr<SDL_Renderer, SDLRendererDestroyer>(raw_renderer); this->renderer = std::unique_ptr<SDL_Renderer, SDLRendererDestroyer>(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<SDL_Texture, SDLTextureDestroyer>(raw_texture); this->texture = std::unique_ptr<SDL_Texture, SDLTextureDestroyer>(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; return true;
} }
void Graphics::draw() { 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()); SDL_RenderClear(renderer.get());
draw_display(); ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), renderer.get());
SDL_RenderPresent(renderer.get()); SDL_RenderPresent(renderer.get());
} }
void Graphics::draw_display() { void Graphics::build_chip8_texture() {
SDL_Surface* surface = nullptr; SDL_Surface* surface = nullptr;
auto& display = machine_state->display; auto& display = machine_state->display;
@@ -70,10 +131,10 @@ void Graphics::draw_display() {
for (int i = 0; i < display.size(); i++) { for (int i = 0; i < display.size(); i++) {
if (display[i]) { if (display[i]) {
int x = (i % 64) * scale; int x = (i % chip8_width);
int y = (i / 64) * scale; int y = (i / chip8_width);
SDL_Rect rect = {x, y, scale, scale}; SDL_Rect rect = {x, y, 1, 1};
Uint32 color = SDL_MapRGB( Uint32 color = SDL_MapRGB(
SDL_GetPixelFormatDetails(surface->format), SDL_GetPixelFormatDetails(surface->format),
nullptr, nullptr,
@@ -88,8 +149,22 @@ void Graphics::draw_display() {
} }
SDL_UnlockTexture(texture.get()); SDL_UnlockTexture(texture.get());
} }
SDL_FRect destination_rect{0.0, 0.0, static_cast<float>(64 * scale), static_cast<float>(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<int>(available_size.x / chip8_width);
int scale_y = static_cast<int>(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();
}

View File

@@ -7,6 +7,7 @@
#include <bitset> #include <bitset>
#include <memory> #include <memory>
#include "imgui.h"
#include "MachineState.h" #include "MachineState.h"
#include "SDL3/SDL.h" #include "SDL3/SDL.h"
@@ -23,15 +24,24 @@ struct SDLTextureDestroyer {
class Graphics { class Graphics {
std::shared_ptr<MachineState> machine_state; std::shared_ptr<MachineState> machine_state;
std::shared_ptr<SDL_Window> window; std::unique_ptr<SDL_Window, SDLWindowDestroyer> window;
std::shared_ptr<SDL_Renderer> renderer; std::unique_ptr<SDL_Renderer, SDLRendererDestroyer> renderer;
std::shared_ptr<SDL_Texture> texture; std::unique_ptr<SDL_Texture, SDLTextureDestroyer> texture;
int width; int window_width;
int height; int window_height;
int scale;
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: public:
Graphics(std::shared_ptr<MachineState> machine_state); Graphics(std::shared_ptr<MachineState> machine_state);

View File

@@ -4,6 +4,8 @@
#include <SDL3/SDL_main.h> #include <SDL3/SDL_main.h>
#include "Chip8.h" #include "Chip8.h"
#include "imgui.h"
#include "imgui_impl_sdl3.h"
SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) { SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {
const auto chip8 = new Chip8(); const auto chip8 = new Chip8();
@@ -31,6 +33,8 @@ SDL_AppResult SDL_AppIterate(void* appstate) {
SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) { SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) {
const auto chip8 = static_cast<Chip8*>(appstate); const auto chip8 = static_cast<Chip8*>(appstate);
ImGui_ImplSDL3_ProcessEvent(event);
if (event->type == SDL_EVENT_QUIT) { if (event->type == SDL_EVENT_QUIT) {
return SDL_APP_SUCCESS; return SDL_APP_SUCCESS;
} }
@@ -39,6 +43,7 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) {
chip8->on_keydown(event->key.scancode); chip8->on_keydown(event->key.scancode);
} }
return SDL_APP_CONTINUE; return SDL_APP_CONTINUE;
} }