Pattern table view
This commit is contained in:
parent
036835d3d0
commit
87179ec891
13
gui/canvas.c
13
gui/canvas.c
|
@ -28,14 +28,21 @@ void canvas_uninit(Canvas *canvas) {
|
|||
free(canvas->pixels);
|
||||
}
|
||||
|
||||
void canvas_draw(Canvas *canvas, Pixel pixel, int x, int y) {
|
||||
void canvas_draw(Canvas *canvas, Pixel pixel, int index) {
|
||||
assert(index >= 0);
|
||||
assert(index < canvas->width * canvas->height);
|
||||
|
||||
canvas->pixels[index] = pixel;
|
||||
}
|
||||
|
||||
void canvas_draw_pos(Canvas *canvas, Pixel pixel, int x, int y) {
|
||||
assert(x >= 0);
|
||||
assert(x < canvas->width);
|
||||
assert(y >= 0);
|
||||
assert(y < canvas->height);
|
||||
|
||||
int pixel_index = x + y * canvas->width;
|
||||
canvas->pixels[pixel_index] = pixel;
|
||||
int index = x + y * canvas->width;
|
||||
canvas_draw(canvas, pixel, index);
|
||||
}
|
||||
|
||||
void canvas_reset(Canvas *canvas) {
|
||||
|
|
|
@ -7,9 +7,6 @@
|
|||
|
||||
#include "../include/types.h"
|
||||
|
||||
//#define CANVAS_WIDTH 256
|
||||
//#define CANVAS_HEIGHT 240
|
||||
|
||||
typedef struct pixel {
|
||||
byte r;
|
||||
byte g;
|
||||
|
@ -25,7 +22,8 @@ typedef struct canvas {
|
|||
Canvas canvas_init(int width, int height);
|
||||
void canvas_uninit(Canvas *canvas);
|
||||
|
||||
void canvas_draw(Canvas *canvas, Pixel pixel, int x, int y);
|
||||
void canvas_draw(Canvas *canvas, Pixel pixel, int index);
|
||||
void canvas_draw_pos(Canvas *canvas, Pixel pixel, int x, int y);
|
||||
void canvas_reset(Canvas *canvas);
|
||||
|
||||
#endif //NES_EMULATOR_CANVAS_H
|
||||
|
|
20
gui/gui.c
20
gui/gui.c
|
@ -3,14 +3,20 @@
|
|||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include "gui.h"
|
||||
#include "log.h"
|
||||
#include "gui.h"
|
||||
#include "window.h"
|
||||
|
||||
typedef struct nes_gui {
|
||||
NesWindow main_window;
|
||||
NesWindow debug_pattern_window;
|
||||
} NesGui;
|
||||
NesGui gui;
|
||||
|
||||
void gui_init() {
|
||||
gui.main_window = window_init(MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT, "NES Emulator");
|
||||
gui.debug_pattern_window = window_init(DEBUG_PATTERN_WIDTH, DEBUG_PATTERN_HEIGHT, "Pattern Table");
|
||||
gui.main_window = window_init(WINDOW_MAIN_WIDTH, WINDOW_MAIN_HEIGHT, WINDOW_MAIN_SCALING, "NES Emulator");
|
||||
gui.debug_pattern_window = window_init(WINDOW_PATTERN_WIDTH, WINDOW_PATTERN_HEIGHT, WINDOW_PATTERN_SCALING,
|
||||
"Pattern Table");
|
||||
}
|
||||
|
||||
void gui_uninit() {
|
||||
|
@ -40,14 +46,18 @@ void gui_present() {
|
|||
window_present(&gui.debug_pattern_window);
|
||||
}
|
||||
|
||||
void gui_delay() {
|
||||
SDL_Delay(16);
|
||||
}
|
||||
|
||||
Canvas *gui_get_canvas(char win_id) {
|
||||
NesWindow *window;
|
||||
|
||||
switch (win_id) {
|
||||
case GUI_WINDOW_MAIN:
|
||||
case WINDOW_ID_MAIN:
|
||||
window = &gui.main_window;
|
||||
break;
|
||||
case GUI_WINDOW_PATTERN:
|
||||
case WINDOW_ID_PATTERN:
|
||||
window = &gui.debug_pattern_window;
|
||||
break;
|
||||
default:
|
||||
|
|
22
gui/gui.h
22
gui/gui.h
|
@ -5,22 +5,17 @@
|
|||
#ifndef NES_EMULATOR_GUI_H
|
||||
#define NES_EMULATOR_GUI_H
|
||||
|
||||
#include <SDL.h>
|
||||
#include "canvas.h"
|
||||
#include "window.h"
|
||||
|
||||
#define MAIN_WINDOW_WIDTH 256
|
||||
#define MAIN_WINDOW_HEIGHT 240
|
||||
#define DEBUG_PATTERN_WIDTH 100
|
||||
#define DEBUG_PATTERN_HEIGHT 100
|
||||
#define WINDOW_ID_MAIN 1
|
||||
#define WINDOW_MAIN_WIDTH 256
|
||||
#define WINDOW_MAIN_HEIGHT 240
|
||||
#define WINDOW_MAIN_SCALING 3
|
||||
|
||||
#define GUI_WINDOW_MAIN 1
|
||||
#define GUI_WINDOW_PATTERN 2
|
||||
|
||||
typedef struct nes_gui {
|
||||
NesWindow main_window;
|
||||
NesWindow debug_pattern_window;
|
||||
} NesGui;
|
||||
#define WINDOW_ID_PATTERN 2
|
||||
#define WINDOW_PATTERN_WIDTH 128
|
||||
#define WINDOW_PATTERN_HEIGHT 256
|
||||
#define WINDOW_PATTERN_SCALING 2
|
||||
|
||||
void gui_init();
|
||||
void gui_uninit();
|
||||
|
@ -28,6 +23,7 @@ void gui_uninit();
|
|||
int gui_input();
|
||||
void gui_render();
|
||||
void gui_present();
|
||||
void gui_delay();
|
||||
|
||||
Canvas *gui_get_canvas(char win_id);
|
||||
|
||||
|
|
23
gui/window.c
23
gui/window.c
|
@ -2,13 +2,15 @@
|
|||
// Created by william on 17/05/24.
|
||||
//
|
||||
|
||||
#include <SDL.h>
|
||||
#include "window.h"
|
||||
#include "log.h"
|
||||
|
||||
NesWindow window_init(int width, int height, char *title) {
|
||||
NesWindow window_init(int width, int height, int scaling, char *title) {
|
||||
NesWindow win;
|
||||
win.width = width * WINDOW_SCALING;
|
||||
win.height = height * WINDOW_SCALING;
|
||||
win.scaling = scaling;
|
||||
win.width = width * scaling;
|
||||
win.height = height * scaling;
|
||||
win.canvas = canvas_init(width, height);
|
||||
|
||||
int renderer_flags = SDL_RENDERER_ACCELERATED;
|
||||
|
@ -44,17 +46,17 @@ void window_uninit(NesWindow *window) {
|
|||
void window_render(NesWindow *window) {
|
||||
SDL_RenderClear(window->renderer);
|
||||
|
||||
for (int x = 0; x < window->canvas.width; x++) {
|
||||
for (int y = 0; y < window->canvas.height; y++) {
|
||||
for (int y = 0; y < window->canvas.height; y++) {
|
||||
for (int x = 0; x < window->canvas.width; x++) {
|
||||
int pixel_index = x + y * window->canvas.width;
|
||||
Pixel pixel = window->canvas.pixels[pixel_index];
|
||||
|
||||
SDL_SetRenderDrawColor(window->renderer, pixel.r, pixel.g, pixel.b, 255);
|
||||
|
||||
for (int i = 0; i < WINDOW_SCALING; i++) {
|
||||
for (int j = 0; j < WINDOW_SCALING; j++) {
|
||||
int scaled_x = x * WINDOW_SCALING + i;
|
||||
int scaled_y = y * WINDOW_SCALING + j;
|
||||
for (int i = 0; i < window->scaling; i++) {
|
||||
for (int j = 0; j < window->scaling; j++) {
|
||||
int scaled_x = x * window->scaling + i;
|
||||
int scaled_y = y * window->scaling + j;
|
||||
SDL_RenderDrawPoint(window->renderer, scaled_x, scaled_y);
|
||||
}
|
||||
}
|
||||
|
@ -64,4 +66,7 @@ void window_render(NesWindow *window) {
|
|||
|
||||
void window_present(NesWindow *window) {
|
||||
SDL_RenderPresent(window->renderer);
|
||||
|
||||
// TODO: Check if this is a good location
|
||||
canvas_reset(&window->canvas);
|
||||
}
|
|
@ -8,18 +8,17 @@
|
|||
#include <SDL.h>
|
||||
#include "canvas.h"
|
||||
|
||||
#define WINDOW_SCALING 3
|
||||
|
||||
typedef struct new_window {
|
||||
typedef struct nes_window {
|
||||
SDL_Renderer *renderer;
|
||||
SDL_Window *window;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
int scaling;
|
||||
Canvas canvas;
|
||||
} NesWindow;
|
||||
|
||||
NesWindow window_init(int width, int height, char *title);
|
||||
NesWindow window_init(int width, int height, int scaling, char *title);
|
||||
void window_uninit(NesWindow *window);
|
||||
|
||||
void window_render(NesWindow *window);
|
||||
|
|
|
@ -63,9 +63,11 @@ typedef struct ppu {
|
|||
byte x;
|
||||
bool w;
|
||||
|
||||
bool fetching;
|
||||
|
||||
unsigned long frame;
|
||||
unsigned int line;
|
||||
unsigned int line_x;
|
||||
unsigned int scanline;
|
||||
unsigned int cycle;
|
||||
} PPU;
|
||||
|
||||
PPU *ppu_get_state();
|
||||
|
|
5
main.c
5
main.c
|
@ -27,7 +27,7 @@ int main() {
|
|||
log_set_level(LOG_INFO);
|
||||
|
||||
system_init();
|
||||
char *rom_path = "../test_roms/dk_jp.nes";
|
||||
char *rom_path = "../test_roms/smb.nes";
|
||||
|
||||
if (!rom_load(rom_path)) {
|
||||
system_uninit();
|
||||
|
@ -47,8 +47,7 @@ int main() {
|
|||
|
||||
gui_render();
|
||||
gui_present();
|
||||
|
||||
SDL_Delay(16);
|
||||
gui_delay();
|
||||
}
|
||||
|
||||
system_uninit();
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
set(SOURCE ppu.c)
|
||||
set(HEADERS pattern_table.h
|
||||
ppu.h)
|
||||
set(SOURCE pattern_table.c ppu.c)
|
||||
|
||||
add_library(nes_ppu ${SOURCE})
|
||||
add_library(nes_ppu ${SOURCE} ${HEADERS})
|
||||
|
||||
target_link_libraries(nes_ppu log.c)
|
|
@ -0,0 +1,57 @@
|
|||
//
|
||||
// Created by william on 17/05/24.
|
||||
//
|
||||
|
||||
#include "pattern_table.h"
|
||||
#include "ppu.h"
|
||||
#include "../gui/canvas.h"
|
||||
#include "../gui/gui.h"
|
||||
|
||||
void pt_debug() {
|
||||
Canvas *canvas = gui_get_canvas(WINDOW_ID_PATTERN);
|
||||
|
||||
for (int palette = 0; palette < 2; palette++) {
|
||||
address palette_addr = palette * 0x1000;
|
||||
int palette_canvas_offset = palette * (PATTERN_TABLE_WIDTH * PATTERN_TILE_SIZE);
|
||||
|
||||
for (int y = 0; y < PATTERN_TABLE_WIDTH; y++) {
|
||||
for (int x = 0; x < PATTERN_TABLE_WIDTH; x++) {
|
||||
address tile_addr = palette_addr + (x + y * PATTERN_TABLE_WIDTH) * PATTERN_TILE_MEM_SIZE;
|
||||
|
||||
for (int tile_y = 0; tile_y < PATTERN_TILE_SIZE; tile_y++) {
|
||||
byte p1_data = ppu_read(tile_addr + tile_y);
|
||||
byte p2_data = ppu_read(tile_addr + tile_y + PATTERN_TILE_SIZE);
|
||||
|
||||
for (int tile_x = 0; tile_x < PATTERN_TILE_SIZE; tile_x++) {
|
||||
byte bitmask = 1 << (PATTERN_TILE_SIZE - tile_x - 1);
|
||||
byte p1_byte = p1_data & bitmask;
|
||||
byte p2_byte = p2_data & bitmask;
|
||||
|
||||
Pixel pixel;
|
||||
if (p1_byte && p2_byte) {
|
||||
pixel.r = 255;
|
||||
pixel.g = 255;
|
||||
pixel.b = 255;
|
||||
} else if (p2_byte) {
|
||||
pixel.r = 255;
|
||||
pixel.g = 0;
|
||||
pixel.b = 0;
|
||||
} else if (p1_byte) {
|
||||
pixel.r = 0;
|
||||
pixel.g = 255;
|
||||
pixel.b = 255;
|
||||
} else {
|
||||
pixel.r = 0;
|
||||
pixel.g = 0;
|
||||
pixel.b = 0;
|
||||
}
|
||||
|
||||
int canvas_x = x * PATTERN_TILE_SIZE + tile_x;
|
||||
int canvas_y = y * PATTERN_TILE_SIZE + tile_y + palette_canvas_offset;
|
||||
canvas_draw_pos(canvas, pixel, canvas_x, canvas_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
//
|
||||
// Created by william on 17/05/24.
|
||||
//
|
||||
|
||||
#ifndef NES_EMULATOR_PATTERN_TABLE_H
|
||||
#define NES_EMULATOR_PATTERN_TABLE_H
|
||||
|
||||
#define PATTERN_TABLE_WIDTH 16
|
||||
#define PATTERN_TILE_MEM_SIZE 16
|
||||
#define PATTERN_TILE_SIZE (PATTERN_TILE_MEM_SIZE / 2)
|
||||
|
||||
void pt_debug();
|
||||
|
||||
#endif //NES_EMULATOR_PATTERN_TABLE_H
|
64
ppu/ppu.c
64
ppu/ppu.c
|
@ -15,6 +15,7 @@
|
|||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include "ppu.h"
|
||||
#include "../include/ppu.h"
|
||||
#include "../cpu/cpu.h"
|
||||
|
||||
|
@ -39,10 +40,11 @@ void ppu_init(byte *registers_ram, byte *oam_dma_register) {
|
|||
ppu_state.registers[PPU_REGISTER_DATA] = 0x00;
|
||||
ppu_state.oam_dma_register = oam_dma_register;
|
||||
ppu_state.odd_frame = false;
|
||||
ppu_state.fetching = false;
|
||||
|
||||
ppu_state.frame = 0;
|
||||
ppu_state.line = 0;
|
||||
ppu_state.line_x = 0;
|
||||
ppu_state.scanline = 0;
|
||||
ppu_state.cycle = 0;
|
||||
}
|
||||
|
||||
PPU *ppu_get_state() {
|
||||
|
@ -66,10 +68,34 @@ void ppu_trigger_vbl_nmi() {
|
|||
cpu_trigger_nmi();
|
||||
}
|
||||
|
||||
void ppu_visible_frame(unsigned int x) {
|
||||
if (x >= 257 && x <= 320) {
|
||||
typedef struct {
|
||||
byte nametable;
|
||||
byte attribute_table;
|
||||
byte pattern_table_tile_low;
|
||||
byte pattern_table_tile_high;
|
||||
|
||||
byte fetch_tick;
|
||||
} Tile;
|
||||
Tile tile;
|
||||
|
||||
void ppu_visible_frame(unsigned int cycle) {
|
||||
if (cycle == 0) {
|
||||
// Idle...
|
||||
} else if (cycle <= 256) {
|
||||
switch (tile.fetch_tick) {
|
||||
|
||||
}
|
||||
|
||||
if (tile.nametable == 0) {
|
||||
|
||||
}
|
||||
|
||||
tile.fetch_tick++;
|
||||
} else if (cycle <= 320) {
|
||||
// OAMADDR is cleared on sprite loading for pre-render and visible lines
|
||||
ppu_write_reg(PPU_REGISTER_OAM_ADDR, 0);
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,12 +120,12 @@ void ppu_post_render(unsigned int x, unsigned int y) {
|
|||
}
|
||||
|
||||
void ppu_cycle() {
|
||||
if (ppu_state.line < PPU_VISIBLE_FRAME_END) {
|
||||
ppu_visible_frame(ppu_state.line_x);
|
||||
} else if (ppu_state.line >= PPU_POST_RENDER_LINE_START && ppu_state.line <= PPU_POST_RENDER_LINE_END) {
|
||||
ppu_post_render(ppu_state.line_x, ppu_state.line);
|
||||
} else if (ppu_state.line == PPU_PRE_RENDER_LINE) {
|
||||
ppu_pre_render(ppu_state.line_x);
|
||||
if (ppu_state.scanline < PPU_VISIBLE_FRAME_END) {
|
||||
ppu_visible_frame(ppu_state.cycle);
|
||||
} else if (ppu_state.scanline >= PPU_POST_RENDER_LINE_START && ppu_state.scanline <= PPU_POST_RENDER_LINE_END) {
|
||||
ppu_post_render(ppu_state.cycle, ppu_state.scanline);
|
||||
} else if (ppu_state.scanline == PPU_PRE_RENDER_LINE) {
|
||||
ppu_pre_render(ppu_state.cycle);
|
||||
}
|
||||
|
||||
int frame_width = PPU_LINE_WIDTH;
|
||||
|
@ -112,14 +138,14 @@ void ppu_cycle() {
|
|||
frame_height = PPU_LINE_END - 1;
|
||||
}
|
||||
|
||||
ppu_state.line_x++;
|
||||
if (ppu_state.line_x >= frame_width) {
|
||||
ppu_state.line_x = 0;
|
||||
ppu_state.line++;
|
||||
ppu_state.cycle++;
|
||||
if (ppu_state.cycle >= frame_width) {
|
||||
ppu_state.cycle = 0;
|
||||
ppu_state.scanline++;
|
||||
}
|
||||
|
||||
if (ppu_state.line >= frame_height) {
|
||||
ppu_state.line = 0;
|
||||
if (ppu_state.scanline >= frame_height) {
|
||||
ppu_state.scanline = 0;
|
||||
ppu_state.frame++;
|
||||
ppu_state.odd_frame = !ppu_state.odd_frame;
|
||||
}
|
||||
|
@ -221,3 +247,9 @@ void ppu_write_reg(byte reg, byte data) {
|
|||
|
||||
ppu_write_reg_ram(reg, data);
|
||||
}
|
||||
|
||||
byte ppu_read(address addr) {
|
||||
assert(addr < PPU_VRAM_SIZE);
|
||||
|
||||
return ppu_state.vram[addr];
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
//
|
||||
// Created by william on 17/05/24.
|
||||
//
|
||||
|
||||
#ifndef NES_EMULATOR_PPU_H
|
||||
#define NES_EMULATOR_PPU_H
|
||||
|
||||
#include "../include/types.h"
|
||||
|
||||
byte ppu_read(address addr);
|
||||
|
||||
#endif //NES_EMULATOR_PPU_H
|
Loading…
Reference in New Issue