true 16-bit color... glorious
This commit is contained in:
parent
3dccce8a81
commit
b1e8525c3e
30 changed files with 678 additions and 652 deletions
155
src/pxl8_gfx.c
155
src/pxl8_gfx.c
|
|
@ -6,6 +6,7 @@
|
|||
#include "pxl8_ase.h"
|
||||
#include "pxl8_atlas.h"
|
||||
#include "pxl8_blit.h"
|
||||
#include "pxl8_color.h"
|
||||
#include "pxl8_font.h"
|
||||
#include "pxl8_hal.h"
|
||||
#include "pxl8_macros.h"
|
||||
|
|
@ -55,21 +56,6 @@ struct pxl8_gfx {
|
|||
|
||||
};
|
||||
|
||||
static inline void pxl8_color_unpack(u32 color, u8* r, u8* g, u8* b, u8* a) {
|
||||
*r = color & 0xFF;
|
||||
*g = (color >> 8) & 0xFF;
|
||||
*b = (color >> 16) & 0xFF;
|
||||
*a = (color >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
static inline u32 pxl8_color_pack(u8 r, u8 g, u8 b, u8 a) {
|
||||
return r | (g << 8) | (b << 16) | (a << 24);
|
||||
}
|
||||
|
||||
static inline u8 pxl8_color_lerp_channel(u8 c1, u8 c2, f32 t) {
|
||||
return c1 + (i32)((c2 - c1) * t);
|
||||
}
|
||||
|
||||
pxl8_bounds pxl8_gfx_get_bounds(pxl8_gfx* gfx) {
|
||||
pxl8_bounds bounds = {0};
|
||||
if (!gfx) {
|
||||
|
|
@ -84,8 +70,14 @@ pxl8_color_mode pxl8_gfx_get_color_mode(pxl8_gfx* gfx) {
|
|||
return gfx ? gfx->color_mode : PXL8_COLOR_MODE_FAMI;
|
||||
}
|
||||
|
||||
u8* pxl8_gfx_get_framebuffer(pxl8_gfx* gfx) {
|
||||
return gfx ? gfx->framebuffer : NULL;
|
||||
u8* pxl8_gfx_get_framebuffer_indexed(pxl8_gfx* gfx) {
|
||||
if (!gfx || gfx->color_mode == PXL8_COLOR_MODE_HICOLOR) return NULL;
|
||||
return gfx->framebuffer;
|
||||
}
|
||||
|
||||
u16* pxl8_gfx_get_framebuffer_hicolor(pxl8_gfx* gfx) {
|
||||
if (!gfx || gfx->color_mode != PXL8_COLOR_MODE_HICOLOR) return NULL;
|
||||
return (u16*)gfx->framebuffer;
|
||||
}
|
||||
|
||||
i32 pxl8_gfx_get_height(const pxl8_gfx* gfx) {
|
||||
|
|
@ -126,7 +118,7 @@ pxl8_gfx* pxl8_gfx_create(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
i32 bytes_per_pixel = (gfx->color_mode == PXL8_COLOR_MODE_HICOLOR) ? 4 : 1;
|
||||
i32 bytes_per_pixel = pxl8_bytes_per_pixel(gfx->color_mode);
|
||||
i32 fb_size = gfx->framebuffer_width * gfx->framebuffer_height * bytes_per_pixel;
|
||||
gfx->framebuffer = (u8*)calloc(1, fb_size);
|
||||
if (!gfx->framebuffer) {
|
||||
|
|
@ -183,14 +175,17 @@ void pxl8_gfx_destroy(pxl8_gfx* gfx) {
|
|||
free(gfx);
|
||||
}
|
||||
|
||||
static pxl8_result pxl8_gfx_ensure_atlas(pxl8_gfx* gfx) {
|
||||
if (gfx->atlas) return PXL8_OK;
|
||||
gfx->atlas = pxl8_atlas_create(PXL8_DEFAULT_ATLAS_SIZE, PXL8_DEFAULT_ATLAS_SIZE, gfx->color_mode);
|
||||
return gfx->atlas ? PXL8_OK : PXL8_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
pxl8_result pxl8_gfx_create_texture(pxl8_gfx* gfx, const u8* pixels, u32 width, u32 height) {
|
||||
if (!gfx || !gfx->initialized || !pixels) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
if (!gfx->atlas) {
|
||||
gfx->atlas = pxl8_atlas_create(1024, 1024, gfx->color_mode);
|
||||
if (!gfx->atlas) return PXL8_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
pxl8_result result = pxl8_gfx_ensure_atlas(gfx);
|
||||
if (result != PXL8_OK) return result;
|
||||
|
||||
u32 texture_id = pxl8_atlas_add_texture(gfx->atlas, pixels, width, height, gfx->color_mode);
|
||||
if (texture_id == UINT32_MAX) {
|
||||
|
|
@ -205,7 +200,7 @@ pxl8_result pxl8_gfx_load_sprite(pxl8_gfx* gfx, const char* path) {
|
|||
if (!gfx || !gfx->initialized || !path) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
if (!gfx->sprite_cache) {
|
||||
gfx->sprite_cache_capacity = 64;
|
||||
gfx->sprite_cache_capacity = PXL8_DEFAULT_SPRITE_CACHE_CAPACITY;
|
||||
gfx->sprite_cache = (pxl8_sprite_cache_entry*)calloc(
|
||||
gfx->sprite_cache_capacity, sizeof(pxl8_sprite_cache_entry)
|
||||
);
|
||||
|
|
@ -218,13 +213,11 @@ pxl8_result pxl8_gfx_load_sprite(pxl8_gfx* gfx, const char* path) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!gfx->atlas) {
|
||||
gfx->atlas = pxl8_atlas_create(1024, 1024, gfx->color_mode);
|
||||
if (!gfx->atlas) return PXL8_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
pxl8_result result = pxl8_gfx_ensure_atlas(gfx);
|
||||
if (result != PXL8_OK) return result;
|
||||
|
||||
pxl8_ase_file ase_file;
|
||||
pxl8_result result = pxl8_ase_load(path, &ase_file);
|
||||
result = pxl8_ase_load(path, &ase_file);
|
||||
if (result != PXL8_OK) {
|
||||
pxl8_error("Failed to load ASE file: %s", path);
|
||||
return result;
|
||||
|
|
@ -252,11 +245,14 @@ pxl8_result pxl8_gfx_load_sprite(pxl8_gfx* gfx, const char* path) {
|
|||
}
|
||||
|
||||
if (gfx->sprite_cache_count >= gfx->sprite_cache_capacity) {
|
||||
gfx->sprite_cache_capacity *= 2;
|
||||
gfx->sprite_cache = (pxl8_sprite_cache_entry*)realloc(
|
||||
u32 new_capacity = gfx->sprite_cache_capacity * 2;
|
||||
pxl8_sprite_cache_entry* new_cache = (pxl8_sprite_cache_entry*)realloc(
|
||||
gfx->sprite_cache,
|
||||
gfx->sprite_cache_capacity * sizeof(pxl8_sprite_cache_entry)
|
||||
new_capacity * sizeof(pxl8_sprite_cache_entry)
|
||||
);
|
||||
if (!new_cache) return PXL8_ERROR_OUT_OF_MEMORY;
|
||||
gfx->sprite_cache = new_cache;
|
||||
gfx->sprite_cache_capacity = new_capacity;
|
||||
}
|
||||
|
||||
pxl8_sprite_cache_entry* entry = &gfx->sprite_cache[gfx->sprite_cache_count++];
|
||||
|
|
@ -271,10 +267,7 @@ pxl8_result pxl8_gfx_load_sprite(pxl8_gfx* gfx, const char* path) {
|
|||
pxl8_atlas* pxl8_gfx_get_atlas(pxl8_gfx* gfx) {
|
||||
if (!gfx || !gfx->initialized) return NULL;
|
||||
|
||||
if (!gfx->atlas) {
|
||||
gfx->atlas = pxl8_atlas_create(1024, 1024, gfx->color_mode);
|
||||
}
|
||||
|
||||
if (pxl8_gfx_ensure_atlas(gfx) != PXL8_OK) return NULL;
|
||||
return gfx->atlas;
|
||||
}
|
||||
|
||||
|
|
@ -369,14 +362,13 @@ void pxl8_gfx_project(pxl8_gfx* gfx, f32 left, f32 right, f32 top, f32 bottom) {
|
|||
void pxl8_clear(pxl8_gfx* gfx, u32 color) {
|
||||
if (!gfx || !gfx->framebuffer) return;
|
||||
|
||||
|
||||
i32 bytes_per_pixel = (gfx->color_mode == PXL8_COLOR_MODE_HICOLOR) ? 4 : 1;
|
||||
i32 size = gfx->framebuffer_width * gfx->framebuffer_height;
|
||||
|
||||
if (bytes_per_pixel == 4) {
|
||||
u32* fb32 = (u32*)gfx->framebuffer;
|
||||
if (gfx->color_mode == PXL8_COLOR_MODE_HICOLOR) {
|
||||
u16* fb16 = (u16*)gfx->framebuffer;
|
||||
u16 color16 = pxl8_rgba32_to_rgb565(color);
|
||||
for (i32 i = 0; i < size; i++) {
|
||||
fb32[i] = color;
|
||||
fb16[i] = color16;
|
||||
}
|
||||
} else {
|
||||
memset(gfx->framebuffer, color & 0xFF, size);
|
||||
|
|
@ -386,10 +378,10 @@ void pxl8_clear(pxl8_gfx* gfx, u32 color) {
|
|||
void pxl8_pixel(pxl8_gfx* gfx, i32 x, i32 y, u32 color) {
|
||||
if (!gfx || !gfx->framebuffer) return;
|
||||
if (x < 0 || x >= gfx->framebuffer_width || y < 0 || y >= gfx->framebuffer_height) return;
|
||||
|
||||
|
||||
i32 idx = y * gfx->framebuffer_width + x;
|
||||
if (gfx->color_mode == PXL8_COLOR_MODE_HICOLOR) {
|
||||
((u32*)gfx->framebuffer)[idx] = color;
|
||||
((u16*)gfx->framebuffer)[idx] = pxl8_rgba32_to_rgb565(color);
|
||||
} else {
|
||||
gfx->framebuffer[idx] = color & 0xFF;
|
||||
}
|
||||
|
|
@ -398,10 +390,10 @@ void pxl8_pixel(pxl8_gfx* gfx, i32 x, i32 y, u32 color) {
|
|||
u32 pxl8_get_pixel(pxl8_gfx* gfx, i32 x, i32 y) {
|
||||
if (!gfx || !gfx->framebuffer) return 0;
|
||||
if (x < 0 || x >= gfx->framebuffer_width || y < 0 || y >= gfx->framebuffer_height) return 0;
|
||||
|
||||
|
||||
i32 idx = y * gfx->framebuffer_width + x;
|
||||
if (gfx->color_mode == PXL8_COLOR_MODE_HICOLOR) {
|
||||
return ((u32*)gfx->framebuffer)[idx];
|
||||
return pxl8_rgb565_to_rgba32(((u16*)gfx->framebuffer)[idx]);
|
||||
} else {
|
||||
return gfx->framebuffer[idx];
|
||||
}
|
||||
|
|
@ -445,7 +437,7 @@ void pxl8_rect(pxl8_gfx* gfx, i32 x, i32 y, i32 w, i32 h, u32 color) {
|
|||
static inline void pxl8_pixel_unchecked(pxl8_gfx* gfx, i32 x, i32 y, u32 color) {
|
||||
i32 idx = y * gfx->framebuffer_width + x;
|
||||
if (gfx->color_mode == PXL8_COLOR_MODE_HICOLOR) {
|
||||
((u32*)gfx->framebuffer)[idx] = color;
|
||||
((u16*)gfx->framebuffer)[idx] = pxl8_rgba32_to_rgb565(color);
|
||||
} else {
|
||||
gfx->framebuffer[idx] = color & 0xFF;
|
||||
}
|
||||
|
|
@ -543,7 +535,7 @@ void pxl8_text(pxl8_gfx* gfx, const char* text, i32 x, i32 y, u32 color) {
|
|||
if (pixel_bit) {
|
||||
i32 fb_idx = py * gfx->framebuffer_width + px;
|
||||
if (gfx->color_mode == PXL8_COLOR_MODE_HICOLOR) {
|
||||
((u32*)gfx->framebuffer)[fb_idx] = color;
|
||||
((u16*)gfx->framebuffer)[fb_idx] = pxl8_rgba32_to_rgb565(color);
|
||||
} else {
|
||||
gfx->framebuffer[fb_idx] = (u8)color;
|
||||
}
|
||||
|
|
@ -582,17 +574,17 @@ void pxl8_sprite(pxl8_gfx* gfx, u32 sprite_id, i32 x, i32 y, i32 w, i32 h) {
|
|||
const u8* atlas_pixels = pxl8_atlas_get_pixels(gfx->atlas);
|
||||
|
||||
if (is_1to1_scale && is_unclipped) {
|
||||
const u8* sprite_data = atlas_pixels + entry->y * atlas_width + entry->x;
|
||||
|
||||
if (gfx->color_mode == PXL8_COLOR_MODE_HICOLOR) {
|
||||
const u16* sprite_data = (const u16*)atlas_pixels + entry->y * atlas_width + entry->x;
|
||||
pxl8_blit_hicolor(
|
||||
(u32*)gfx->framebuffer,
|
||||
(u16*)gfx->framebuffer,
|
||||
gfx->framebuffer_width,
|
||||
(const u32*)sprite_data,
|
||||
sprite_data,
|
||||
atlas_width,
|
||||
x, y, w, h
|
||||
);
|
||||
} else {
|
||||
const u8* sprite_data = atlas_pixels + entry->y * atlas_width + entry->x;
|
||||
pxl8_blit_indexed(
|
||||
gfx->framebuffer,
|
||||
gfx->framebuffer_width,
|
||||
|
|
@ -610,9 +602,9 @@ void pxl8_sprite(pxl8_gfx* gfx, u32 sprite_id, i32 x, i32 y, i32 w, i32 h) {
|
|||
i32 dest_idx = (dest_y + py) * gfx->framebuffer_width + (dest_x + px);
|
||||
|
||||
if (gfx->color_mode == PXL8_COLOR_MODE_HICOLOR) {
|
||||
u32 pixel = ((const u32*)atlas_pixels)[src_idx];
|
||||
if (pixel & 0xFF000000) {
|
||||
((u32*)gfx->framebuffer)[dest_idx] = pixel;
|
||||
u16 pixel = ((const u16*)atlas_pixels)[src_idx];
|
||||
if (pixel != 0) {
|
||||
((u16*)gfx->framebuffer)[dest_idx] = pixel;
|
||||
}
|
||||
} else {
|
||||
u8 pixel = atlas_pixels[src_idx];
|
||||
|
|
@ -655,18 +647,18 @@ void pxl8_gfx_fade_palette(pxl8_gfx* gfx, u8 start, u8 count, f32 amount, u32 ta
|
|||
if (amount > 1.0f) amount = 1.0f;
|
||||
|
||||
u8 target_r, target_g, target_b, target_a;
|
||||
pxl8_color_unpack(target_color, &target_r, &target_g, &target_b, &target_a);
|
||||
pxl8_rgba32_unpack(target_color, &target_r, &target_g, &target_b, &target_a);
|
||||
|
||||
for (u8 i = 0; i < count && (start + i) < gfx->palette_size; i++) {
|
||||
u8 cur_r, cur_g, cur_b, cur_a;
|
||||
pxl8_color_unpack(gfx->palette[start + i], &cur_r, &cur_g, &cur_b, &cur_a);
|
||||
pxl8_rgba32_unpack(gfx->palette[start + i], &cur_r, &cur_g, &cur_b, &cur_a);
|
||||
|
||||
u8 new_r = pxl8_color_lerp_channel(cur_r, target_r, amount);
|
||||
u8 new_g = pxl8_color_lerp_channel(cur_g, target_g, amount);
|
||||
u8 new_b = pxl8_color_lerp_channel(cur_b, target_b, amount);
|
||||
u8 new_a = pxl8_color_lerp_channel(cur_a, target_a, amount);
|
||||
|
||||
gfx->palette[start + i] = pxl8_color_pack(new_r, new_g, new_b, new_a);
|
||||
gfx->palette[start + i] = pxl8_rgba32_pack(new_r, new_g, new_b, new_a);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -685,15 +677,15 @@ void pxl8_gfx_interpolate_palettes(
|
|||
|
||||
for (u8 i = 0; i < count && (start + i) < gfx->palette_size; i++) {
|
||||
u8 r1, g1, b1, a1, r2, g2, b2, a2;
|
||||
pxl8_color_unpack(palette1[i], &r1, &g1, &b1, &a1);
|
||||
pxl8_color_unpack(palette2[i], &r2, &g2, &b2, &a2);
|
||||
pxl8_rgba32_unpack(palette1[i], &r1, &g1, &b1, &a1);
|
||||
pxl8_rgba32_unpack(palette2[i], &r2, &g2, &b2, &a2);
|
||||
|
||||
u8 r = pxl8_color_lerp_channel(r1, r2, t);
|
||||
u8 g = pxl8_color_lerp_channel(g1, g2, t);
|
||||
u8 b = pxl8_color_lerp_channel(b1, b2, t);
|
||||
u8 a = pxl8_color_lerp_channel(a1, a2, t);
|
||||
|
||||
gfx->palette[start + i] = pxl8_color_pack(r, g, b, a);
|
||||
gfx->palette[start + i] = pxl8_rgba32_pack(r, g, b, a);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -702,8 +694,8 @@ void pxl8_gfx_color_ramp(pxl8_gfx* gfx, u8 start, u8 count, u32 from_color, u32
|
|||
|
||||
u8 from_r, from_g, from_b, from_a;
|
||||
u8 to_r, to_g, to_b, to_a;
|
||||
pxl8_color_unpack(from_color, &from_r, &from_g, &from_b, &from_a);
|
||||
pxl8_color_unpack(to_color, &to_r, &to_g, &to_b, &to_a);
|
||||
pxl8_rgba32_unpack(from_color, &from_r, &from_g, &from_b, &from_a);
|
||||
pxl8_rgba32_unpack(to_color, &to_r, &to_g, &to_b, &to_a);
|
||||
|
||||
for (u8 i = 0; i < count && (start + i) < gfx->palette_size; i++) {
|
||||
f32 t = (f32)i / (f32)(count - 1);
|
||||
|
|
@ -713,7 +705,7 @@ void pxl8_gfx_color_ramp(pxl8_gfx* gfx, u8 start, u8 count, u32 from_color, u32
|
|||
u8 b = pxl8_color_lerp_channel(from_b, to_b, t);
|
||||
u8 a = pxl8_color_lerp_channel(from_a, to_a, t);
|
||||
|
||||
gfx->palette[start + i] = pxl8_color_pack(r, g, b, a);
|
||||
gfx->palette[start + i] = pxl8_rgba32_pack(r, g, b, a);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -872,12 +864,13 @@ static inline void pxl8_fill_scanline(pxl8_gfx* gfx, i32 y, i32 xs, i32 xe, f32
|
|||
i32 fb_offset = y * gfx->framebuffer_width;
|
||||
|
||||
if (gfx->color_mode == PXL8_COLOR_MODE_HICOLOR) {
|
||||
u32* fb = (u32*)gfx->framebuffer;
|
||||
u16* fb = (u16*)gfx->framebuffer;
|
||||
u16 color16 = pxl8_rgba32_to_rgb565(color);
|
||||
if (width == 0) {
|
||||
i32 idx = zbuf_offset + xs;
|
||||
if (z0 <= gfx->zbuffer[idx]) {
|
||||
gfx->zbuffer[idx] = z0;
|
||||
fb[fb_offset + xs] = color;
|
||||
fb[fb_offset + xs] = color16;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -889,7 +882,7 @@ static inline void pxl8_fill_scanline(pxl8_gfx* gfx, i32 y, i32 xs, i32 xe, f32
|
|||
i32 idx = zbuf_offset + x;
|
||||
if (z <= gfx->zbuffer[idx]) {
|
||||
gfx->zbuffer[idx] = z;
|
||||
fb[fb_offset + x] = color;
|
||||
fb[fb_offset + x] = color16;
|
||||
}
|
||||
z += dz;
|
||||
}
|
||||
|
|
@ -946,7 +939,7 @@ static inline void pxl8_fill_scanline_textured(
|
|||
i32 tex_mask = tex_w - 1;
|
||||
i32 atlas_x_base = entry->x;
|
||||
i32 atlas_y_base = entry->y;
|
||||
bool is_hicolor = (gfx->color_mode == PXL8_COLOR_MODE_HICOLOR);
|
||||
bool is_hicolor = gfx->color_mode == PXL8_COLOR_MODE_HICOLOR;
|
||||
bool affine = gfx->affine_textures;
|
||||
|
||||
i32 span = xe - xs;
|
||||
|
|
@ -975,17 +968,18 @@ static inline void pxl8_fill_scanline_textured(
|
|||
}
|
||||
|
||||
i32 atlas_idx = (atlas_y_base + ty) * atlas_width + (atlas_x_base + tx);
|
||||
u32 color = is_hicolor ? ((const u32*)atlas_pixels)[atlas_idx] : atlas_pixels[atlas_idx];
|
||||
|
||||
if (is_hicolor) {
|
||||
if (color & 0xFF000000) {
|
||||
gfx->zbuffer[idx] = z0;
|
||||
((u32*)gfx->framebuffer)[y * gfx->framebuffer_width + xs] = color;
|
||||
}
|
||||
} else {
|
||||
u16 color = ((const u16*)atlas_pixels)[atlas_idx];
|
||||
if (color != 0) {
|
||||
gfx->zbuffer[idx] = z0;
|
||||
gfx->framebuffer[y * gfx->framebuffer_width + xs] = (u8)color;
|
||||
((u16*)gfx->framebuffer)[y * gfx->framebuffer_width + xs] = color;
|
||||
}
|
||||
} else {
|
||||
u8 color = atlas_pixels[atlas_idx];
|
||||
if (color != 0) {
|
||||
gfx->zbuffer[idx] = z0;
|
||||
gfx->framebuffer[y * gfx->framebuffer_width + xs] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1030,17 +1024,18 @@ static inline void pxl8_fill_scanline_textured(
|
|||
}
|
||||
|
||||
i32 atlas_idx = (atlas_y_base + ty) * atlas_width + (atlas_x_base + tx);
|
||||
u32 color = is_hicolor ? ((const u32*)atlas_pixels)[atlas_idx] : atlas_pixels[atlas_idx];
|
||||
|
||||
if (is_hicolor) {
|
||||
if (color & 0xFF000000) {
|
||||
gfx->zbuffer[idx] = z;
|
||||
((u32*)gfx->framebuffer)[y * gfx->framebuffer_width + x] = color;
|
||||
}
|
||||
} else {
|
||||
u16 color = ((const u16*)atlas_pixels)[atlas_idx];
|
||||
if (color != 0) {
|
||||
gfx->zbuffer[idx] = z;
|
||||
gfx->framebuffer[y * gfx->framebuffer_width + x] = (u8)color;
|
||||
((u16*)gfx->framebuffer)[y * gfx->framebuffer_width + x] = color;
|
||||
}
|
||||
} else {
|
||||
u8 color = atlas_pixels[atlas_idx];
|
||||
if (color != 0) {
|
||||
gfx->zbuffer[idx] = z;
|
||||
gfx->framebuffer[y * gfx->framebuffer_width + x] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue