better lighting
This commit is contained in:
parent
805a2713a3
commit
6ed4e17065
75 changed files with 6417 additions and 3667 deletions
|
|
@ -7,11 +7,11 @@
|
|||
#define MINIZ_NO_TIME
|
||||
#define MINIZ_NO_ARCHIVE_APIS
|
||||
#define MINIZ_NO_ARCHIVE_WRITING_APIS
|
||||
#define MINIZ_NO_DEFLATE_APIS
|
||||
#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
|
||||
|
||||
#include <miniz.h>
|
||||
|
||||
#include "pxl8_color.h"
|
||||
#include "pxl8_io.h"
|
||||
#include "pxl8_log.h"
|
||||
#include "pxl8_mem.h"
|
||||
|
|
@ -635,3 +635,302 @@ void pxl8_ase_destroy(pxl8_ase_file* ase_file) {
|
|||
|
||||
memset(ase_file, 0, sizeof(pxl8_ase_file));
|
||||
}
|
||||
|
||||
pxl8_result pxl8_ase_load_palette(const char* filepath, u32* colors, u32* count) {
|
||||
if (!filepath || !colors || !count) {
|
||||
return PXL8_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
pxl8_ase_file ase;
|
||||
pxl8_result result = pxl8_ase_load(filepath, &ase);
|
||||
if (result != PXL8_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
u32 n = ase.palette.entry_count;
|
||||
if (n > 256) n = 256;
|
||||
|
||||
for (u32 i = 0; i < n; i++) {
|
||||
colors[i] = ase.palette.colors[i];
|
||||
}
|
||||
*count = n;
|
||||
|
||||
pxl8_ase_destroy(&ase);
|
||||
return PXL8_OK;
|
||||
}
|
||||
|
||||
pxl8_result pxl8_ase_remap(const char* input_path, const char* output_path, const pxl8_ase_remap_config* config) {
|
||||
if (!input_path || !output_path || !config) {
|
||||
return PXL8_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (!config->palette || config->palette_count == 0) {
|
||||
return PXL8_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
f32 hue_tol = config->hue_tolerance > 0.0f ? config->hue_tolerance : 0.08f;
|
||||
|
||||
u8* file_data;
|
||||
usize file_size;
|
||||
pxl8_result result = pxl8_io_read_binary_file(input_path, &file_data, &file_size);
|
||||
if (result != PXL8_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (file_size < 128) {
|
||||
pxl8_io_free_binary_data(file_data);
|
||||
return PXL8_ERROR_ASE_TRUNCATED_FILE;
|
||||
}
|
||||
|
||||
u8* output_data = (u8*)pxl8_malloc(file_size + 65536);
|
||||
if (!output_data) {
|
||||
pxl8_io_free_binary_data(file_data);
|
||||
return PXL8_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
memcpy(output_data, file_data, file_size);
|
||||
|
||||
pxl8_stream stream = pxl8_stream_create(file_data, (u32)file_size);
|
||||
pxl8_stream_seek(&stream, 128);
|
||||
|
||||
u32 frame_start = 128;
|
||||
u32 frame_size = pxl8_read_u32(&stream);
|
||||
pxl8_skip_bytes(&stream, 2);
|
||||
u16 old_chunks = pxl8_read_u16(&stream);
|
||||
pxl8_skip_bytes(&stream, 2);
|
||||
u16 num_chunks = old_chunks;
|
||||
if (old_chunks == 0xFFFF || old_chunks == 0xFFFE) {
|
||||
num_chunks = (u16)pxl8_read_u32(&stream);
|
||||
} else {
|
||||
pxl8_skip_bytes(&stream, 4);
|
||||
}
|
||||
|
||||
u32 palette_chunk_offset = 0;
|
||||
u32 palette_entry_start = 0;
|
||||
u32 orig_colors[256] = {0};
|
||||
|
||||
u32 chunk_offset = frame_start + 16;
|
||||
for (u16 c = 0; c < num_chunks; c++) {
|
||||
pxl8_stream_seek(&stream, chunk_offset);
|
||||
u32 chunk_size = pxl8_read_u32(&stream);
|
||||
u16 chunk_type = pxl8_read_u16(&stream);
|
||||
|
||||
if (chunk_type == PXL8_ASE_CHUNK_PALETTE) {
|
||||
palette_chunk_offset = chunk_offset;
|
||||
pxl8_skip_bytes(&stream, 4);
|
||||
u32 first_color = pxl8_read_u32(&stream);
|
||||
u32 last_color = pxl8_read_u32(&stream);
|
||||
pxl8_skip_bytes(&stream, 8);
|
||||
palette_entry_start = pxl8_stream_position(&stream);
|
||||
|
||||
for (u32 i = first_color; i <= last_color && i < 256; i++) {
|
||||
u16 flags = pxl8_read_u16(&stream);
|
||||
u8 r = pxl8_read_u8(&stream);
|
||||
u8 g = pxl8_read_u8(&stream);
|
||||
u8 b = pxl8_read_u8(&stream);
|
||||
pxl8_skip_bytes(&stream, 1);
|
||||
orig_colors[i] = r | (g << 8) | (b << 16);
|
||||
if (flags & 1) {
|
||||
u16 name_len = pxl8_read_u16(&stream);
|
||||
pxl8_skip_bytes(&stream, name_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
chunk_offset += chunk_size;
|
||||
}
|
||||
|
||||
if (palette_entry_start == 0) {
|
||||
pxl8_free(output_data);
|
||||
pxl8_io_free_binary_data(file_data);
|
||||
return PXL8_ERROR_ASE_MALFORMED_CHUNK;
|
||||
}
|
||||
|
||||
u8 remap[256];
|
||||
bool used[256] = {0};
|
||||
for (u32 i = 0; i < 256; i++) {
|
||||
u32 src = orig_colors[i];
|
||||
f32 src_hue = pxl8_color_hue(src);
|
||||
f32 src_sat = pxl8_color_saturation(src);
|
||||
f32 src_lum = pxl8_color_luminance(src);
|
||||
|
||||
u32 best_idx = 0;
|
||||
f32 best_score = 999999.0f;
|
||||
|
||||
for (u32 j = 0; j < config->palette_count; j++) {
|
||||
u32 tgt = config->palette[j];
|
||||
f32 tgt_hue = pxl8_color_hue(tgt);
|
||||
f32 tgt_sat = pxl8_color_saturation(tgt);
|
||||
f32 tgt_lum = pxl8_color_luminance(tgt);
|
||||
|
||||
f32 hue_diff = pxl8_color_hue_diff(src_hue, tgt_hue);
|
||||
f32 lum_diff = src_lum > tgt_lum ? src_lum - tgt_lum : tgt_lum - src_lum;
|
||||
f32 sat_diff = src_sat > tgt_sat ? src_sat - tgt_sat : tgt_sat - src_sat;
|
||||
|
||||
f32 score;
|
||||
if (src_sat < 0.1f) {
|
||||
score = lum_diff + sat_diff * 100.0f;
|
||||
} else if (hue_diff <= hue_tol) {
|
||||
score = lum_diff + sat_diff * 50.0f;
|
||||
} else {
|
||||
score = hue_diff * 1000.0f + lum_diff;
|
||||
}
|
||||
|
||||
if (score < best_score) {
|
||||
best_score = score;
|
||||
best_idx = j;
|
||||
}
|
||||
}
|
||||
remap[i] = (u8)best_idx;
|
||||
used[best_idx] = true;
|
||||
}
|
||||
|
||||
u8 compact[256];
|
||||
u32 compact_colors[256];
|
||||
u32 compact_count = 0;
|
||||
for (u32 i = 0; i < config->palette_count; i++) {
|
||||
if (used[i]) {
|
||||
compact[i] = (u8)compact_count;
|
||||
compact_colors[compact_count] = config->palette[i];
|
||||
compact_count++;
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < 256; i++) {
|
||||
remap[i] = compact[remap[i]];
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < compact_count; i++) {
|
||||
u32 offset = palette_entry_start + i * 6;
|
||||
u32 color = compact_colors[i];
|
||||
output_data[offset + 0] = 0;
|
||||
output_data[offset + 1] = 0;
|
||||
output_data[offset + 2] = color & 0xFF;
|
||||
output_data[offset + 3] = (color >> 8) & 0xFF;
|
||||
output_data[offset + 4] = (color >> 16) & 0xFF;
|
||||
output_data[offset + 5] = 0xFF;
|
||||
}
|
||||
|
||||
u32 new_last_color = compact_count > 0 ? compact_count - 1 : 0;
|
||||
output_data[palette_chunk_offset + 6] = compact_count & 0xFF;
|
||||
output_data[palette_chunk_offset + 7] = (compact_count >> 8) & 0xFF;
|
||||
output_data[palette_chunk_offset + 8] = (compact_count >> 16) & 0xFF;
|
||||
output_data[palette_chunk_offset + 9] = (compact_count >> 24) & 0xFF;
|
||||
output_data[palette_chunk_offset + 14] = new_last_color & 0xFF;
|
||||
output_data[palette_chunk_offset + 15] = (new_last_color >> 8) & 0xFF;
|
||||
output_data[palette_chunk_offset + 16] = (new_last_color >> 16) & 0xFF;
|
||||
output_data[palette_chunk_offset + 17] = (new_last_color >> 24) & 0xFF;
|
||||
|
||||
chunk_offset = frame_start + 16;
|
||||
usize output_size = file_size;
|
||||
|
||||
for (u16 c = 0; c < num_chunks; c++) {
|
||||
pxl8_stream_seek(&stream, chunk_offset);
|
||||
u32 chunk_size = pxl8_read_u32(&stream);
|
||||
u16 chunk_type = pxl8_read_u16(&stream);
|
||||
|
||||
if (chunk_type == PXL8_ASE_CHUNK_CEL) {
|
||||
pxl8_skip_bytes(&stream, 7);
|
||||
u16 cel_type = pxl8_read_u16(&stream);
|
||||
|
||||
if (cel_type == 2) {
|
||||
pxl8_skip_bytes(&stream, 7);
|
||||
u16 width = pxl8_read_u16(&stream);
|
||||
u16 height = pxl8_read_u16(&stream);
|
||||
u32 pixels_size = width * height;
|
||||
u32 compressed_start = pxl8_stream_position(&stream);
|
||||
u32 compressed_size = chunk_size - (compressed_start - chunk_offset);
|
||||
|
||||
u8* pixels = (u8*)pxl8_malloc(pixels_size);
|
||||
if (!pixels) {
|
||||
pxl8_free(output_data);
|
||||
pxl8_io_free_binary_data(file_data);
|
||||
return PXL8_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
const u8* compressed_data = file_data + compressed_start;
|
||||
mz_ulong dest_len = pixels_size;
|
||||
i32 mz_result = mz_uncompress(pixels, &dest_len, compressed_data, compressed_size);
|
||||
if (mz_result != MZ_OK) {
|
||||
pxl8_free(pixels);
|
||||
pxl8_free(output_data);
|
||||
pxl8_io_free_binary_data(file_data);
|
||||
return PXL8_ERROR_ASE_MALFORMED_CHUNK;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < pixels_size; i++) {
|
||||
pixels[i] = remap[pixels[i]];
|
||||
}
|
||||
|
||||
mz_ulong new_compressed_size = mz_compressBound(pixels_size);
|
||||
u8* new_compressed = (u8*)pxl8_malloc(new_compressed_size);
|
||||
if (!new_compressed) {
|
||||
pxl8_free(pixels);
|
||||
pxl8_free(output_data);
|
||||
pxl8_io_free_binary_data(file_data);
|
||||
return PXL8_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
mz_result = mz_compress2(new_compressed, &new_compressed_size, pixels, pixels_size, 6);
|
||||
pxl8_free(pixels);
|
||||
|
||||
if (mz_result != MZ_OK) {
|
||||
pxl8_free(new_compressed);
|
||||
pxl8_free(output_data);
|
||||
pxl8_io_free_binary_data(file_data);
|
||||
return PXL8_ERROR_ASE_MALFORMED_CHUNK;
|
||||
}
|
||||
|
||||
i32 size_diff = (i32)new_compressed_size - (i32)compressed_size;
|
||||
|
||||
u8* new_output = (u8*)pxl8_malloc(output_size + size_diff + 65536);
|
||||
if (!new_output) {
|
||||
pxl8_free(new_compressed);
|
||||
pxl8_free(output_data);
|
||||
pxl8_io_free_binary_data(file_data);
|
||||
return PXL8_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
memcpy(new_output, output_data, compressed_start);
|
||||
memcpy(new_output + compressed_start, new_compressed, new_compressed_size);
|
||||
memcpy(new_output + compressed_start + new_compressed_size,
|
||||
output_data + compressed_start + compressed_size,
|
||||
output_size - compressed_start - compressed_size);
|
||||
|
||||
u32 new_chunk_size = chunk_size + size_diff;
|
||||
new_output[chunk_offset + 0] = new_chunk_size & 0xFF;
|
||||
new_output[chunk_offset + 1] = (new_chunk_size >> 8) & 0xFF;
|
||||
new_output[chunk_offset + 2] = (new_chunk_size >> 16) & 0xFF;
|
||||
new_output[chunk_offset + 3] = (new_chunk_size >> 24) & 0xFF;
|
||||
|
||||
u32 new_frame_size = frame_size + size_diff;
|
||||
new_output[frame_start + 0] = new_frame_size & 0xFF;
|
||||
new_output[frame_start + 1] = (new_frame_size >> 8) & 0xFF;
|
||||
new_output[frame_start + 2] = (new_frame_size >> 16) & 0xFF;
|
||||
new_output[frame_start + 3] = (new_frame_size >> 24) & 0xFF;
|
||||
|
||||
output_size += size_diff;
|
||||
new_output[0] = output_size & 0xFF;
|
||||
new_output[1] = (output_size >> 8) & 0xFF;
|
||||
new_output[2] = (output_size >> 16) & 0xFF;
|
||||
new_output[3] = (output_size >> 24) & 0xFF;
|
||||
|
||||
pxl8_free(new_compressed);
|
||||
pxl8_free(output_data);
|
||||
output_data = new_output;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
chunk_offset += chunk_size;
|
||||
}
|
||||
|
||||
pxl8_io_free_binary_data(file_data);
|
||||
|
||||
result = pxl8_io_write_binary_file(output_path, output_data, output_size);
|
||||
pxl8_free(output_data);
|
||||
|
||||
if (result == PXL8_OK) {
|
||||
pxl8_info("Remapped %s -> %s", input_path, output_path);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,12 +141,20 @@ typedef struct pxl8_ase_file {
|
|||
pxl8_ase_tileset* tilesets;
|
||||
} pxl8_ase_file;
|
||||
|
||||
typedef struct pxl8_ase_remap_config {
|
||||
const u32* palette;
|
||||
u32 palette_count;
|
||||
f32 hue_tolerance;
|
||||
} pxl8_ase_remap_config;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file);
|
||||
pxl8_result pxl8_ase_load_palette(const char* filepath, u32* colors, u32* count);
|
||||
void pxl8_ase_destroy(pxl8_ase_file* ase_file);
|
||||
pxl8_result pxl8_ase_remap(const char* input_path, const char* output_path, const pxl8_ase_remap_config* config);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue