improve sw renderer

This commit is contained in:
asrael 2026-01-21 23:19:50 -06:00
parent 415d424057
commit 39ee0fefb7
89 changed files with 9380 additions and 2307 deletions

View file

@ -7,6 +7,7 @@
#include "pxl8_color.h"
#include "pxl8_log.h"
#include "pxl8_mem.h"
typedef struct pxl8_skyline_fit {
bool found;
@ -27,6 +28,8 @@ typedef struct pxl8_skyline {
struct pxl8_atlas {
u32 height, width;
u8* pixels;
u8* pixels_tiled;
u32 tiled_capacity, tiled_size;
bool dirty;
@ -103,7 +106,7 @@ static bool pxl8_skyline_add_rect(pxl8_skyline* skyline, pxl8_point pos, u32 w,
if (skyline->count - nodes_to_remove + 1 > skyline->capacity) {
u32 new_capacity = (skyline->count - nodes_to_remove + 1) * 2;
pxl8_skyline_node* new_nodes = (pxl8_skyline_node*)realloc(
pxl8_skyline_node* new_nodes = (pxl8_skyline_node*)pxl8_realloc(
skyline->nodes,
new_capacity * sizeof(pxl8_skyline_node)
);
@ -142,44 +145,44 @@ static void pxl8_skyline_compact(pxl8_skyline* skyline) {
}
pxl8_atlas* pxl8_atlas_create(u32 width, u32 height, pxl8_pixel_mode pixel_mode) {
pxl8_atlas* atlas = (pxl8_atlas*)calloc(1, sizeof(pxl8_atlas));
pxl8_atlas* atlas = (pxl8_atlas*)pxl8_calloc(1, sizeof(pxl8_atlas));
if (!atlas) return NULL;
atlas->height = height;
atlas->width = width;
i32 bytes_per_pixel = pxl8_bytes_per_pixel(pixel_mode);
atlas->pixels = (u8*)calloc(width * height, bytes_per_pixel);
atlas->pixels = (u8*)pxl8_calloc(width * height, bytes_per_pixel);
if (!atlas->pixels) {
free(atlas);
pxl8_free(atlas);
return NULL;
}
atlas->entry_capacity = PXL8_DEFAULT_ATLAS_ENTRY_CAPACITY;
atlas->entries = (pxl8_atlas_entry*)calloc(atlas->entry_capacity, sizeof(pxl8_atlas_entry));
atlas->entries = (pxl8_atlas_entry*)pxl8_calloc(atlas->entry_capacity, sizeof(pxl8_atlas_entry));
if (!atlas->entries) {
free(atlas->pixels);
free(atlas);
pxl8_free(atlas->pixels);
pxl8_free(atlas);
return NULL;
}
atlas->free_capacity = 16;
atlas->free_list = (u32*)calloc(atlas->free_capacity, sizeof(u32));
atlas->free_list = (u32*)pxl8_calloc(atlas->free_capacity, sizeof(u32));
if (!atlas->free_list) {
free(atlas->entries);
free(atlas->pixels);
free(atlas);
pxl8_free(atlas->entries);
pxl8_free(atlas->pixels);
pxl8_free(atlas);
return NULL;
}
atlas->skyline.capacity = 16;
atlas->skyline.nodes =
(pxl8_skyline_node*)calloc(atlas->skyline.capacity, sizeof(pxl8_skyline_node));
(pxl8_skyline_node*)pxl8_calloc(atlas->skyline.capacity, sizeof(pxl8_skyline_node));
if (!atlas->skyline.nodes) {
free(atlas->free_list);
free(atlas->entries);
free(atlas->pixels);
free(atlas);
pxl8_free(atlas->free_list);
pxl8_free(atlas->entries);
pxl8_free(atlas->pixels);
pxl8_free(atlas);
return NULL;
}
@ -192,11 +195,12 @@ pxl8_atlas* pxl8_atlas_create(u32 width, u32 height, pxl8_pixel_mode pixel_mode)
void pxl8_atlas_destroy(pxl8_atlas* atlas) {
if (!atlas) return;
free(atlas->entries);
free(atlas->free_list);
free(atlas->pixels);
free(atlas->skyline.nodes);
free(atlas);
pxl8_free(atlas->entries);
pxl8_free(atlas->free_list);
pxl8_free(atlas->pixels);
pxl8_free(atlas->pixels_tiled);
pxl8_free(atlas->skyline.nodes);
pxl8_free(atlas);
}
void pxl8_atlas_clear(pxl8_atlas* atlas, u32 preserve_count) {
@ -209,6 +213,13 @@ void pxl8_atlas_clear(pxl8_atlas* atlas, u32 preserve_count) {
atlas->entry_count = preserve_count;
atlas->free_count = 0;
if (preserve_count == 0) {
atlas->tiled_size = 0;
} else {
pxl8_atlas_entry* last = &atlas->entries[preserve_count - 1];
atlas->tiled_size = last->tiled_base + (u32)(last->w * last->h);
}
atlas->skyline.nodes[0] = (pxl8_skyline_node){0, 0, (i32)atlas->width};
atlas->skyline.count = 1;
@ -222,13 +233,13 @@ bool pxl8_atlas_expand(pxl8_atlas* atlas, pxl8_pixel_mode pixel_mode) {
u32 new_size = atlas->width * 2;
u32 old_width = atlas->width;
u8* new_pixels = (u8*)calloc(new_size * new_size, bytes_per_pixel);
u8* new_pixels = (u8*)pxl8_calloc(new_size * new_size, bytes_per_pixel);
if (!new_pixels) return false;
pxl8_skyline new_skyline;
new_skyline.nodes = (pxl8_skyline_node*)calloc(16, sizeof(pxl8_skyline_node));
new_skyline.nodes = (pxl8_skyline_node*)pxl8_calloc(16, sizeof(pxl8_skyline_node));
if (!new_skyline.nodes) {
free(new_pixels);
pxl8_free(new_pixels);
return false;
}
@ -248,8 +259,8 @@ bool pxl8_atlas_expand(pxl8_atlas* atlas, pxl8_pixel_mode pixel_mode) {
);
if (!fit.found) {
free(new_skyline.nodes);
free(new_pixels);
pxl8_free(new_skyline.nodes);
pxl8_free(new_pixels);
return false;
}
@ -269,15 +280,15 @@ bool pxl8_atlas_expand(pxl8_atlas* atlas, pxl8_pixel_mode pixel_mode) {
atlas->entries[i].y = fit.pos.y;
if (!pxl8_skyline_add_rect(&new_skyline, fit.pos, atlas->entries[i].w, atlas->entries[i].h)) {
free(new_skyline.nodes);
free(new_pixels);
pxl8_free(new_skyline.nodes);
pxl8_free(new_pixels);
return false;
}
pxl8_skyline_compact(&new_skyline);
}
free(atlas->pixels);
free(atlas->skyline.nodes);
pxl8_free(atlas->pixels);
pxl8_free(atlas->skyline.nodes);
atlas->pixels = new_pixels;
atlas->skyline = new_skyline;
@ -316,7 +327,7 @@ u32 pxl8_atlas_add_texture(
} else {
if (atlas->entry_count >= atlas->entry_capacity) {
u32 new_capacity = atlas->entry_capacity * 2;
pxl8_atlas_entry* new_entries = (pxl8_atlas_entry*)realloc(
pxl8_atlas_entry* new_entries = (pxl8_atlas_entry*)pxl8_realloc(
atlas->entries,
new_capacity * sizeof(pxl8_atlas_entry)
);
@ -334,6 +345,7 @@ u32 pxl8_atlas_add_texture(
entry->y = fit.pos.y;
entry->w = w;
entry->h = h;
entry->log2_w = pxl8_log2(w);
i32 bytes_per_pixel = pxl8_bytes_per_pixel(pixel_mode);
for (u32 y = 0; y < h; y++) {
@ -349,6 +361,30 @@ u32 pxl8_atlas_add_texture(
}
}
u32 tiled_tex_size = w * h;
u32 new_tiled_size = atlas->tiled_size + tiled_tex_size;
if (new_tiled_size > atlas->tiled_capacity) {
u32 new_cap = atlas->tiled_capacity ? atlas->tiled_capacity * 2 : 4096;
while (new_cap < new_tiled_size) new_cap *= 2;
u8* new_tiled = (u8*)pxl8_realloc(atlas->pixels_tiled, new_cap);
if (!new_tiled) {
entry->active = false;
return UINT32_MAX;
}
atlas->pixels_tiled = new_tiled;
atlas->tiled_capacity = new_cap;
}
entry->tiled_base = atlas->tiled_size;
u8* tiled_dst = atlas->pixels_tiled + entry->tiled_base;
for (u32 ty = 0; ty < h; ty++) {
for (u32 tx = 0; tx < w; tx++) {
u32 tiled_offset = pxl8_tile_addr(tx, ty, entry->log2_w);
tiled_dst[tiled_offset] = pixels[ty * w + tx];
}
}
atlas->tiled_size = new_tiled_size;
if (!pxl8_skyline_add_rect(&atlas->skyline, fit.pos, w, h)) {
entry->active = false;
return UINT32_MAX;
@ -377,6 +413,10 @@ const u8* pxl8_atlas_get_pixels(const pxl8_atlas* atlas) {
return atlas ? atlas->pixels : NULL;
}
const u8* pxl8_atlas_get_pixels_tiled(const pxl8_atlas* atlas) {
return atlas ? atlas->pixels_tiled : NULL;
}
u32 pxl8_atlas_get_width(const pxl8_atlas* atlas) {
return atlas ? atlas->width : 0;
}