Aplicando formato default de jetbrains :c

This commit is contained in:
2025-06-26 21:01:27 -04:00
parent 4d129018e3
commit 5ebc235cae
21 changed files with 455 additions and 233 deletions

18
.idea/editor.xml generated
View File

@@ -244,23 +244,5 @@
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IfStdIsConstantEvaluatedCanBeReplaced/@EntryIndexedValue" value="SUGGESTION" type="string" /> <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IfStdIsConstantEvaluatedCanBeReplaced/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StdIsConstantEvaluatedWillAlwaysEvaluateToConstant/@EntryIndexedValue" value="WARNING" type="string" /> <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StdIsConstantEvaluatedWillAlwaysEvaluateToConstant/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StringLiteralTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" /> <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StringLiteralTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALLOW_COMMENT_AFTER_LBRACE/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CASE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/DISABLE_SPACE_CHANGES_BEFORE_TRAILING_COMMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/EMPTY_BLOCK_STYLE/@EntryValue" value="TOGETHER" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/EXPORT_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CASE_FROM_SWITCH/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INT_ALIGN_COMMENTS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INT_ALIGN_ENUM_INITIALIZERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INVOCABLE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/OTHER_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_CATCH_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_ELSE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_WHILE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/REQUIRES_EXPRESSION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TYPE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CppIncludeDirective/SortIncludeDirectives/@EntryValue" value="true" type="bool" />
</component> </component>
</project> </project>

View File

@@ -2,12 +2,15 @@
#define COLOR_H #define COLOR_H
#include <cstdint> #include <cstdint>
struct Color { struct Color
{
uint8_t r; uint8_t r;
uint8_t g; uint8_t g;
uint8_t b; uint8_t b;
Color(const uint8_t r, const uint8_t g, const uint8_t b) : r(r), g(g), b(b) {} Color(const uint8_t r, const uint8_t g, const uint8_t b) : r(r), g(g), b(b)
{
}
}; };
#endif //COLOR_H #endif //COLOR_H

View File

@@ -8,15 +8,18 @@
#include "imgui_impl_sdl3.h" #include "imgui_impl_sdl3.h"
#include "imgui_impl_sdlrenderer3.h" #include "imgui_impl_sdlrenderer3.h"
Graphics::Graphics(): window_width{1366}, window_height{768}, main_scale{1.0f} { Graphics::Graphics() : window_width{1366}, window_height{768}, main_scale{1.0f}
{
create_sdl(); create_sdl();
create_imgui(); create_imgui();
} }
void Graphics::create_sdl() { void Graphics::create_sdl()
{
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))
{
throw std::runtime_error(std::format("Couldn't initialize SDL: {}", SDL_GetError())); throw std::runtime_error(std::format("Couldn't initialize SDL: {}", SDL_GetError()));
} }
@@ -33,7 +36,8 @@ void Graphics::create_sdl() {
window_flags, window_flags,
&raw_window, &raw_window,
&raw_renderer &raw_renderer
)) { ))
{
throw std::runtime_error(std::format("Couldn't create window/renderer: {}", SDL_GetError())); throw std::runtime_error(std::format("Couldn't create window/renderer: {}", SDL_GetError()));
} }
@@ -45,7 +49,8 @@ void Graphics::create_sdl() {
SDL_ShowWindow(this->window.get()); SDL_ShowWindow(this->window.get());
} }
void Graphics::create_imgui() const { void Graphics::create_imgui() const
{
IMGUI_CHECKVERSION(); IMGUI_CHECKVERSION();
ImGui::CreateContext(); ImGui::CreateContext();
@@ -62,21 +67,26 @@ void Graphics::create_imgui() const {
ImGui_ImplSDLRenderer3_Init(this->renderer.get()); ImGui_ImplSDLRenderer3_Init(this->renderer.get());
} }
std::shared_ptr<SDL_Renderer> Graphics::get_renderer() { std::shared_ptr<SDL_Renderer> Graphics::get_renderer()
{
return this->renderer; return this->renderer;
} }
std::shared_ptr<SDL_Window> Graphics::get_window() {
std::shared_ptr<SDL_Window> Graphics::get_window()
{
return this->window; return this->window;
} }
void Graphics::start() const { void Graphics::start() const
{
ImGui_ImplSDLRenderer3_NewFrame(); ImGui_ImplSDLRenderer3_NewFrame();
ImGui_ImplSDL3_NewFrame(); ImGui_ImplSDL3_NewFrame();
ImGui::NewFrame(); ImGui::NewFrame();
ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport()); ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport());
} }
void Graphics::end() const { void Graphics::end() const
{
const ImGuiIO& io = ImGui::GetIO(); const ImGuiIO& io = ImGui::GetIO();
ImGui::Render(); ImGui::Render();
@@ -86,4 +96,4 @@ void Graphics::end() const {
ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), this->renderer.get()); ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), this->renderer.get());
SDL_RenderPresent(this->renderer.get()); SDL_RenderPresent(this->renderer.get());
} }

View File

@@ -4,11 +4,13 @@
#include <memory> #include <memory>
#include "SDL3/SDL.h" #include "SDL3/SDL.h"
struct SDLWindowDestroyer { struct SDLWindowDestroyer
{
void operator()(SDL_Window* window) const; void operator()(SDL_Window* window) const;
}; };
class Graphics { class Graphics
{
int window_width; int window_width;
int window_height; int window_height;
float main_scale; float main_scale;
@@ -18,6 +20,7 @@ class Graphics {
void create_sdl(); void create_sdl();
void create_imgui() const; void create_imgui() const;
public: public:
Graphics(); Graphics();
@@ -27,4 +30,4 @@ public:
std::shared_ptr<SDL_Window> get_window(); std::shared_ptr<SDL_Window> get_window();
}; };
#endif //GRAPHICS_H #endif //GRAPHICS_H

View File

@@ -5,7 +5,8 @@
#include "OpCode.h" #include "OpCode.h"
struct Instruction { struct Instruction
{
OpCode op_code; OpCode op_code;
uint8_t operation; uint8_t operation;
uint16_t instruction; uint16_t instruction;
@@ -16,4 +17,4 @@ struct Instruction {
uint16_t nnn; uint16_t nnn;
}; };
#endif //INSTRUCTION_H #endif //INSTRUCTION_H

View File

@@ -3,16 +3,19 @@
#include <iostream> #include <iostream>
#include <random> #include <random>
Interpreter::Interpreter(std::shared_ptr<MachineState> machine_state): Interpreter::Interpreter(std::shared_ptr<MachineState> machine_state) :
machine_state{std::move(machine_state)}, machine_state{std::move(machine_state)},
random_generator{std::random_device{}()} { random_generator{std::random_device{}()}
{
srand(time(nullptr)); srand(time(nullptr));
for (bool& display : this->machine_state->display) { for (bool& display : this->machine_state->display)
{
display = rand() % 100 > 50; display = rand() % 100 > 50;
} }
} }
void Interpreter::tick() { void Interpreter::tick()
{
const uint8_t high_word = this->machine_state->memory[this->machine_state->pc]; const uint8_t high_word = this->machine_state->memory[this->machine_state->pc];
const uint8_t low_word = this->machine_state->memory[this->machine_state->pc + 1]; const uint8_t low_word = this->machine_state->memory[this->machine_state->pc + 1];
const uint16_t word = high_word << 8 | low_word; const uint16_t word = high_word << 8 | low_word;
@@ -21,13 +24,15 @@ void Interpreter::tick() {
this->machine_state->pc += 2; this->machine_state->pc += 2;
this->execute_instruction(instruction); this->execute_instruction(instruction);
if (this->machine_state->pc >= 0xFFF) { if (this->machine_state->pc >= 0xFFF)
{
std::cout << "PC Outside of memory, going back 0x200" << std::endl; std::cout << "PC Outside of memory, going back 0x200" << std::endl;
this->machine_state->pc = 0x200; this->machine_state->pc = 0x200;
} }
} }
Instruction Interpreter::decode(const uint16_t word) const { Instruction Interpreter::decode(const uint16_t word) const
{
const uint8_t operation = (word & 0xF000) >> 12; const uint8_t operation = (word & 0xF000) >> 12;
const uint8_t x = (word & 0x0F00) >> 8; const uint8_t x = (word & 0x0F00) >> 8;
const uint8_t y = (word & 0x00F0) >> 4; const uint8_t y = (word & 0x00F0) >> 4;
@@ -37,82 +42,155 @@ Instruction Interpreter::decode(const uint16_t word) const {
auto op_code = OpCode::NOP; auto op_code = OpCode::NOP;
if (operation == 0) { if (operation == 0)
if (kk == 0xE0) { {
if (kk == 0xE0)
{
op_code = OpCode::CLS; op_code = OpCode::CLS;
} else if (kk == 0xEE) { }
else if (kk == 0xEE)
{
op_code = OpCode::RET; op_code = OpCode::RET;
} else { }
else
{
op_code = OpCode::SYS_ADDR; op_code = OpCode::SYS_ADDR;
} }
} else if (operation == 1) { }
else if (operation == 1)
{
op_code = OpCode::JP_ADDR; op_code = OpCode::JP_ADDR;
} else if (operation == 2) { }
else if (operation == 2)
{
op_code = OpCode::CALL_ADDR; op_code = OpCode::CALL_ADDR;
} else if (operation == 3) { }
else if (operation == 3)
{
op_code = OpCode::SE_VX_BYTE; op_code = OpCode::SE_VX_BYTE;
} else if (operation == 4) { }
else if (operation == 4)
{
op_code = OpCode::SNE_VX_BYTE; op_code = OpCode::SNE_VX_BYTE;
} else if (operation == 5) { }
else if (operation == 5)
{
op_code = OpCode::SE_VX_VY; op_code = OpCode::SE_VX_VY;
} else if (operation == 6) { }
else if (operation == 6)
{
op_code = OpCode::LD_VX_BYTE; op_code = OpCode::LD_VX_BYTE;
} else if (operation == 7) { }
else if (operation == 7)
{
op_code = OpCode::ADD_VX_BYTE; op_code = OpCode::ADD_VX_BYTE;
} else if (operation == 8) { }
if (n == 0) { else if (operation == 8)
{
if (n == 0)
{
op_code = OpCode::LD_VX_VY; op_code = OpCode::LD_VX_VY;
} else if (n == 1) { }
else if (n == 1)
{
op_code = OpCode::OR_VX_VY; op_code = OpCode::OR_VX_VY;
} else if (n == 2) { }
else if (n == 2)
{
op_code = OpCode::AND_VX_VY; op_code = OpCode::AND_VX_VY;
} else if (n == 3) { }
else if (n == 3)
{
op_code = OpCode::XOR_VX_VY; op_code = OpCode::XOR_VX_VY;
} else if (n == 4) { }
else if (n == 4)
{
op_code = OpCode::ADD_VX_VY; op_code = OpCode::ADD_VX_VY;
} else if (n == 5) { }
else if (n == 5)
{
op_code = OpCode::SUB_VX_VY; op_code = OpCode::SUB_VX_VY;
} else if (n == 6) { }
else if (n == 6)
{
op_code = OpCode::SHR_VX_VY; op_code = OpCode::SHR_VX_VY;
} else if (n == 7) { }
else if (n == 7)
{
op_code = OpCode::SUBN_VX_VY; op_code = OpCode::SUBN_VX_VY;
} else if (n == 0xE) { }
else if (n == 0xE)
{
op_code = OpCode::SHL_VX_VY; op_code = OpCode::SHL_VX_VY;
} }
} else if (operation == 9) { }
else if (operation == 9)
{
op_code = OpCode::SNE_VX_VY; op_code = OpCode::SNE_VX_VY;
} else if (operation == 0xA) { }
else if (operation == 0xA)
{
op_code = OpCode::LD_I_ADDR; op_code = OpCode::LD_I_ADDR;
} else if (operation == 0xB) { }
else if (operation == 0xB)
{
op_code = OpCode::JP_V0_ADDR; op_code = OpCode::JP_V0_ADDR;
} else if (operation == 0xC) { }
else if (operation == 0xC)
{
op_code = OpCode::RND_VX_BYTE; op_code = OpCode::RND_VX_BYTE;
} else if (operation == 0xD) { }
else if (operation == 0xD)
{
op_code = OpCode::DRW_VX_VY_NIBBLE; op_code = OpCode::DRW_VX_VY_NIBBLE;
} else if (operation == 0xE) { }
if (kk == 0x9E) { else if (operation == 0xE)
{
if (kk == 0x9E)
{
op_code = OpCode::SKP_VX; op_code = OpCode::SKP_VX;
} else if (kk == 0xA1) { }
else if (kk == 0xA1)
{
op_code = OpCode::SKNP_VX; op_code = OpCode::SKNP_VX;
} }
} else if (operation == 0xF) { }
if (kk == 0x07) { else if (operation == 0xF)
{
if (kk == 0x07)
{
op_code = OpCode::LD_VX_DT; op_code = OpCode::LD_VX_DT;
} else if (kk == 0x0A) { }
else if (kk == 0x0A)
{
op_code = OpCode::LD_VX_K; op_code = OpCode::LD_VX_K;
} else if (kk == 0x15) { }
else if (kk == 0x15)
{
op_code = OpCode::LD_DT_VX; op_code = OpCode::LD_DT_VX;
} else if (kk == 0x18) { }
else if (kk == 0x18)
{
op_code = OpCode::LD_ST_VX; op_code = OpCode::LD_ST_VX;
} else if (kk == 0x1E) { }
else if (kk == 0x1E)
{
op_code = OpCode::ADD_I_VX; op_code = OpCode::ADD_I_VX;
} else if (kk == 0x29) { }
else if (kk == 0x29)
{
op_code = OpCode::LD_F_VX; op_code = OpCode::LD_F_VX;
} else if (kk == 0x33) { }
else if (kk == 0x33)
{
op_code = OpCode::LD_B_VX; op_code = OpCode::LD_B_VX;
} else if (kk == 0x55) { }
else if (kk == 0x55)
{
op_code = OpCode::LD_I_VX; op_code = OpCode::LD_I_VX;
} else if (kk == 0x65) { }
else if (kk == 0x65)
{
op_code = OpCode::LD_VX_I; op_code = OpCode::LD_VX_I;
} }
} }
@@ -129,7 +207,8 @@ Instruction Interpreter::decode(const uint16_t word) const {
}; };
} }
void Interpreter::execute_instruction(const Instruction& instruction) { void Interpreter::execute_instruction(const Instruction& instruction)
{
if (instruction.op_code == OpCode::CLS) this->cls(); if (instruction.op_code == OpCode::CLS) this->cls();
else if (instruction.op_code == OpCode::RET) this->ret(); else if (instruction.op_code == OpCode::RET) this->ret();
else if (instruction.op_code == OpCode::SYS_ADDR) this->sys_addr(); else if (instruction.op_code == OpCode::SYS_ADDR) this->sys_addr();
@@ -168,179 +247,228 @@ void Interpreter::execute_instruction(const Instruction& instruction) {
else if (instruction.op_code == OpCode::NOP) this->nop(); else if (instruction.op_code == OpCode::NOP) this->nop();
} }
void Interpreter::sys_addr() const { void Interpreter::sys_addr() const
{
// NOP // NOP
} }
void Interpreter::nop() const { void Interpreter::nop() const
{
// NOP // NOP
} }
void Interpreter::cls() const { void Interpreter::cls() const
{
this->machine_state->display.fill(false); this->machine_state->display.fill(false);
} }
void Interpreter::ret() const { void Interpreter::ret() const
{
this->machine_state->sp -= 1; this->machine_state->sp -= 1;
this->machine_state->pc = this->machine_state->stack[this->machine_state->sp]; this->machine_state->pc = this->machine_state->stack[this->machine_state->sp];
} }
void Interpreter::jp_addr(const Instruction& instruction) const { void Interpreter::jp_addr(const Instruction& instruction) const
{
this->machine_state->pc = instruction.nnn; this->machine_state->pc = instruction.nnn;
} }
void Interpreter::call_addr(const Instruction& instruction) const { void Interpreter::call_addr(const Instruction& instruction) const
{
this->machine_state->stack[this->machine_state->sp] = this->machine_state->pc; this->machine_state->stack[this->machine_state->sp] = this->machine_state->pc;
this->machine_state->sp += 1; this->machine_state->sp += 1;
this->machine_state->pc = instruction.nnn; this->machine_state->pc = instruction.nnn;
} }
void Interpreter::se_vx_byte(const Instruction& instruction) const { void Interpreter::se_vx_byte(const Instruction& instruction) const
if (this->machine_state->v[instruction.x] == instruction.kk) { {
if (this->machine_state->v[instruction.x] == instruction.kk)
{
this->machine_state->pc += 2; this->machine_state->pc += 2;
} }
} }
void Interpreter::sne_vx_byte(const Instruction& instruction) const { void Interpreter::sne_vx_byte(const Instruction& instruction) const
if (this->machine_state->v[instruction.x] != instruction.kk) { {
if (this->machine_state->v[instruction.x] != instruction.kk)
{
this->machine_state->pc += 2; this->machine_state->pc += 2;
} }
} }
void Interpreter::se_vx_vy(const Instruction& instruction) const { void Interpreter::se_vx_vy(const Instruction& instruction) const
if (this->machine_state->v[instruction.x] == this->machine_state->v[instruction.y]) { {
if (this->machine_state->v[instruction.x] == this->machine_state->v[instruction.y])
{
this->machine_state->pc += 2; this->machine_state->pc += 2;
} }
} }
void Interpreter::ld_vx_byte(const Instruction& instruction) const { void Interpreter::ld_vx_byte(const Instruction& instruction) const
{
this->machine_state->v[instruction.x] = instruction.kk; this->machine_state->v[instruction.x] = instruction.kk;
} }
void Interpreter::add_vx_byte(const Instruction& instruction) const { void Interpreter::add_vx_byte(const Instruction& instruction) const
{
this->machine_state->v[instruction.x] += instruction.kk; this->machine_state->v[instruction.x] += instruction.kk;
} }
void Interpreter::ld_vx_vy(const Instruction& instruction) const { void Interpreter::ld_vx_vy(const Instruction& instruction) const
{
this->machine_state->v[instruction.x] = this->machine_state->v[instruction.y]; this->machine_state->v[instruction.x] = this->machine_state->v[instruction.y];
} }
void Interpreter::or_vx_vy(const Instruction& instruction) const { void Interpreter::or_vx_vy(const Instruction& instruction) const
{
this->machine_state->v[instruction.x] |= this->machine_state->v[instruction.y]; this->machine_state->v[instruction.x] |= this->machine_state->v[instruction.y];
} }
void Interpreter::and_vx_vy(const Instruction& instruction) const { void Interpreter::and_vx_vy(const Instruction& instruction) const
{
this->machine_state->v[instruction.x] &= this->machine_state->v[instruction.y]; this->machine_state->v[instruction.x] &= this->machine_state->v[instruction.y];
} }
void Interpreter::xor_vx_vy(const Instruction& instruction) const { void Interpreter::xor_vx_vy(const Instruction& instruction) const
{
this->machine_state->v[instruction.x] ^= this->machine_state->v[instruction.y]; this->machine_state->v[instruction.x] ^= this->machine_state->v[instruction.y];
} }
void Interpreter::add_vx_vy(const Instruction& instruction) const { void Interpreter::add_vx_vy(const Instruction& instruction) const
{
auto& vx = this->machine_state->v[instruction.x]; auto& vx = this->machine_state->v[instruction.x];
const auto& vy = this->machine_state->v[instruction.y]; const auto& vy = this->machine_state->v[instruction.y];
auto& vf = this->machine_state->v[0xF]; auto& vf = this->machine_state->v[0xF];
if (vx + vy > 0xFF) { if (vx + vy > 0xFF)
{
vf = 1; vf = 1;
} else { }
else
{
vf = 0; vf = 0;
} }
vx += vy; vx += vy;
} }
void Interpreter::sub_vx_vy(const Instruction& instruction) const { void Interpreter::sub_vx_vy(const Instruction& instruction) const
{
auto& vx = this->machine_state->v[instruction.x]; auto& vx = this->machine_state->v[instruction.x];
const auto& vy = this->machine_state->v[instruction.y]; const auto& vy = this->machine_state->v[instruction.y];
auto& vf = this->machine_state->v[0xF]; auto& vf = this->machine_state->v[0xF];
if (vx > vy) { if (vx > vy)
{
vf = 1; vf = 1;
} else { }
else
{
vf = 0; vf = 0;
} }
vx -= vy; vx -= vy;
} }
void Interpreter::shr_vx_vy(const Instruction& instruction) const { void Interpreter::shr_vx_vy(const Instruction& instruction) const
{
auto& vx = this->machine_state->v[instruction.x]; auto& vx = this->machine_state->v[instruction.x];
const auto& vy = this->machine_state->v[instruction.y]; const auto& vy = this->machine_state->v[instruction.y];
auto& vf = this->machine_state->v[0xF]; auto& vf = this->machine_state->v[0xF];
if (quirks & static_cast<uint8_t>(InterpreterQuirks::COSMAC_SHIFT)) { if (quirks & static_cast<uint8_t>(InterpreterQuirks::COSMAC_SHIFT))
{
vx = vy; vx = vy;
} }
if (vx & 0x01) { if (vx & 0x01)
{
vf = 1; vf = 1;
} else { }
else
{
vf = 0; vf = 0;
} }
vx = vx >> 1; vx = vx >> 1;
} }
void Interpreter::subn_vx_vy(const Instruction& instruction) const { void Interpreter::subn_vx_vy(const Instruction& instruction) const
{
auto& vx = this->machine_state->v[instruction.x]; auto& vx = this->machine_state->v[instruction.x];
const auto& vy = this->machine_state->v[instruction.y]; const auto& vy = this->machine_state->v[instruction.y];
auto& vf = this->machine_state->v[0xF]; auto& vf = this->machine_state->v[0xF];
if (vy > vx) { if (vy > vx)
{
vf = 1; vf = 1;
} else { }
else
{
vf = 0; vf = 0;
} }
vx = vy - vx; vx = vy - vx;
} }
void Interpreter::shl_vx_vy(const Instruction& instruction) const { void Interpreter::shl_vx_vy(const Instruction& instruction) const
{
auto& vx = this->machine_state->v[instruction.x]; auto& vx = this->machine_state->v[instruction.x];
const auto& vy = this->machine_state->v[instruction.y]; const auto& vy = this->machine_state->v[instruction.y];
auto& vf = this->machine_state->v[0xF]; auto& vf = this->machine_state->v[0xF];
if (this->quirks & static_cast<uint8_t>(InterpreterQuirks::COSMAC_SHIFT)) { if (this->quirks & static_cast<uint8_t>(InterpreterQuirks::COSMAC_SHIFT))
{
vx = vy; vx = vy;
} }
if (vx & 0x80) { if (vx & 0x80)
{
vf = 1; vf = 1;
} else { }
else
{
vf = 0; vf = 0;
} }
vx = vx << 1; vx = vx << 1;
} }
void Interpreter::sne_vx_vy(const Instruction& instruction) const { void Interpreter::sne_vx_vy(const Instruction& instruction) const
if (this->machine_state->v[instruction.x] != this->machine_state->v[instruction.y]) { {
if (this->machine_state->v[instruction.x] != this->machine_state->v[instruction.y])
{
this->machine_state->pc += 2; this->machine_state->pc += 2;
} }
} }
void Interpreter::ld_i_addr(const Instruction& instruction) const { void Interpreter::ld_i_addr(const Instruction& instruction) const
{
this->machine_state->i = instruction.nnn; this->machine_state->i = instruction.nnn;
} }
void Interpreter::jp_v0_addr(const Instruction& instruction) const { void Interpreter::jp_v0_addr(const Instruction& instruction) const
if (this->quirks & static_cast<uint8_t>(InterpreterQuirks::SUPER_CHIP_JUMP)) { {
if (this->quirks & static_cast<uint8_t>(InterpreterQuirks::SUPER_CHIP_JUMP))
{
this->machine_state->pc = instruction.nnn + this->machine_state->v[instruction.x]; this->machine_state->pc = instruction.nnn + this->machine_state->v[instruction.x];
} else { }
else
{
this->machine_state->pc = instruction.nnn + this->machine_state->v[0]; this->machine_state->pc = instruction.nnn + this->machine_state->v[0];
} }
} }
void Interpreter::rnd_vx_byte(const Instruction& instruction) { void Interpreter::rnd_vx_byte(const Instruction& instruction)
{
auto distribution = std::uniform_int_distribution<uint8_t>(0, 0xFF); auto distribution = std::uniform_int_distribution<uint8_t>(0, 0xFF);
const auto value = distribution(this->random_generator); const auto value = distribution(this->random_generator);
this->machine_state->v[instruction.x] = value & instruction.kk; this->machine_state->v[instruction.x] = value & instruction.kk;
} }
void Interpreter::drw_vx_vy_nibble(const Instruction& instruction) const { void Interpreter::drw_vx_vy_nibble(const Instruction& instruction) const
{
const auto& memory = this->machine_state->memory; const auto& memory = this->machine_state->memory;
auto& display = this->machine_state->display; auto& display = this->machine_state->display;
const auto& vx = this->machine_state->v[instruction.x]; const auto& vx = this->machine_state->v[instruction.x];
@@ -352,30 +480,38 @@ void Interpreter::drw_vx_vy_nibble(const Instruction& instruction) const {
const uint8_t start_y = vy & 31; const uint8_t start_y = vy & 31;
vf = 0; vf = 0;
for (auto row = 0; row < instruction.n; row++) { for (auto row = 0; row < instruction.n; row++)
{
const auto current_y = start_y + row; const auto current_y = start_y + row;
if (current_y > 31) { if (current_y > 31)
{
break; break;
} }
const auto sprite_byte = memory[i + row]; const auto sprite_byte = memory[i + row];
for (auto bit = 0; bit < 8; bit++) { for (auto bit = 0; bit < 8; bit++)
{
const auto current_x = start_x + bit; const auto current_x = start_x + bit;
if (current_x > 63) { if (current_x > 63)
{
break; break;
} }
const auto pixel = sprite_byte >> (7 - bit) & 0x01; const auto pixel = sprite_byte >> (7 - bit) & 0x01;
const auto index = current_y * 64 + current_x; const auto index = current_y * 64 + current_x;
if (pixel) { if (pixel)
if (display[index]) { {
if (display[index])
{
display[index] = false; display[index] = false;
vf = 1; vf = 1;
} else { }
else
{
display[index] = true; display[index] = true;
} }
} }
@@ -383,81 +519,107 @@ void Interpreter::drw_vx_vy_nibble(const Instruction& instruction) const {
} }
} }
void Interpreter::skp_vx(const Instruction& instruction) const { void Interpreter::skp_vx(const Instruction& instruction) const
if (this->machine_state->keyboard & 1 << instruction.x) { {
if (this->machine_state->keyboard & 1 << instruction.x)
{
this->machine_state->pc += 2; this->machine_state->pc += 2;
} }
} }
void Interpreter::sknp_vx(const Instruction& instruction) const { void Interpreter::sknp_vx(const Instruction& instruction) const
if (!(this->machine_state->keyboard & 1 << instruction.x)) { {
if (!(this->machine_state->keyboard & 1 << instruction.x))
{
this->machine_state->pc += 2; this->machine_state->pc += 2;
} }
} }
void Interpreter::ld_vx_dt(const Instruction& instruction) const { void Interpreter::ld_vx_dt(const Instruction& instruction) const
{
this->machine_state->v[instruction.x] = this->machine_state->dt; this->machine_state->v[instruction.x] = this->machine_state->dt;
} }
void Interpreter::ld_vx_k(const Instruction& instruction) const { void Interpreter::ld_vx_k(const Instruction& instruction) const
if (this->machine_state->keyboard == 0) { {
if (this->machine_state->keyboard == 0)
{
this->machine_state->pc -= 2; this->machine_state->pc -= 2;
return; return;
} }
for (auto key = 0; key < 16; key++) { for (auto key = 0; key < 16; key++)
if (this->machine_state->keyboard & 1 << key) { {
if (this->machine_state->keyboard & 1 << key)
{
this->machine_state->v[instruction.x] = key; this->machine_state->v[instruction.x] = key;
break; break;
} }
} }
} }
void Interpreter::ld_dt_vx(const Instruction& instruction) const { void Interpreter::ld_dt_vx(const Instruction& instruction) const
{
this->machine_state->dt = this->machine_state->v[instruction.x]; this->machine_state->dt = this->machine_state->v[instruction.x];
} }
void Interpreter::ld_st_vx(const Instruction& instruction) const { void Interpreter::ld_st_vx(const Instruction& instruction) const
{
this->machine_state->st = this->machine_state->v[instruction.x]; this->machine_state->st = this->machine_state->v[instruction.x];
} }
void Interpreter::add_i_vx(const Instruction& instruction) const { void Interpreter::add_i_vx(const Instruction& instruction) const
{
this->machine_state->i += this->machine_state->v[instruction.x]; this->machine_state->i += this->machine_state->v[instruction.x];
} }
void Interpreter::ld_f_vx(const Instruction& instruction) const { void Interpreter::ld_f_vx(const Instruction& instruction) const
{
this->machine_state->i = (this->machine_state->v[instruction.x] & 0xF) * 5 + 0x50; this->machine_state->i = (this->machine_state->v[instruction.x] & 0xF) * 5 + 0x50;
} }
void Interpreter::ld_b_vx(const Instruction& instruction) const { void Interpreter::ld_b_vx(const Instruction& instruction) const
{
const auto number = this->machine_state->v[instruction.x]; const auto number = this->machine_state->v[instruction.x];
this->machine_state->memory[this->machine_state->i] = number / 100; this->machine_state->memory[this->machine_state->i] = number / 100;
this->machine_state->memory[this->machine_state->i + 1] = (number - this->machine_state->memory[this->machine_state->i] * 100) / 10; this->machine_state->memory[this->machine_state->i + 1] = (number - this->machine_state->memory[this->machine_state
this->machine_state->memory[this->machine_state->i + 2] = number - this->machine_state->memory[this->machine_state->i] * 100 - this->machine_state->memory[this->machine_state->i + 1] * 10; ->i] * 100) / 10;
this->machine_state->memory[this->machine_state->i + 2] = number - this->machine_state->memory[this->machine_state->
i] * 100 - this->machine_state->memory[this->machine_state->i + 1] * 10;
} }
void Interpreter::ld_i_vx(const Instruction& instruction) const { void Interpreter::ld_i_vx(const Instruction& instruction) const
{
const bool use_quirk = this->quirks & static_cast<uint8_t>(InterpreterQuirks::COSMAC_STORE_AND_LOAD); const bool use_quirk = this->quirks & static_cast<uint8_t>(InterpreterQuirks::COSMAC_STORE_AND_LOAD);
for (auto reg = 0; reg <= instruction.x; reg++) { for (auto reg = 0; reg <= instruction.x; reg++)
if (use_quirk) { {
if (use_quirk)
{
this->machine_state->memory[this->machine_state->i] = this->machine_state->v[reg]; this->machine_state->memory[this->machine_state->i] = this->machine_state->v[reg];
this->machine_state->i++; this->machine_state->i++;
} else { }
else
{
this->machine_state->memory[this->machine_state->i + reg] = this->machine_state->v[reg]; this->machine_state->memory[this->machine_state->i + reg] = this->machine_state->v[reg];
} }
} }
} }
void Interpreter::ld_vx_i(const Instruction& instruction) const { void Interpreter::ld_vx_i(const Instruction& instruction) const
{
const bool use_quirk = this->quirks & static_cast<uint8_t>(InterpreterQuirks::COSMAC_STORE_AND_LOAD); const bool use_quirk = this->quirks & static_cast<uint8_t>(InterpreterQuirks::COSMAC_STORE_AND_LOAD);
for (auto reg = 0; reg <= instruction.x; reg++) { for (auto reg = 0; reg <= instruction.x; reg++)
if (use_quirk) { {
if (use_quirk)
{
this->machine_state->v[reg] = this->machine_state->memory[this->machine_state->i]; this->machine_state->v[reg] = this->machine_state->memory[this->machine_state->i];
this->machine_state->i++; this->machine_state->i++;
} else { }
else
{
this->machine_state->v[reg] = this->machine_state->memory[this->machine_state->i + reg]; this->machine_state->v[reg] = this->machine_state->memory[this->machine_state->i + reg];
} }
} }
} }

View File

@@ -7,13 +7,15 @@
#include "Instruction.h" #include "Instruction.h"
#include "MachineState.h" #include "MachineState.h"
enum class InterpreterQuirks { enum class InterpreterQuirks
COSMAC_SHIFT = 1 << 0, {
SUPER_CHIP_JUMP = 1 << 1, COSMAC_SHIFT = 1 << 0,
SUPER_CHIP_JUMP = 1 << 1,
COSMAC_STORE_AND_LOAD = 1 << 2, COSMAC_STORE_AND_LOAD = 1 << 2,
}; };
class Interpreter { class Interpreter
{
std::shared_ptr<MachineState> machine_state; std::shared_ptr<MachineState> machine_state;
std::mt19937 random_generator; std::mt19937 random_generator;
@@ -66,4 +68,4 @@ public:
}; };
#endif //INTERPRETER_H #endif //INTERPRETER_H

View File

@@ -1,6 +1,6 @@
#include "MachineState.h" #include "MachineState.h"
MachineState::MachineState(): MachineState::MachineState() :
memory{}, memory{},
v{}, v{},
stack{}, stack{},
@@ -11,9 +11,11 @@ MachineState::MachineState():
i{0}, i{0},
dt{0}, dt{0},
st{0} st{0}
{} {
}
void MachineState::reset() { void MachineState::reset()
{
this->memory.fill(0); this->memory.fill(0);
this->v.fill(0); this->v.fill(0);
this->stack.fill(0); this->stack.fill(0);
@@ -24,4 +26,4 @@ void MachineState::reset() {
this->i = 0; this->i = 0;
this->dt = 0; this->dt = 0;
this->st = 0; this->st = 0;
} }

View File

@@ -3,7 +3,8 @@
#include <array> #include <array>
#include <cstdint> #include <cstdint>
struct MachineState { struct MachineState
{
std::array<uint8_t, 4096> memory; std::array<uint8_t, 4096> memory;
std::array<uint16_t, 16> v; std::array<uint16_t, 16> v;
std::array<uint16_t, 16> stack; std::array<uint16_t, 16> stack;
@@ -20,4 +21,4 @@ struct MachineState {
void reset(); void reset();
}; };
#endif //MACHINESTATE_H #endif //MACHINESTATE_H

View File

@@ -1,7 +1,8 @@
#ifndef OPCODE_H #ifndef OPCODE_H
#define OPCODE_H #define OPCODE_H
enum class OpCode { enum class OpCode
{
CLS, // 00E0 - CLS CLS, // 00E0 - CLS
RET, // 00EE - RET RET, // 00EE - RET
SYS_ADDR, // 0nnn - SYS addr SYS_ADDR, // 0nnn - SYS addr
@@ -40,4 +41,4 @@ enum class OpCode {
NOP, // INVALID OPERATION NOP, // INVALID OPERATION
}; };
#endif //OPCODE_H #endif //OPCODE_H

View File

@@ -20,15 +20,16 @@ Machine::Machine() :
interpreter{std::make_unique<Interpreter>(this->machine_state)}, interpreter{std::make_unique<Interpreter>(this->machine_state)},
ui_manager{std::make_unique<UIManager>(this->graphics, this->machine_state, this->callback_manager)}, ui_manager{std::make_unique<UIManager>(this->graphics, this->machine_state, this->callback_manager)},
ips{700}, ips{700},
last_update_time{0}, last_update_time{0},
accumulator{0}, accumulator{0},
target_cycle_time{1.0 / this->ips} { target_cycle_time{1.0 / this->ips}
{
this->register_callbacks(); this->register_callbacks();
} }
void Machine::iterate() { void Machine::iterate()
{
this->execute_interpreter(); this->execute_interpreter();
this->graphics->start(); this->graphics->start();
@@ -36,29 +37,34 @@ void Machine::iterate() {
this->graphics->end(); this->graphics->end();
} }
bool Machine::on_event(const SDL_Event* event) const { bool Machine::on_event(const SDL_Event* event) const
{
ImGui_ImplSDL3_ProcessEvent(event); ImGui_ImplSDL3_ProcessEvent(event);
if (event->type == SDL_EVENT_QUIT) { if (event->type == SDL_EVENT_QUIT)
{
return false; return false;
} }
return true; return true;
} }
void Machine::execute_interpreter() { void Machine::execute_interpreter()
{
const auto current_time = SDL_GetTicks(); const auto current_time = SDL_GetTicks();
const auto delta_time = static_cast<double>(current_time - this->last_update_time) / 1000.0; const auto delta_time = static_cast<double>(current_time - this->last_update_time) / 1000.0;
this->last_update_time = current_time; this->last_update_time = current_time;
this->accumulator += delta_time; this->accumulator += delta_time;
while (this->accumulator >= this->target_cycle_time) { while (this->accumulator >= this->target_cycle_time)
{
this->interpreter->tick(); this->interpreter->tick();
this->accumulator -= this->target_cycle_time; this->accumulator -= this->target_cycle_time;
} }
} }
void Machine::register_callbacks() { void Machine::register_callbacks()
{
callback_manager->set_rom_load_callback(std::bind( callback_manager->set_rom_load_callback(std::bind(
&Machine::on_rom_load, &Machine::on_rom_load,
this, this,
@@ -70,7 +76,8 @@ void Machine::register_callbacks() {
)); ));
} }
void Machine::on_rom_load(const std::string& path) const { void Machine::on_rom_load(const std::string& path) const
{
std::ifstream file(path, std::ios::binary); std::ifstream file(path, std::ios::binary);
file.unsetf(std::ios::skipws); file.unsetf(std::ios::skipws);
@@ -80,7 +87,8 @@ void Machine::on_rom_load(const std::string& path) const {
// La memoria para los rom es desde 0x200 hasta el final de 0x1000 // La memoria para los rom es desde 0x200 hasta el final de 0x1000
// Por lo que un rom sería muy grande si sobrepasa este tamaño // Por lo que un rom sería muy grande si sobrepasa este tamaño
if (file_size >= 0x1000 - 0x200 ) { if (file_size >= 0x1000 - 0x200)
{
std::cout << "File too large!" << std::endl; std::cout << "File too large!" << std::endl;
return; return;
} }
@@ -95,6 +103,7 @@ void Machine::on_rom_load(const std::string& path) const {
std::cout << "Cargado rom: " << path << std::endl; std::cout << "Cargado rom: " << path << std::endl;
} }
void Machine::on_reset() const { void Machine::on_reset() const
{
this->machine_state->reset(); this->machine_state->reset();
} }

View File

@@ -7,7 +7,8 @@
#include "UI/Display.h" #include "UI/Display.h"
#include "UI/UIManager.h" #include "UI/UIManager.h"
class Machine { class Machine
{
std::shared_ptr<MachineState> machine_state; std::shared_ptr<MachineState> machine_state;
std::shared_ptr<Graphics> graphics; std::shared_ptr<Graphics> graphics;
std::shared_ptr<CallbackManager> callback_manager; std::shared_ptr<CallbackManager> callback_manager;
@@ -31,4 +32,4 @@ public:
bool on_event(const SDL_Event* event) const; bool on_event(const SDL_Event* event) const;
}; };
#endif //MACHINE_H #endif //MACHINE_H

View File

@@ -1,19 +1,27 @@
#include "CallbackManager.h" #include "CallbackManager.h"
void CallbackManager::set_rom_load_callback(const RomLoadCallback& callback) { void CallbackManager::set_rom_load_callback(const RomLoadCallback& callback)
{
this->rom_load_callback = callback; this->rom_load_callback = callback;
} }
void CallbackManager::set_reset_callback(const ResetCallback& callback) {
void CallbackManager::set_reset_callback(const ResetCallback& callback)
{
this->reset_callback = callback; this->reset_callback = callback;
} }
void CallbackManager::trigger_rom_load(const std::string& path) { void CallbackManager::trigger_rom_load(const std::string& path)
if (this->rom_load_callback) { {
if (this->rom_load_callback)
{
this->rom_load_callback(path); this->rom_load_callback(path);
} }
} }
void CallbackManager::trigger_reset() {
if (this->reset_callback) { void CallbackManager::trigger_reset()
{
if (this->reset_callback)
{
this->reset_callback(); this->reset_callback();
} }
} }

View File

@@ -5,8 +5,9 @@
#include <string> #include <string>
struct CallbackManager { struct CallbackManager
using RomLoadCallback = std::function<void(const std::string&)>; {
using RomLoadCallback = std::function<void(const std::string &)>;
using ResetCallback = std::function<void()>; using ResetCallback = std::function<void()>;
void set_rom_load_callback(const RomLoadCallback& callback); void set_rom_load_callback(const RomLoadCallback& callback);

View File

@@ -12,17 +12,23 @@ ControlPanel::ControlPanel(
std::shared_ptr<CallbackManager> callback_manager std::shared_ptr<CallbackManager> callback_manager
) : graphics{std::move(graphics)}, ) : graphics{std::move(graphics)},
machine_state{std::move(machine_state)}, machine_state{std::move(machine_state)},
callback_manager{std::move(callback_manager)} {} callback_manager{std::move(callback_manager)}
{
}
void ControlPanel::render() { void ControlPanel::render()
{
constexpr auto full_width = ImVec2(-FLT_MIN, 0.0f); constexpr auto full_width = ImVec2(-FLT_MIN, 0.0f);
if (ImGui::Begin("Chip-8 - Controls")) { if (ImGui::Begin("Chip-8 - Controls"))
if (ImGui::Button("Load Rom", full_width)) { {
if (ImGui::Button("Load Rom", full_width))
{
this->on_click_load_rom(); this->on_click_load_rom();
} }
if (ImGui::Button(run ? "Pause" : "Run", full_width)) { if (ImGui::Button(run ? "Pause" : "Run", full_width))
{
this->run = !run; this->run = !run;
} }
@@ -45,7 +51,8 @@ void ControlPanel::render() {
ImGui::SeparatorText(""); ImGui::SeparatorText("");
if (ImGui::Button("Reset", full_width)) { if (ImGui::Button("Reset", full_width))
{
this->callback_manager->trigger_reset(); this->callback_manager->trigger_reset();
} }
ImGui::Button("Reload ROM", full_width); ImGui::Button("Reload ROM", full_width);
@@ -54,7 +61,8 @@ void ControlPanel::render() {
ImGui::End(); ImGui::End();
} }
void ControlPanel::on_click_load_rom() { void ControlPanel::on_click_load_rom()
{
constexpr SDL_DialogFileFilter filters[] = { constexpr SDL_DialogFileFilter filters[] = {
{"CHIP8 ROMs", "ch8"}, {"CHIP8 ROMs", "ch8"},
{"All files", "*"} {"All files", "*"}
@@ -71,12 +79,14 @@ void ControlPanel::on_click_load_rom() {
); );
} }
void ControlPanel::on_callback_load_rom(void* self, const char* const* filelist, int filter) { void ControlPanel::on_callback_load_rom(void* self, const char* const* filelist, int filter)
{
const auto control_panel = static_cast<ControlPanel*>(self); const auto control_panel = static_cast<ControlPanel*>(self);
if (!filelist || !*filelist) { if (!filelist || !*filelist)
{
return; return;
} }
control_panel->callback_manager->trigger_rom_load(filelist[0]); control_panel->callback_manager->trigger_rom_load(filelist[0]);
} }

View File

@@ -9,7 +9,8 @@
#include "../Interpreter/MachineState.h" #include "../Interpreter/MachineState.h"
class ControlPanel { class ControlPanel
{
std::shared_ptr<Graphics> graphics; std::shared_ptr<Graphics> graphics;
std::shared_ptr<MachineState> machine_state; std::shared_ptr<MachineState> machine_state;
std::shared_ptr<CallbackManager> callback_manager; std::shared_ptr<CallbackManager> callback_manager;
@@ -32,4 +33,4 @@ public:
}; };
#endif //CONTROLPANEL_H #endif //CONTROLPANEL_H

View File

@@ -8,23 +8,29 @@
#include "imgui.h" #include "imgui.h"
#include "SDL3/SDL.h" #include "SDL3/SDL.h"
void SDLTextureDestroyer::operator()(SDL_Texture* texture) const { void SDLTextureDestroyer::operator()(SDL_Texture* texture) const
{
SDL_DestroyTexture(texture); SDL_DestroyTexture(texture);
} }
Display::Display(std::shared_ptr<Graphics> graphics, std::shared_ptr<MachineState> machine_state): Display::Display(std::shared_ptr<Graphics> graphics, std::shared_ptr<MachineState> machine_state) :
graphics{std::move(graphics)}, graphics{std::move(graphics)},
machine_state{std::move(machine_state)}, machine_state{std::move(machine_state)},
width(64), width(64),
height(32), height(32),
background_color{0x00, 0x2b, 0x59}, background_color{0x00, 0x2b, 0x59},
foreground_color(0x00, 0xb9, 0xbe), foreground_color(0x00, 0xb9, 0xbe),
texture{create_texture()} {} texture{create_texture()}
{
}
std::unique_ptr<SDL_Texture, SDLTextureDestroyer> Display::create_texture() const { std::unique_ptr<SDL_Texture, SDLTextureDestroyer> Display::create_texture() const
SDL_Texture* raw_texture = SDL_CreateTexture(this->graphics->get_renderer().get(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, width, height); {
SDL_Texture* raw_texture = SDL_CreateTexture(this->graphics->get_renderer().get(), SDL_PIXELFORMAT_RGBA8888,
SDL_TEXTUREACCESS_STREAMING, width, height);
if (!raw_texture) { if (!raw_texture)
{
throw std::runtime_error(std::format("Couldn't create texture: {}", SDL_GetError())); throw std::runtime_error(std::format("Couldn't create texture: {}", SDL_GetError()));
} }
@@ -33,16 +39,19 @@ std::unique_ptr<SDL_Texture, SDLTextureDestroyer> Display::create_texture() cons
return std::unique_ptr<SDL_Texture, SDLTextureDestroyer>(raw_texture); return std::unique_ptr<SDL_Texture, SDLTextureDestroyer>(raw_texture);
} }
void Display::render() const { void Display::render() const
{
update_texture(); update_texture();
display_widget(); display_widget();
} }
void Display::update_texture() const { void Display::update_texture() const
{
SDL_Surface* surface = nullptr; SDL_Surface* surface = nullptr;
const auto& display = machine_state->display; const auto& display = machine_state->display;
if (SDL_LockTextureToSurface(this->texture.get(), nullptr, &surface)) { if (SDL_LockTextureToSurface(this->texture.get(), nullptr, &surface))
{
SDL_FillSurfaceRect( SDL_FillSurfaceRect(
surface, surface,
nullptr, nullptr,
@@ -55,8 +64,10 @@ void Display::update_texture() const {
) )
); );
for (int i = 0; i < display.size(); i++) { for (int i = 0; i < display.size(); i++)
if (display[i]) { {
if (display[i])
{
const int x = (i % this->width); const int x = (i % this->width);
const int y = (i / this->width); const int y = (i / this->width);
@@ -73,12 +84,15 @@ void Display::update_texture() const {
} }
} }
SDL_UnlockTexture(this->texture.get()); SDL_UnlockTexture(this->texture.get());
} else { }
else
{
throw std::runtime_error(std::format("Couldn't get texture lock onto surface: {}", SDL_GetError())); throw std::runtime_error(std::format("Couldn't get texture lock onto surface: {}", SDL_GetError()));
} }
} }
void Display::display_widget() const { void Display::display_widget() const
{
ImGui::Begin("CHIP-8 - Display"); ImGui::Begin("CHIP-8 - Display");
const ImVec2 available_size = ImGui::GetContentRegionAvail(); const ImVec2 available_size = ImGui::GetContentRegionAvail();
@@ -94,4 +108,4 @@ void Display::display_widget() const {
ImGui::Image(static_cast<ImTextureID>(reinterpret_cast<intptr_t>(texture.get())), scaled_size); ImGui::Image(static_cast<ImTextureID>(reinterpret_cast<intptr_t>(texture.get())), scaled_size);
ImGui::End(); ImGui::End();
} }

View File

@@ -7,11 +7,13 @@
#include "../Interpreter/MachineState.h" #include "../Interpreter/MachineState.h"
#include "SDL3/SDL.h" #include "SDL3/SDL.h"
struct SDLTextureDestroyer { struct SDLTextureDestroyer
{
void operator()(SDL_Texture* texture) const; void operator()(SDL_Texture* texture) const;
}; };
class Display { class Display
{
std::shared_ptr<Graphics> graphics; std::shared_ptr<Graphics> graphics;
std::shared_ptr<MachineState> machine_state; std::shared_ptr<MachineState> machine_state;
@@ -37,4 +39,4 @@ public:
}; };
#endif //DISPLAY_H #endif //DISPLAY_H

View File

@@ -9,9 +9,12 @@ UIManager::UIManager(
machine_state{std::move(machine_state)}, machine_state{std::move(machine_state)},
callback_manager{std::move(callback_manager)}, callback_manager{std::move(callback_manager)},
display{std::make_unique<Display>(this->graphics, this->machine_state)}, display{std::make_unique<Display>(this->graphics, this->machine_state)},
control_panel{std::make_unique<ControlPanel>(this->graphics, this->machine_state, this->callback_manager)} {} control_panel{std::make_unique<ControlPanel>(this->graphics, this->machine_state, this->callback_manager)}
{
}
void UIManager::render() { void UIManager::render()
{
this->display->render(); this->display->render();
this->control_panel->render(); this->control_panel->render();
} }

View File

@@ -7,7 +7,8 @@
#include "Display.h" #include "Display.h"
#include "../Graphics/Graphics.h" #include "../Graphics/Graphics.h"
class UIManager { class UIManager
{
std::shared_ptr<Graphics> graphics; std::shared_ptr<Graphics> graphics;
std::shared_ptr<MachineState> machine_state; std::shared_ptr<MachineState> machine_state;
std::shared_ptr<CallbackManager> callback_manager; std::shared_ptr<CallbackManager> callback_manager;
@@ -22,7 +23,7 @@ public:
std::shared_ptr<CallbackManager> callback_manager std::shared_ptr<CallbackManager> callback_manager
); );
void render() ; void render();
}; };
#endif //UIMANAGER_H #endif //UIMANAGER_H

View File

@@ -4,14 +4,16 @@
#include <memory> #include <memory>
#include "Machine.h" #include "Machine.h"
SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) { SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[])
{
auto machine = std::make_unique<Machine>(); auto machine = std::make_unique<Machine>();
*appstate = machine.release(); *appstate = machine.release();
return SDL_APP_CONTINUE; return SDL_APP_CONTINUE;
} }
SDL_AppResult SDL_AppIterate(void* appstate) { SDL_AppResult SDL_AppIterate(void* appstate)
{
const auto machine = static_cast<Machine*>(appstate); const auto machine = static_cast<Machine*>(appstate);
machine->iterate(); machine->iterate();
@@ -19,16 +21,19 @@ SDL_AppResult SDL_AppIterate(void* appstate) {
return SDL_APP_CONTINUE; return SDL_APP_CONTINUE;
} }
SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) { SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
{
const auto machine = static_cast<Machine*>(appstate); const auto machine = static_cast<Machine*>(appstate);
if (!machine->on_event(event)) { if (!machine->on_event(event))
{
return SDL_APP_SUCCESS; return SDL_APP_SUCCESS;
} }
return SDL_APP_CONTINUE; return SDL_APP_CONTINUE;
} }
void SDL_AppQuit(void* appstate, SDL_AppResult result) { void SDL_AppQuit(void* appstate, SDL_AppResult result)
{
std::unique_ptr<Machine> chip8(static_cast<Machine*>(appstate)); std::unique_ptr<Machine> chip8(static_cast<Machine*>(appstate));
} }