nesemu/gui/pattern_display.c

122 lines
4.1 KiB
C

//
// Created by william on 12/07/24.
//
#include <assert.h>
#include "pattern_display.h"
#define PATTERN_BYTES (PATTERN_SIZE * 2)
void pattern_display_init(PatternDisplay *display, SDL_Renderer *renderer, int tiles_x, int tiles_y) {
assert(tiles_x > 0);
assert(tiles_y > 0);
display->width = tiles_x;
display->height = tiles_y;
display->texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC,
pattern_display_get_size(tiles_x),
pattern_display_get_size(tiles_y));
}
void pattern_display_uninit(PatternDisplay *display) {
SDL_DestroyTexture(display->texture);
}
void pattern_display_draw_borders(unsigned int *buffer, int win_width, int win_height) {
assert(buffer != NULL);
for (int x = 0; x < win_width; x++) {
buffer[x] = PATTERN_BORDER_COLOR;
}
for (int y = 1; y < win_height; y++) {
buffer[y * win_width] = PATTERN_BORDER_COLOR;
}
}
void pattern_display_build_table(PatternTile *tile_table, byte *memory, int tile_count) {
for (int tile_index = 0; tile_index < tile_count; tile_index++) {
PatternTile *tile = &tile_table[tile_index];
address tile_addr = tile_index * PATTERN_BYTES;
memcpy(tile->data_low, &memory[tile_addr], 8);
memcpy(tile->data_high, &memory[tile_addr + 8], 8);
}
}
void pattern_display_draw_tile_borders(int tile_addr, pixel *buffer, int win_width) {
assert(buffer != NULL);
for (int by = 0; by < PATTERN_DRAW_SIZE; by++) {
address pixel_addr = tile_addr + (by * win_width) + PATTERN_DRAW_SIZE - 1;
buffer[pixel_addr] = PATTERN_BORDER_COLOR;
}
for (int bx = 0; bx < PATTERN_DRAW_SIZE; bx++) {
address pixel_addr = tile_addr + ((PATTERN_DRAW_SIZE - 1) * win_width) + bx;
buffer[pixel_addr] = PATTERN_BORDER_COLOR;
}
}
void pattern_display_draw_tile(PatternTile *tile, pixel *buffer, int tile_addr, int win_width) {
assert(buffer != NULL);
for (int fine_y = 0; fine_y < PATTERN_SIZE; fine_y++) {
byte data_high = tile->data_high[fine_y];
byte data_low = tile->data_low[fine_y];
for (int fine_x = 0; fine_x < PATTERN_SIZE; fine_x++) {
byte bitmask = 1 << (PATTERN_SIZE - fine_x - 1);
byte bit_high = data_high & bitmask;
byte bit_low = data_low & bitmask;
int pixel_addr = tile_addr + fine_x + fine_y * win_width;
pixel *pixel = &buffer[pixel_addr];
// TODO: Use palette colors
if (bit_high && bit_low) {
*pixel = 0xffffffff;
} else if (bit_low) {
*pixel = 0xffff0000;
} else if (bit_high) {
*pixel = 0xff00ffff;
} else {
*pixel = 0xff000000;
}
}
}
pattern_display_draw_tile_borders(tile_addr, buffer, win_width);
}
void pattern_display_build(PatternDisplay *display, byte *memory) {
int tile_count = display->width * display->height;
PatternTile *tile_table = malloc(tile_count * sizeof(PatternTile));
pattern_display_build_table(tile_table, memory, tile_count);
int win_width = pattern_display_get_size(display->width);
int win_height = pattern_display_get_size(display->height);
pixel *buffer = malloc(win_width * win_height * sizeof(pixel));
pattern_display_draw_borders(buffer, win_width, win_height);
for (int x = 0; x < display->width; x++) {
for (int y = 0; y < display->height; y++) {
PatternTile *tile = &tile_table[x + y * display->width];
address row_addr = (y * PATTERN_DRAW_SIZE + PATTERN_BORDER_WIDTH) * win_width;
address tile_addr = row_addr + (x * PATTERN_DRAW_SIZE + PATTERN_BORDER_WIDTH);
pattern_display_draw_tile(tile, buffer, tile_addr, win_width);
}
}
SDL_UpdateTexture(display->texture, NULL, buffer, win_width * sizeof(pixel));
free(tile_table);
free(buffer);
}
void pattern_display_render(PatternDisplay *display, SDL_Renderer *renderer) {
SDL_RenderCopy(renderer, display->texture, NULL, NULL);
}