#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
#include <stdbool.h>
#include <SDL3/SDL.h>
#include <sys/mman.h>
#include "main.h"
#include "procfs.h"
#include "hash.h"
#include "curve.h"
#include "panic.h"
#include "memory.h"
uintptr_t to_addr(int x, int y) {
unsigned int ux, uy;
memcpy(&ux, &x, sizeof(unsigned int));
memcpy(&uy, &y, sizeof(unsigned int));
uintptr_t page = zorder(ux / PAGE_WIDTH, uy / PAGE_HEIGHT);
int offset = x % PAGE_WIDTH / CHAR_BIT * PAGE_HEIGHT + y % PAGE_HEIGHT;
return page * PAGE_SIZE + offset;
}
void to_pos(uintptr_t addr, int *x, int *y) {
int px, py;
unzorder(addr / PAGE_SIZE, &px, &py);
int offset = addr % PAGE_SIZE;
int ux = px * PAGE_WIDTH + offset % PAGE_WIDTH;
int uy = py * PAGE_HEIGHT + offset / PAGE_WIDTH;
memcpy(x, &ux, sizeof(int));
memcpy(y, &uy, sizeof(int));
}
int init_page_list(page_list *l, int fd) {
l->fd = fd;
}
static void free_page(page *p) {
if (p->tex) {
SDL_DestroyTexture(p->tex);
}
free(p);
}
void free_page_list(page_list *l) {
page *p = l->first;
while (p) {
page *next = p->next;
free_page(p);
p = next;
}
l->fd = -1;
l->first = NULL;
}
void free_unused_pages(page_list *l) {
page **prev_link = &l->first;
page *p = l->first;
while (p) {
page *next = p->next;
if (!p->in_use) {
*prev_link = next;
free_page(p);
} else {
prev_link = &p->next;
p->in_use = false;
}
p = next;
}
}
page *get_page(page_list *l, uintptr_t addr) {
addr = addr - addr % PAGE_SIZE;
for (page *p = l->first; p; p = p->next) {
if (p->address == addr) {
return p;
}
}
page *p = calloc(1, sizeof(page));
if (!p) panic("out of memory");
p->address = addr;
p->l = l;
p->next = l->first;
l->first = p;
return p;
}
static SDL_Palette *texture_palette() {
SDL_Color colors[] = {{0x00, 0x00, 0x00, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}};
static SDL_Palette *palette = NULL;
if (!palette) {
palette = must(SDL_CreatePalette(2));
must(SDL_SetPaletteColors(palette, colors, 0, 2));
}
return palette;
}
SDL_Texture *get_texture(page *p) {
static char data[PAGE_SIZE];
if (read_mem(p->l->fd, p->address, data, PAGE_SIZE) != 0) {
return NULL;
}
uint32_t hash = fnv(data, PAGE_SIZE);
if (p->hash != hash) {
static char pixels[PAGE_SIZE];
for (int col = 0; col < PAGE_WIDTH / 8; col++) {
for (int row = 0; row < PAGE_HEIGHT; row++) {
pixels[row * PAGE_WIDTH / 8 + col] =
data[col * PAGE_HEIGHT + row];
}
}
if (p->tex) SDL_DestroyTexture(p->tex);
SDL_Surface *surface = must(SDL_CreateSurfaceFrom(
PAGE_WIDTH, PAGE_HEIGHT, SDL_PIXELFORMAT_INDEX1LSB, pixels,
PAGE_WIDTH / 8
));
must(SDL_SetSurfacePalette(surface, texture_palette()));
p->tex = must(SDL_CreateTextureFromSurface(renderer, surface));
SDL_DestroySurface(surface);
}
p->hash = hash;
p->in_use = true;
return p->tex;
}
static void write_bit(int fd, int x, int y, bool bit) {
uintptr_t addr = to_addr(x, y);
int bit_offs = x % CHAR_BIT;
uint8_t byte;
if (read_mem(fd, addr, &byte, 1) == -1) return;
byte = (byte & ~(1 << bit_offs)) | (bit << bit_offs);
write_mem(fd, addr, &byte, 1);
}
void draw_line(page_list *l,
double x1, double y1, double x2, double y2, bool bit) {
double dx = (x2 - x1);
double dy = (y2 - y1);
int step = abs(dx) >= abs(dy) ? abs(dx) : abs(dy);
dx = dx / step; dy = dy / step;
double x = x1; double y = y1;
for (int i = 0; i <= step; i++) {
write_bit(l->fd, x, y, bit);
x = x + dx;
y = y + dy;
}
}