This commit is contained in:
asrael 2025-09-28 13:10:29 -05:00
parent 9f96626ea7
commit 6a02b24ae6
29 changed files with 653 additions and 583 deletions

View file

@ -1,6 +1,6 @@
#include <SDL3/SDL.h>
#include <stdlib.h>
#include <string.h>
#include <SDL3/SDL.h>
#define MINIZ_NO_STDIO
#define MINIZ_NO_TIME
@ -89,8 +89,7 @@ static pxl8_result parse_old_palette_chunk(const u8* data, pxl8_ase_palette* pal
u8 r = packet_data[0];
u8 g = packet_data[1];
u8 b = packet_data[2];
// Store in ABGR format for GPU
palette->colors[color_index] = 0xFF000000 | (b << 16) | (g << 8) | r;
packet_data += 3;
}
@ -100,16 +99,12 @@ static pxl8_result parse_old_palette_chunk(const u8* data, pxl8_ase_palette* pal
}
static pxl8_result parse_layer_chunk(const u8* data, pxl8_ase_layer* layer) {
layer->flags = read_u16_le(data); // Offset 0: flags (2 bytes)
layer->layer_type = read_u16_le(data + 2); // Offset 2: layer_type (2 bytes)
layer->child_level = read_u16_le(data + 4); // Offset 4: child_level (2 bytes)
// Offset 6: default_width (2 bytes) - skip
// Offset 8: default_height (2 bytes) - skip
layer->blend_mode = read_u16_le(data + 10); // Offset 10: blend_mode (2 bytes)
layer->opacity = data[12]; // Offset 12: opacity (1 byte)
// Offset 13-15: reserved (3 bytes) - skip
// Offset 16: name length (2 bytes), then name string at offset 18
layer->flags = read_u16_le(data);
layer->layer_type = read_u16_le(data + 2);
layer->child_level = read_u16_le(data + 4);
layer->blend_mode = read_u16_le(data + 10);
layer->opacity = data[12];
u16 name_len = read_u16_le(data + 16);
if (name_len > 0) {
layer->name = (char*)SDL_malloc(name_len + 1);
@ -124,9 +119,9 @@ static pxl8_result parse_layer_chunk(const u8* data, pxl8_ase_layer* layer) {
}
static pxl8_result parse_palette_chunk(const u8* data, pxl8_ase_palette* palette) {
palette->entry_count = read_u32_le(data); // Offset 0: entry_count (4 bytes)
palette->first_color = read_u32_le(data + 4); // Offset 4: first_color (4 bytes)
palette->last_color = read_u32_le(data + 8); // Offset 8: last_color (4 bytes)
palette->entry_count = read_u32_le(data);
palette->first_color = read_u32_le(data + 4);
palette->last_color = read_u32_le(data + 8);
u32 color_count = palette->entry_count;
palette->colors = (u32*)SDL_malloc(color_count * sizeof(u32));
@ -134,15 +129,14 @@ static pxl8_result parse_palette_chunk(const u8* data, pxl8_ase_palette* palette
return PXL8_ERROR_OUT_OF_MEMORY;
}
const u8* color_data = data + 20; // Skip palette header (20 bytes)
const u8* color_data = data + 20;
for (u32 i = 0; i < color_count; i++) {
u16 flags = read_u16_le(color_data); // Offset 0: flags (2 bytes)
u8 r = color_data[2]; // Offset 2: red (1 byte)
u8 g = color_data[3]; // Offset 3: green (1 byte)
u8 b = color_data[4]; // Offset 4: blue (1 byte)
u8 a = color_data[5]; // Offset 5: alpha (1 byte)
// Store in ABGR format for GPU
u16 flags = read_u16_le(color_data);
u8 r = color_data[2];
u8 g = color_data[3];
u8 b = color_data[4];
u8 a = color_data[5];
palette->colors[i] = (a << 24) | (b << 16) | (g << 8) | r;
color_data += 6;
@ -160,21 +154,19 @@ static pxl8_result parse_cel_chunk(const u8* data, u32 chunk_size, pxl8_ase_cel*
return PXL8_ERROR_ASE_MALFORMED_CHUNK;
}
cel->layer_index = read_u16_le(data); // Offset 0: layer_index (2 bytes)
cel->x = read_i16_le(data + 2); // Offset 2: x (2 bytes)
cel->y = read_i16_le(data + 4); // Offset 4: y (2 bytes)
cel->opacity = data[6]; // Offset 6: opacity (1 byte)
cel->cel_type = read_u16_le(data + 7); // Offset 7: cel_type (2 bytes)
cel->layer_index = read_u16_le(data);
cel->x = read_i16_le(data + 2);
cel->y = read_i16_le(data + 4);
cel->opacity = data[6];
cel->cel_type = read_u16_le(data + 7);
if (cel->cel_type == 2) {
if (chunk_size < 20) {
return PXL8_ERROR_ASE_MALFORMED_CHUNK;
}
// Offset 9: Z-Index (2 bytes) - skip
// Offset 11: Reserved (5 bytes) - skip
cel->width = read_u16_le(data + 16); // Offset 16: width (2 bytes)
cel->height = read_u16_le(data + 18); // Offset 18: height (2 bytes)
cel->width = read_u16_le(data + 16);
cel->height = read_u16_le(data + 18);
u32 pixel_data_size = cel->width * cel->height;
u32 compressed_data_size = chunk_size - 20;
@ -183,8 +175,7 @@ static pxl8_result parse_cel_chunk(const u8* data, u32 chunk_size, pxl8_ase_cel*
if (!cel->pixel_data) {
return PXL8_ERROR_OUT_OF_MEMORY;
}
// Decompress ZLIB data
mz_ulong dest_len = pixel_data_size;
int result = mz_uncompress(cel->pixel_data, &dest_len, data + 20, compressed_data_size);
if (result != MZ_OK) {
@ -274,16 +265,17 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) {
case PXL8_ASE_CHUNK_OLD_PALETTE: // 0x0004
if (!ase_file->palette.colors) {
result = parse_old_palette_chunk(chunk_payload, &ase_file->palette);
pxl8_debug("Parsed old palette: %d colors, indices %d-%d", ase_file->palette.entry_count, ase_file->palette.first_color, ase_file->palette.last_color);
pxl8_debug("Parsed old palette: %d colors, indices %d-%d",
ase_file->palette.entry_count, ase_file->palette.first_color, ase_file->palette.last_color);
} else {
pxl8_debug("Ignoring old palette (0x0004) - new palette (0x2019) already loaded");
}
break;
case PXL8_ASE_CHUNK_LAYER: { // 0x2004
// Need to allocate or reallocate layers array
ase_file->layers = (pxl8_ase_layer*)SDL_realloc(ase_file->layers,
(ase_file->layer_count + 1) * sizeof(pxl8_ase_layer));
ase_file->layers =
(pxl8_ase_layer*)SDL_realloc(ase_file->layers,
(ase_file->layer_count + 1) * sizeof(pxl8_ase_layer));
if (!ase_file->layers) {
result = PXL8_ERROR_OUT_OF_MEMORY;
break;
@ -315,15 +307,12 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) {
u32 src_offset = y * cel.width;
u32 dst_offset = (y + cel.y) * frame->width + cel.x;
if (dst_offset + copy_width <= pixel_count) {
// Composite layers: only copy non-transparent pixels
// Check if palette color is transparent (#00000000)
for (u32 x = 0; x < copy_width; x++) {
u8 src_pixel = cel.pixel_data[src_offset + x];
bool is_transparent = false;
if (src_pixel < ase_file->palette.entry_count && ase_file->palette.colors) {
u32 color = ase_file->palette.colors[src_pixel];
// Check if color is fully transparent (alpha = 0)
is_transparent = ((color >> 24) & 0xFF) == 0;
}
@ -331,9 +320,9 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) {
frame->pixels[dst_offset + x] = src_pixel;
}
}
// Debug: check first few pixels of each row
if (y < 3) {
pxl8_debug("Row %d: cel[%d]=%d, frame[%d]=%d", y, src_offset, cel.pixel_data[src_offset], dst_offset, frame->pixels[dst_offset]);
pxl8_debug("Row %d: cel[%d]=%d, frame[%d]=%d",
y, src_offset, cel.pixel_data[src_offset], dst_offset, frame->pixels[dst_offset]);
}
}
}
@ -347,7 +336,8 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) {
SDL_free(ase_file->palette.colors);
}
result = parse_palette_chunk(chunk_payload, &ase_file->palette);
pxl8_debug("Parsed new palette: %d colors, indices %d-%d", ase_file->palette.entry_count, ase_file->palette.first_color, ase_file->palette.last_color);
pxl8_debug("Parsed new palette: %d colors, indices %d-%d",
ase_file->palette.entry_count, ase_file->palette.first_color, ase_file->palette.last_color);
break;
default:
@ -355,10 +345,12 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) {
}
if (result != PXL8_OK) break;
chunk_data += chunk_header.chunk_size;
}
if (result != PXL8_OK) break;
frame_data += frame_header.frame_bytes;
}