diff options
author | Raghuram Subramani <raghus2247@gmail.com> | 2023-10-21 15:59:54 +0530 |
---|---|---|
committer | Raghuram Subramani <raghus2247@gmail.com> | 2023-10-21 21:57:47 +0530 |
commit | 6f5020bb6c198e475982e207179605b314b1afbe (patch) | |
tree | d1350c1f423c56ed034ec5e66ba46ac8c4b20833 | |
parent | 6b9606398e8f466dc3f0aa60596a3a574f7af57e (diff) |
Initial code
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | CMakeLists.txt | 12 | ||||
-rw-r--r-- | src/chip8.cpp | 520 | ||||
-rw-r--r-- | src/chip8.hpp | 69 | ||||
-rw-r--r-- | src/main.cpp | 40 | ||||
-rw-r--r-- | src/platform.cpp | 80 | ||||
-rw-r--r-- | src/platform.hpp | 24 |
7 files changed, 748 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f54ec33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +compile_commands.json +build/ +.ccls-cache/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..101d22f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.12) +project(chip8emu) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +find_package(SDL2 REQUIRED) + +include_directories(src) +file(GLOB SOURCES src/*.cpp) +add_executable(chip8emu ${SOURCES}) + +# Link SDL2 library +target_link_libraries(chip8emu PRIVATE SDL2::SDL2) diff --git a/src/chip8.cpp b/src/chip8.cpp new file mode 100644 index 0000000..94573f0 --- /dev/null +++ b/src/chip8.cpp @@ -0,0 +1,520 @@ +#include "chip8.hpp" + +#include <fstream> +#include <iostream> +#include <cstdint> +#include <chrono> + +const uint32_t FONTSET_START_ADDRESS = 0x050; +const uint32_t ROM_START_ADDRESS = 0x200; + +const uint32_t FONTSET_SIZE = 0x0a0 - FONTSET_START_ADDRESS; + +uint8_t fontset[FONTSET_SIZE] = { + 0xF0, 0x90, 0x90, 0x90, 0xF0, // 0 + 0x20, 0x60, 0x20, 0x20, 0x70, // 1 + 0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2 + 0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3 + 0x90, 0x90, 0xF0, 0x10, 0x10, // 4 + 0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5 + 0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6 + 0xF0, 0x10, 0x20, 0x40, 0x40, // 7 + 0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8 + 0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9 + 0xF0, 0x90, 0xF0, 0x90, 0x90, // A + 0xE0, 0x90, 0xE0, 0x90, 0xE0, // B + 0xF0, 0x80, 0x80, 0x80, 0xF0, // C + 0xE0, 0x90, 0x90, 0x90, 0xE0, // D + 0xF0, 0x80, 0xF0, 0x80, 0xF0, // E + 0xF0, 0x80, 0xF0, 0x80, 0x80 // F +}; + +Chip8::Chip8() { + pc = ROM_START_ADDRESS; + + for (uint32_t i = 0; i < FONTSET_SIZE; i++) { + memory[FONTSET_START_ADDRESS + i] = fontset[i]; + } + + randGen = std::default_random_engine( + std::chrono::system_clock::now() + .time_since_epoch() + .count() + ); + randByte = std::uniform_int_distribution<uint8_t>(0, 255U); + + SetupTable(); +} + +void Chip8::SetupTable() { + for (size_t i = 0; i <= sizeof(table0) / sizeof(table0[0]); i++) { + table0[i] = &Chip8::OP_NULL; + table8[i] = &Chip8::OP_NULL; + tableE[i] = &Chip8::OP_NULL; + } + + for (size_t i = 0; i <= sizeof(tableF) / sizeof(tableF[0]); i++) { + tableF[i] = &Chip8::OP_NULL; + } + + table[0x0] = &Chip8::Table0; + table[0x1] = &Chip8::OP_1nnn; + table[0x2] = &Chip8::OP_2nnn; + table[0x3] = &Chip8::OP_3xkk; + table[0x4] = &Chip8::OP_4xkk; + table[0x5] = &Chip8::OP_5xy0; + table[0x6] = &Chip8::OP_6xkk; + table[0x7] = &Chip8::OP_7xkk; + table[0x8] = &Chip8::Table8; + table[0x9] = &Chip8::OP_9xy0; + table[0xA] = &Chip8::OP_Annn; + table[0xB] = &Chip8::OP_Bnnn; + table[0xC] = &Chip8::OP_Cxkk; + table[0xD] = &Chip8::OP_Dxyn; + table[0xE] = &Chip8::TableE; + table[0xF] = &Chip8::TableF; + + table0[0x0] = &Chip8::OP_00E0; + table0[0xE] = &Chip8::OP_00EE; + + table8[0x0] = &Chip8::OP_8xy0; + table8[0x1] = &Chip8::OP_8xy1; + table8[0x2] = &Chip8::OP_8xy2; + table8[0x3] = &Chip8::OP_8xy3; + table8[0x4] = &Chip8::OP_8xy4; + table8[0x5] = &Chip8::OP_8xy5; + table8[0x6] = &Chip8::OP_8xy6; + table8[0x7] = &Chip8::OP_8xy7; + table8[0xE] = &Chip8::OP_8xyE; + + tableE[0x1] = &Chip8::OP_ExA1; + tableE[0xE] = &Chip8::OP_Ex9E; + + tableF[0x07] = &Chip8::OP_Fx07; + tableF[0x0A] = &Chip8::OP_Fx0A; + tableF[0x15] = &Chip8::OP_Fx15; + tableF[0x18] = &Chip8::OP_Fx18; + tableF[0x1E] = &Chip8::OP_Fx1E; + tableF[0x29] = &Chip8::OP_Fx29; + tableF[0x33] = &Chip8::OP_Fx33; + tableF[0x55] = &Chip8::OP_Fx55; + tableF[0x65] = &Chip8::OP_Fx65; +} + +void Chip8::Table0() { + ((*this).*(table0[opcode & 0x000Fu]))(); +} + +void Chip8::Table8() { + ((*this).*(table8[opcode & 0x000Fu]))(); +} + +void Chip8::TableE() { + ((*this).*(tableE[opcode & 0x000Fu]))(); +} + +void Chip8::TableF() { + ((*this).*(tableF[opcode & 0x00FFu]))(); +} + +void Chip8::Cycle() { + // Fetch + opcode = (memory[pc] << 8u) | memory[pc + 1]; + pc += 2; + + // Decode and Execute + ((*this).*(table[(opcode & 0xF000u) >> 12u]))(); + + // Decrement delay timer + if (delayTimer > 0) { + delayTimer--; + } + + if (soundTimer > 0) { + --soundTimer; + } +} + +void Chip8::LoadROM(const char* filename) { + // Open file as binary stream and seek to the end + std::ifstream file(filename, std::ios::binary | std::ios::ate); + + if (file.is_open()) { + // Get file size + std::streampos size = file.tellg(); + // Allocate buffer + char* buffer = new char[size]; + + // Seek to the beginning + file.seekg(0, std::ios::beg); + // Populate the buffer + file.read(buffer, size); + file.close(); + + // Load ROM contents into Chip8's memory, from 0x200 + for (uint64_t i = 0; i < size; i++) { + memory[ROM_START_ADDRESS + i] = buffer[i]; + } + + // Free the buffer + delete[] buffer; + } +} + +// NULL: NOP +// Do nothing +void Chip8::OP_NULL() {} + +// 00E0: CLS +// Clear the display +void Chip8::OP_00E0() { + for (uint32_t i = 0; i < sizeof(video) / sizeof(video[0]); i++) { + video[i] = 0; + } +}; + +// 00EE: RET +// Return from a subroutine +void Chip8::OP_00EE() { + sp--; + pc = stack[sp]; +} + +// 1nnn: JP addr +// Jump to location nnn +void Chip8::OP_1nnn() { + uint16_t address = opcode & 0x0FFFu; + pc = address; +} + +// 2nnn: CALL addr +// Call subroutine at nnn +void Chip8::OP_2nnn() { + uint16_t address = opcode & 0x0FFFu; + stack[sp] = pc; + sp++; + pc = address; +} + +// 3xkk: SE Vx, byte +// Skip next instruction if Vx = kk +void Chip8::OP_3xkk() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + uint8_t byte = opcode & 0x00FFu; + + if (registers[Vx] == byte) + pc += 2; +} + +// 4xkk: SNE Vx, byte +// Skip next instruction if Vx != kk +void Chip8::OP_4xkk() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + uint8_t byte = opcode & 0x00FFu; + + if (registers[Vx] != byte) + pc += 2; +} + +// 5xy0: SE Vx, Vy +// Skip next instruction if Vx == Vy +void Chip8::OP_5xy0() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + uint8_t Vy = (opcode & 0x00FFu) >> 4u; + + if (registers[Vx] == registers[Vy]) + pc += 2; +} + +// 6xkk: LD Vx, byte +// Set Vx = kk +void Chip8::OP_6xkk() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + uint8_t byte = opcode & 0x00FFu; + + registers[Vx] = byte; +} + +// 7xkk: ADD Vx, byte +// Set Vx += kk +void Chip8::OP_7xkk() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + uint8_t byte = opcode & 0x00FFu; + + registers[Vx] += byte; +} + +// 8xy0: LD Vx, Vy +// Set Vx = Vy +void Chip8::OP_8xy0() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + uint8_t Vy = (opcode & 0x00FFu) >> 4u; + + registers[Vx] = registers[Vy]; +} + +// 8xy1: OR Vx, Vy +// Set Vx = Vx OR Vy +void Chip8::OP_8xy1() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + uint8_t Vy = (opcode & 0x00FFu) >> 4u; + + registers[Vx] |= registers[Vy]; +} + +// 8xy2: AND Vx, Vy +// Set Vx = Vx AND Vy +void Chip8::OP_8xy2() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + uint8_t Vy = (opcode & 0x00FFu) >> 4u; + + registers[Vx] &= registers[Vy]; +} + +// 8xy3: XOR Vx, Vy +// Set Vx = Vx XOR Vy +void Chip8::OP_8xy3() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + uint8_t Vy = (opcode & 0x00FFu) >> 4u; + + registers[Vx] ^= registers[Vy]; +} + +// 8xy4: ADD Vx, Vy +// Set Vx += Vy, set VF = carry +void Chip8::OP_8xy4() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + uint8_t Vy = (opcode & 0x00FFu) >> 4u; + + uint16_t sum = registers[Vx] + registers[Vy]; + + if (sum > 255u) { + registers[0xF] = 1; + } else { + registers[0xF] = 0; + } + + registers[Vx] = sum & 0xFFu; +} + +// 8xy5: SUB Vx, Vy +// Set Vx -= Vy, set VF = NOT borrow +void Chip8::OP_8xy5() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + uint8_t Vy = (opcode & 0x00FFu) >> 4u; + + if (registers[Vx] > registers[Vy]) { + registers[0xF] = 1; + } else { + registers[0xF] = 0; + } + + registers[Vx] -= registers[Vy]; +} + +// 8xy6: SHR Vx +// Set Vx = Vx SHR 1 +void Chip8::OP_8xy6() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + + // Save LSB in VF + registers[0xF] = (registers[Vx] & 0x1u); + + registers[Vx] >>= 1; +} + +// 8xy7: SUBN Vx, Vy +// Set Vy -= Vx, set VF = NOT borrow +void Chip8::OP_8xy7() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + uint8_t Vy = (opcode & 0x00FFu) >> 4u; + + if (registers[Vy] > registers[Vx]) { + registers[0xF] = 1; + } else { + registers[0xF] = 0; + } + + registers[Vx] = registers[Vy] - registers[Vx]; +} + +// 8xyE: SHL Vx +// Set Vx = Vx SHL 1 +void Chip8::OP_8xyE() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + + // Save LSB in VF + registers[0xF] = (registers[Vx] & 0x80u) >> 7u; + + registers[Vx] <<= 1; +} + +// 9xy0: SNE Vx, Vy +// Skip next instruction if Vx != Vy +void Chip8::OP_9xy0() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + uint8_t Vy = (opcode & 0x00FFu) >> 4u; + + if (registers[Vx] != registers[Vy]) + pc += 2; +} + +// Annn: LD I, addr +// Set I = nnn +void Chip8::OP_Annn() { + uint16_t address = opcode & 0x0FFFu; + index = address; +} + +// Bnnn: JP V0, addr +// Jump to location nnn + V0 +void Chip8::OP_Bnnn() { + uint16_t address = opcode & 0x0FFFu; + pc = registers[0x0] + address; +} + +// Cxkk: RND Vx, byte +// Set Vx = random byte AND kk +void Chip8::OP_Cxkk() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + uint8_t byte = opcode & 0x00FFu; + + registers[Vx] = randByte(randGen) & byte; +} + +// Dxyn: DRW Vx, Vy, nibble +// Display n-byte sprite starting at memory location I at (Vx, Vy), set VF = collision +void Chip8::OP_Dxyn() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + uint8_t Vy = (opcode & 0x00FFu) >> 4u; + uint8_t height = opcode & 0x000Fu; + + // Wrap if going beyond screen boundaries + uint8_t xPos = registers[Vx] % VIDEO_WIDTH; + uint8_t yPos = registers[Vy] % VIDEO_HEIGHT; + + registers[0xF] = 0; + + for (uint32_t row = 0; row < height; ++row) { + uint8_t spriteByte = memory[index + row]; + for (uint32_t col = 0; col < 8; ++col) { + uint8_t spritePixel = spriteByte & (0x80u >> col); + uint32_t* screenPixel = &video[(yPos + row) * VIDEO_WIDTH + (xPos + col)]; + + if (spritePixel) { + if(*screenPixel == 0xFFFFFFFF) + registers[0xF] = 1; + *screenPixel ^= 0xFFFFFFFF; + } + } + } +} + +// Ex9E: SKP Vx +// Skip next instruction if key with the value of Vx is pressed +void Chip8::OP_Ex9E() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + uint8_t key = registers[Vx]; + + if (keypad[key]) + pc += 2; +} + +// ExA1: SKNP Vx +// Skip next instruction if key with the value of Vx is not pressed +void Chip8::OP_ExA1() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + uint8_t key = registers[Vx]; + + if (!keypad[key]) + pc += 2; +} + +// Fx07: LD Vx, DT +// Set Vx = delay timer value +void Chip8::OP_Fx07() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + registers[Vx] = delayTimer; +} + +// Fx0A: LD Vx, K +// Wait for a key press, store the value of the key in Vx +void Chip8::OP_Fx0A() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + for (uint16_t i = 0; i < 16; i++) { + if (keypad[i]) { + registers[Vx] = static_cast<uint8_t>(i); + return; + } + } + + pc -= 2; +} + +// Fx15: LD DT, Vx +// Set delay timer value = Vx +void Chip8::OP_Fx15() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + delayTimer = registers[Vx]; +} + +// Fx18: LD ST, Vx +// Set sound timer value = Vx +void Chip8::OP_Fx18() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + soundTimer = registers[Vx]; +} + +// Fx1E: ADD I, Vx +// Set I += Vx +void Chip8::OP_Fx1E() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + index += registers[Vx]; +} + +// Fx29: LD F, Vx +// Set I = location of sprite for digit Vx +void Chip8::OP_Fx29() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + uint8_t digit = registers[Vx]; + + index = FONTSET_START_ADDRESS + (5 * digit); +} + +// Fx33: LD B, Vx +// Store BCD representation of Vx in memory locations I, I+1, and I+2 +void Chip8::OP_Fx33() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + uint8_t value = registers[Vx]; + + // Ones-place + memory[index + 2] = value % 10; + value /= 10; + + // Tens-place + memory[index + 1] = value % 10; + value /= 10; + + // Hundreds-place + memory[index] = value % 10; +} + +// Fx55: LD [I], Vx +// Store registers V0 through Vx in memory starting at location I +void Chip8::OP_Fx55() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + + for (uint8_t i = 0; i <= Vx; ++i) { + memory[index + i] = registers[i]; + } +} + +// Fx65: LD Vx, [I] +// Read registers V0 through Vx in memory starting at location I +void Chip8::OP_Fx65() { + uint8_t Vx = (opcode & 0x0F00u) >> 8u; + + for (uint8_t i = 0; i <= Vx; ++i) { + registers[i] = memory[index + i]; + } +} diff --git a/src/chip8.hpp b/src/chip8.hpp new file mode 100644 index 0000000..f144341 --- /dev/null +++ b/src/chip8.hpp @@ -0,0 +1,69 @@ +#ifndef CHIP8_H_ +#define CHIP8_H_ + +#include <cstdint> +#include <random> + +const uint32_t VIDEO_HEIGHT = 32; +const uint32_t VIDEO_WIDTH = 64; + +class Chip8 { + public: + Chip8(); + + public: + uint8_t registers[16] {}; + uint8_t memory[4096] {}; + + uint16_t index {}; + uint16_t pc {}; + uint16_t stack[16] {}; + uint8_t sp {}; + + uint8_t delayTimer {}; + uint8_t soundTimer {}; + + uint8_t keypad[16] {}; + uint32_t video[VIDEO_WIDTH * VIDEO_HEIGHT] {}; + + uint16_t opcode; + + private: + std::default_random_engine randGen; + std::uniform_int_distribution<uint8_t> randByte; + + public: + void LoadROM(const char* filename); + void SetupTable(); + + public: + void Cycle(); + + public: + typedef void (Chip8::*OpcodeFunction)(); + OpcodeFunction table[0x10u]; + OpcodeFunction table0[0xFu]; + OpcodeFunction table8[0xFu]; + OpcodeFunction tableE[0xFu]; + OpcodeFunction tableF[0x65u]; + + void Table0(); + void Table8(); + void TableE(); + void TableF(); + + void OP_NULL(); void OP_00E0(); void OP_00EE(); + void OP_1nnn(); void OP_2nnn(); void OP_3xkk(); + void OP_4xkk(); void OP_5xy0(); void OP_6xkk(); + void OP_7xkk(); void OP_8xy0(); void OP_8xy1(); + void OP_8xy2(); void OP_8xy3(); void OP_8xy4(); + void OP_8xy5(); void OP_8xy6(); void OP_8xy7(); + void OP_8xyE(); void OP_9xy0(); void OP_Annn(); + void OP_Bnnn(); void OP_Cxkk(); void OP_Dxyn(); + void OP_Ex9E(); void OP_ExA1(); void OP_Fx07(); + void OP_Fx0A(); void OP_Fx15(); void OP_Fx18(); + void OP_Fx1E(); void OP_Fx29(); void OP_Fx33(); + void OP_Fx55(); void OP_Fx65(); +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..b5f12df --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,40 @@ +#include <iostream> +#include <unistd.h> + +#include "chip8.hpp" +#include "platform.hpp" + +int main(int argc, char** argv) { + if (argc != 4) { + std::cerr << "Usage: " << argv[0] << " <Scale> <Delay> <ROM>\n"; + std::exit(EXIT_FAILURE); + } + + int videoScale = std::stoi(argv[1]); + int cycleDelay = std::stoi(argv[2]); + char const* filename = argv[3]; + + Platform platform( + "chip8emu", + VIDEO_WIDTH * videoScale, + VIDEO_HEIGHT * videoScale, + VIDEO_WIDTH, VIDEO_HEIGHT + ); + + Chip8 chip8; + chip8.LoadROM(filename); + + int videoPitch = sizeof(chip8.video[0]) * VIDEO_WIDTH; + + bool quit = false; + while (!quit) { + quit = platform.ProcessInput(chip8.keypad); + + usleep(cycleDelay * 1000); + + chip8.Cycle(); + platform.Update(chip8.video, videoPitch); + } + + return 0; +} diff --git a/src/platform.cpp b/src/platform.cpp new file mode 100644 index 0000000..c7d9ab3 --- /dev/null +++ b/src/platform.cpp @@ -0,0 +1,80 @@ +#include "platform.hpp" + +Platform::Platform(const char* title, int windowWidth, int windowHeight, int textureWidth, int textureHeight) { + SDL_Init(SDL_INIT_VIDEO); + + window = SDL_CreateWindow(title, 0, 0, windowWidth, windowHeight, SDL_WINDOW_SHOWN); + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, textureWidth, textureHeight); +} + +Platform::~Platform() { + SDL_DestroyTexture(texture); + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); + SDL_Quit(); +} + +void Platform::Update(const void* buffer, int pitch) { + SDL_UpdateTexture(texture, nullptr, buffer, pitch); + SDL_RenderClear(renderer); + SDL_RenderCopy(renderer, texture, nullptr, nullptr); + SDL_RenderPresent(renderer); +} + +bool Platform::ProcessInput(uint8_t* keys) { + bool quit = false; + + SDL_Event event; + + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + quit = true; + break; + + case SDL_KEYDOWN: + switch (event.key.keysym.sym) { + case SDLK_ESCAPE: quit = true; + case SDLK_x: keys[0x0] = 1; break; + case SDLK_1: keys[0x1] = 1; break; + case SDLK_2: keys[0x2] = 1; break; + case SDLK_3: keys[0x3] = 1; break; + case SDLK_q: keys[0x4] = 1; break; + case SDLK_w: keys[0x5] = 1; break; + case SDLK_e: keys[0x6] = 1; break; + case SDLK_a: keys[0x7] = 1; break; + case SDLK_s: keys[0x8] = 1; break; + case SDLK_d: keys[0x9] = 1; break; + case SDLK_z: keys[0xA] = 1; break; + case SDLK_c: keys[0xB] = 1; break; + case SDLK_4: keys[0xC] = 1; break; + case SDLK_r: keys[0xD] = 1; break; + case SDLK_f: keys[0xE] = 1; break; + case SDLK_v: keys[0xF] = 1; break; + } break; + + case SDL_KEYUP: + switch (event.key.keysym.sym) { + case SDLK_x: keys[0x0] = 0; break; + case SDLK_1: keys[0x1] = 0; break; + case SDLK_2: keys[0x2] = 0; break; + case SDLK_3: keys[0x3] = 0; break; + case SDLK_q: keys[0x4] = 0; break; + case SDLK_w: keys[0x5] = 0; break; + case SDLK_e: keys[0x6] = 0; break; + case SDLK_a: keys[0x7] = 0; break; + case SDLK_s: keys[0x8] = 0; break; + case SDLK_d: keys[0x9] = 0; break; + case SDLK_z: keys[0xA] = 0; break; + case SDLK_c: keys[0xB] = 0; break; + case SDLK_4: keys[0xC] = 0; break; + case SDLK_r: keys[0xD] = 0; break; + case SDLK_f: keys[0xE] = 0; break; + case SDLK_v: keys[0xF] = 0; break; + } + } + } + + return quit; +} diff --git a/src/platform.hpp b/src/platform.hpp new file mode 100644 index 0000000..55b91df --- /dev/null +++ b/src/platform.hpp @@ -0,0 +1,24 @@ +#ifndef PLATFORM_HPP_ +#define PLATFORM_HPP_ + +#include <cstdint> +#include <SDL.h> + +class Platform { + public: + Platform( + const char* title, int windowWidth, int windowHeight, int textureWidth, int textureHeight + ); + ~Platform(); + + public: + void Update(const void* buffer, int pitch); + bool ProcessInput(uint8_t* keys); + + private: + SDL_Window* window {}; + SDL_Renderer* renderer {}; + SDL_Texture* texture {}; +}; + +#endif |