2021-03-08 01:05:41 +02:00
|
|
|
#include <SDL2/SDL.h>
|
2021-03-09 14:41:16 +02:00
|
|
|
#include <SDL2/SDL_mixer.h>
|
2021-03-08 01:05:41 +02:00
|
|
|
|
|
|
|
|
#include "chip8.h"
|
|
|
|
|
#include "version.h"
|
|
|
|
|
|
|
|
|
|
#include <fstream>
|
|
|
|
|
|
2021-03-09 14:41:16 +02:00
|
|
|
constexpr uint32_t ON_COLOR = 0xFFFFFFFF;
|
|
|
|
|
constexpr uint32_t OFF_COLOR = 0x000000FF;
|
|
|
|
|
|
|
|
|
|
void poll_events(SDL_Window *window, bool *running, Chip8 &chip8) {
|
2021-03-08 01:05:41 +02:00
|
|
|
SDL_Event ev;
|
|
|
|
|
|
|
|
|
|
while (SDL_PollEvent(&ev)) {
|
|
|
|
|
switch (ev.type) {
|
|
|
|
|
case SDL_QUIT:
|
|
|
|
|
*running = false;
|
|
|
|
|
break;
|
|
|
|
|
case SDL_KEYDOWN:
|
|
|
|
|
switch (ev.key.keysym.sym) {
|
|
|
|
|
case SDLK_ESCAPE:
|
|
|
|
|
*running = false;
|
|
|
|
|
break;
|
2021-03-09 14:41:16 +02:00
|
|
|
case SDLK_1:
|
|
|
|
|
chip8.keys[0] = true;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_2:
|
|
|
|
|
chip8.keys[1] = true;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_3:
|
|
|
|
|
chip8.keys[2] = true;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_4:
|
|
|
|
|
chip8.keys[3] = true;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_q:
|
|
|
|
|
chip8.keys[4] = true;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_w:
|
|
|
|
|
chip8.keys[5] = true;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_e:
|
|
|
|
|
chip8.keys[6] = true;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_r:
|
|
|
|
|
chip8.keys[7] = true;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_a:
|
|
|
|
|
chip8.keys[8] = true;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_s:
|
|
|
|
|
chip8.keys[9] = true;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_d:
|
|
|
|
|
chip8.keys[0xA] = true;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_f:
|
|
|
|
|
chip8.keys[0xB] = true;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_z:
|
|
|
|
|
chip8.keys[0xC] = true;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_x:
|
|
|
|
|
chip8.keys[0xD] = true;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_c:
|
|
|
|
|
chip8.keys[0xE] = true;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_v:
|
|
|
|
|
chip8.keys[0xF] = true;
|
|
|
|
|
break;
|
2021-03-08 01:05:41 +02:00
|
|
|
}
|
|
|
|
|
break;
|
2021-03-09 14:41:16 +02:00
|
|
|
case SDL_KEYUP:
|
|
|
|
|
switch (ev.key.keysym.sym) {
|
|
|
|
|
case SDLK_1:
|
|
|
|
|
chip8.keys[0] = false;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_2:
|
|
|
|
|
chip8.keys[1] = false;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_3:
|
|
|
|
|
chip8.keys[2] = false;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_4:
|
|
|
|
|
chip8.keys[3] = false;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_q:
|
|
|
|
|
chip8.keys[4] = false;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_w:
|
|
|
|
|
chip8.keys[5] = false;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_e:
|
|
|
|
|
chip8.keys[6] = false;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_r:
|
|
|
|
|
chip8.keys[7] = false;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_a:
|
|
|
|
|
chip8.keys[8] = false;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_s:
|
|
|
|
|
chip8.keys[9] = false;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_d:
|
|
|
|
|
chip8.keys[0xA] = false;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_f:
|
|
|
|
|
chip8.keys[0xB] = false;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_z:
|
|
|
|
|
chip8.keys[0xC] = false;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_x:
|
|
|
|
|
chip8.keys[0xD] = false;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_c:
|
|
|
|
|
chip8.keys[0xE] = false;
|
|
|
|
|
break;
|
|
|
|
|
case SDLK_v:
|
|
|
|
|
chip8.keys[0xF] = false;
|
2021-03-08 01:05:41 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2021-03-09 14:41:16 +02:00
|
|
|
break;
|
2021-03-08 01:05:41 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-09 14:41:16 +02:00
|
|
|
void emulate(Chip8 &chip8, SDL_Window *window, Mix_Music *beep) {
|
2021-03-08 01:05:41 +02:00
|
|
|
const uint8_t first_byte = chip8.memory[chip8.PC];
|
|
|
|
|
const uint8_t second_byte = chip8.memory[chip8.PC + 1];
|
|
|
|
|
const uint16_t opcode = first_byte << 8 | second_byte;
|
|
|
|
|
|
2021-03-09 14:41:16 +02:00
|
|
|
if (chip8.delay_timer > 0) {
|
|
|
|
|
// decrement at 60hz
|
|
|
|
|
chip8.delay_timer--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (chip8.sound_timer > 0) {
|
|
|
|
|
// decrement at 60hz
|
|
|
|
|
// play sound
|
|
|
|
|
Mix_PlayMusic(beep, 1);
|
|
|
|
|
chip8.sound_timer--;
|
|
|
|
|
}
|
2021-03-08 01:05:41 +02:00
|
|
|
|
|
|
|
|
switch (first_byte >> 4) {
|
|
|
|
|
case 0x0:
|
|
|
|
|
switch (second_byte) {
|
|
|
|
|
case 0xE0: {
|
|
|
|
|
// clear the screen with a black color
|
|
|
|
|
std::fill_n(chip8.pixels, 64 * 32, OFF_COLOR);
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 0xEE:
|
|
|
|
|
// return from a subroutine
|
|
|
|
|
chip8.SP--;
|
|
|
|
|
chip8.PC = chip8.stack[chip8.SP];
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 0x1:
|
|
|
|
|
chip8.PC = ((first_byte & 0x0F) << 8) | second_byte;
|
|
|
|
|
break;
|
|
|
|
|
case 0x2:
|
|
|
|
|
// CALL subroutine
|
|
|
|
|
chip8.stack[chip8.SP] = chip8.PC;
|
|
|
|
|
chip8.SP = (chip8.SP + 1);
|
|
|
|
|
chip8.PC = ((first_byte & 0x0F) << 8) | second_byte;
|
|
|
|
|
break;
|
|
|
|
|
case 0x3:
|
|
|
|
|
if (chip8.V[first_byte & 0x0F] == second_byte) {
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
}
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
break;
|
|
|
|
|
case 0x4:
|
|
|
|
|
if (chip8.V[first_byte & 0x0F] != second_byte) {
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
}
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
break;
|
|
|
|
|
case 0x5:
|
|
|
|
|
if (chip8.V[first_byte & 0x0F] == chip8.V[(second_byte & 0xF0) >> 4]) {
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
}
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
break;
|
|
|
|
|
case 0x6:
|
|
|
|
|
chip8.V[first_byte & 0x0F] = second_byte;
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
break;
|
|
|
|
|
case 0x7:
|
|
|
|
|
chip8.V[first_byte & 0x0F] = chip8.V[first_byte & 0x0F] + second_byte;
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
break;
|
|
|
|
|
case 0x8:
|
|
|
|
|
switch (second_byte & 0x0F) {
|
|
|
|
|
case 0x0:
|
|
|
|
|
chip8.V[first_byte & 0x0F] = chip8.V[(second_byte & 0xF0) >> 4];
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
break;
|
|
|
|
|
case 0x1:
|
|
|
|
|
chip8.V[first_byte & 0x0F] = chip8.V[first_byte & 0x0F] | chip8.V[(second_byte & 0xF0) >> 4];
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
break;
|
|
|
|
|
case 0x2:
|
|
|
|
|
chip8.V[first_byte & 0x0F] = chip8.V[first_byte & 0x0F] & chip8.V[(second_byte & 0xF0) >> 4];
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
break;
|
|
|
|
|
case 0x3:
|
|
|
|
|
chip8.V[first_byte & 0x0F] = chip8.V[first_byte & 0x0F] ^ chip8.V[(second_byte & 0xF0) >> 4];
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
break;
|
|
|
|
|
case 0x4:
|
|
|
|
|
if ((chip8.V[first_byte & 0x0F] + chip8.V[(second_byte & 0xF0) >> 4]) > 0xFF) {
|
|
|
|
|
chip8.V[0xF] = 1;
|
|
|
|
|
} else {
|
|
|
|
|
chip8.V[0xF] = 0;
|
|
|
|
|
}
|
|
|
|
|
chip8.V[first_byte & 0x0F] = chip8.V[first_byte & 0x0F] + chip8.V[(second_byte & 0xF0) >> 4];
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
break;
|
|
|
|
|
case 0x5:
|
|
|
|
|
// set Vx = Vx - Vy, set VF = NOT borrow
|
|
|
|
|
if (chip8.V[first_byte & 0x0F] > chip8.V[(second_byte & 0xF0) >> 4]) {
|
|
|
|
|
chip8.V[0xF] = 1;
|
|
|
|
|
} else {
|
|
|
|
|
chip8.V[0xF] = 0;
|
|
|
|
|
}
|
|
|
|
|
chip8.V[first_byte & 0x0F] = chip8.V[first_byte & 0x0F] - chip8.V[(second_byte & 0xF0) >> 4];
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
break;
|
|
|
|
|
case 0x6:
|
|
|
|
|
if (chip8.V[first_byte & 0x0F] & 1 == 1) {
|
|
|
|
|
chip8.V[0xF] = 1;
|
|
|
|
|
} else {
|
|
|
|
|
chip8.V[0xF] = 0;
|
|
|
|
|
}
|
|
|
|
|
chip8.V[first_byte & 0x0F] = chip8.V[first_byte & 0x0F] >> 1;
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
break;
|
|
|
|
|
case 0x7:
|
|
|
|
|
// set Vx = Vy - Vx, set VF = NOT borrow
|
|
|
|
|
if (chip8.V[(second_byte & 0xF0) >> 4] > chip8.V[first_byte & 0x0F]) {
|
|
|
|
|
chip8.V[0xF] = 1;
|
|
|
|
|
} else {
|
|
|
|
|
chip8.V[0xF] = 0;
|
|
|
|
|
}
|
|
|
|
|
chip8.V[first_byte & 0x0F] = chip8.V[(second_byte & 0xF0) >> 4] - chip8.V[first_byte & 0x0F];
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
break;
|
|
|
|
|
case 0xE:
|
|
|
|
|
chip8.V[0xF] = (chip8.V[(opcode & 0x0F00) >> 8] >> 7) & 1;
|
|
|
|
|
chip8.V[first_byte & 0x0F] = chip8.V[first_byte & 0x0F] << 1;
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 0x9:
|
|
|
|
|
if (chip8.V[first_byte & 0x0F] != chip8.V[(second_byte & 0xF0) >> 4]) {
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
}
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
break;
|
|
|
|
|
case 0xA:
|
|
|
|
|
chip8.I = ((first_byte & 0x0F) << 8) | second_byte;
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
break;
|
|
|
|
|
case 0xB:
|
|
|
|
|
chip8.PC = (((first_byte & 0x0F) << 8) | second_byte) + chip8.V[0];
|
|
|
|
|
break;
|
|
|
|
|
case 0xC:
|
|
|
|
|
chip8.V[first_byte & 0x0F] = (rand() & 0x00FF) & second_byte;
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
break;
|
|
|
|
|
case 0xD: {
|
|
|
|
|
int height = second_byte & 0x0F;
|
|
|
|
|
chip8.V[0xF] = 0;
|
|
|
|
|
for (int y = 0; y < height; y++) {
|
|
|
|
|
uint8_t pixel = chip8.memory[chip8.I + y];
|
|
|
|
|
for (int x = 0; x < 8; x++) {
|
|
|
|
|
if (pixel & (0x80 >> x)) {
|
|
|
|
|
// check if we're turning off the pixel and set VF.
|
2021-03-09 14:41:16 +02:00
|
|
|
int index = ((chip8.V[first_byte & 0x0F] + x) % 64) + ((chip8.V[((second_byte & 0xF0) >> 4)] + y) % 32) * 64;
|
2021-03-08 01:05:41 +02:00
|
|
|
if (chip8.pixels[index] == ON_COLOR) {
|
|
|
|
|
chip8.V[0xF] = 1;
|
|
|
|
|
chip8.pixels[index] = OFF_COLOR;
|
2021-03-09 14:41:16 +02:00
|
|
|
} else {
|
|
|
|
|
chip8.pixels[index] = ON_COLOR;
|
2021-03-08 01:05:41 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
chip8.draw = true;
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 0xE:
|
2021-03-09 14:41:16 +02:00
|
|
|
switch (second_byte) {
|
|
|
|
|
case 0x9E:
|
|
|
|
|
if (chip8.keys[chip8.V[first_byte & 0x0F]]) {
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 0xA1:
|
|
|
|
|
if (!chip8.keys[chip8.V[first_byte & 0x0F]]) {
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-03-08 01:05:41 +02:00
|
|
|
chip8.PC += 2;
|
|
|
|
|
break;
|
|
|
|
|
case 0xF:
|
|
|
|
|
auto X = (opcode & 0x0F00) >> 8;
|
|
|
|
|
switch (second_byte) {
|
|
|
|
|
case 0x07:
|
2021-03-09 14:41:16 +02:00
|
|
|
chip8.V[X] = chip8.delay_timer;
|
2021-03-08 01:05:41 +02:00
|
|
|
break;
|
|
|
|
|
case 0x0A:
|
2021-03-09 14:41:16 +02:00
|
|
|
// TODO: wait for keypress and then store it somewhere
|
2021-03-08 01:05:41 +02:00
|
|
|
break;
|
|
|
|
|
case 0x15:
|
2021-03-09 14:41:16 +02:00
|
|
|
chip8.delay_timer = chip8.V[X];
|
2021-03-08 01:05:41 +02:00
|
|
|
break;
|
|
|
|
|
case 0x18:
|
2021-03-09 14:41:16 +02:00
|
|
|
chip8.sound_timer = chip8.V[X];
|
2021-03-08 01:05:41 +02:00
|
|
|
break;
|
|
|
|
|
case 0x1E:
|
|
|
|
|
chip8.I = chip8.I + chip8.V[X];
|
|
|
|
|
break;
|
|
|
|
|
case 0x29:
|
|
|
|
|
chip8.I = chip8.V[X] * 5;
|
|
|
|
|
break;
|
|
|
|
|
case 0x33:
|
|
|
|
|
chip8.memory[chip8.I] = (chip8.V[X]) / 100;
|
|
|
|
|
chip8.memory[chip8.I + 1] = (chip8.V[X] % 100) / 10;
|
|
|
|
|
chip8.memory[chip8.I + 2] = chip8.V[X] % 10;
|
|
|
|
|
break;
|
|
|
|
|
case 0x55: {
|
|
|
|
|
for (int i = 0; i <= X; i++) {
|
|
|
|
|
chip8.memory[chip8.I + i] = chip8.V[i];
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 0x65: {
|
|
|
|
|
for (int i = 0; i <= X; i++) {
|
|
|
|
|
chip8.V[i] = chip8.memory[chip8.I + i];
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
chip8.PC += 2;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
|
if (argc < 2) {
|
2021-03-09 14:41:16 +02:00
|
|
|
printf("No file was provided as input, quitting program\n");
|
2021-03-08 01:05:41 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::ifstream file(argv[1], std::ios::binary | std::ios::ate);
|
|
|
|
|
|
|
|
|
|
if (!file) {
|
2021-03-09 14:41:16 +02:00
|
|
|
printf("Invalid file was provided, quitting program\n");
|
2021-03-08 01:05:41 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SDL_Window *window = nullptr;
|
|
|
|
|
SDL_Renderer *renderer = nullptr;
|
|
|
|
|
SDL_Texture *texture = nullptr;
|
|
|
|
|
|
|
|
|
|
char title[64];
|
|
|
|
|
sprintf(title, "Chip-8 v%d.%d [%s]", VERSION_MAJOR, VERSION_MINOR, argv[1]);
|
|
|
|
|
|
|
|
|
|
Chip8 chip8;
|
|
|
|
|
|
|
|
|
|
memcpy(chip8.memory, font, sizeof(font));
|
2021-03-09 14:41:16 +02:00
|
|
|
memset(chip8.pixels, 0, sizeof(chip8.pixels));
|
2021-03-08 01:05:41 +02:00
|
|
|
memset(chip8.stack, 0, sizeof(chip8.stack));
|
|
|
|
|
memset(chip8.V, 0, sizeof(chip8.V));
|
|
|
|
|
|
|
|
|
|
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
2021-03-09 14:41:16 +02:00
|
|
|
printf("Video init failed\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SDL_Init(SDL_INIT_AUDIO) < 0) {
|
|
|
|
|
printf("Audio init failed\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (MIX_INIT_MP3 != Mix_Init(MIX_INIT_MP3)) {
|
|
|
|
|
printf("Could not init audio mixer\n");
|
2021-03-08 01:05:41 +02:00
|
|
|
return -1;
|
|
|
|
|
}
|
2021-03-09 14:41:16 +02:00
|
|
|
|
|
|
|
|
Mix_OpenAudio(22050, AUDIO_S16SYS, 2, 640);
|
|
|
|
|
Mix_Music *beep = Mix_LoadMUS("./beep.mp3");
|
|
|
|
|
|
2021-03-08 01:05:41 +02:00
|
|
|
srand(time(0));
|
|
|
|
|
|
|
|
|
|
std::streamsize size = file.tellg();
|
|
|
|
|
file.seekg(0, std::ios::beg);
|
|
|
|
|
|
|
|
|
|
file.read(reinterpret_cast<char *>(&chip8.memory) + 0x200, size);
|
|
|
|
|
|
|
|
|
|
window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 320, SDL_WINDOW_SHOWN);
|
|
|
|
|
renderer = SDL_CreateRenderer(window, 0, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
|
2021-03-09 14:41:16 +02:00
|
|
|
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC, 64, 32);
|
2021-03-08 01:05:41 +02:00
|
|
|
|
|
|
|
|
bool running = true;
|
|
|
|
|
|
|
|
|
|
while (running) {
|
2021-03-09 14:41:16 +02:00
|
|
|
emulate(chip8, window, beep);
|
2021-03-08 01:05:41 +02:00
|
|
|
|
|
|
|
|
if (chip8.draw) {
|
2021-03-09 14:41:16 +02:00
|
|
|
SDL_UpdateTexture(texture, nullptr, chip8.pixels, 64 * sizeof(uint32_t));
|
|
|
|
|
SDL_RenderCopy(renderer, texture, nullptr, nullptr);
|
2021-03-08 01:05:41 +02:00
|
|
|
SDL_RenderPresent(renderer);
|
|
|
|
|
|
|
|
|
|
chip8.draw = false;
|
|
|
|
|
}
|
2021-03-09 14:41:16 +02:00
|
|
|
poll_events(window, &running, chip8);
|
2021-03-08 01:05:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SDL_DestroyTexture(texture);
|
|
|
|
|
SDL_DestroyRenderer(renderer);
|
|
|
|
|
SDL_DestroyWindow(window);
|
2021-03-09 14:41:16 +02:00
|
|
|
Mix_FreeMusic(beep);
|
2021-03-08 01:05:41 +02:00
|
|
|
SDL_Quit();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|