refactor atlas implementation

This commit is contained in:
asrael 2025-10-05 16:25:17 -05:00
parent 6008ebf5ed
commit c662c550df
12 changed files with 867 additions and 303 deletions

View file

@ -69,6 +69,22 @@ function pxl8.load_sprite(filepath)
end
end
function pxl8.create_texture(pixels, width, height)
local pixel_data = ffi.new("u8[?]", width * height)
for i = 0, width * height - 1 do
pixel_data[i] = pixels[i + 1] or 0
end
local result = C.pxl8_gfx_create_texture(gfx, pixel_data, width, height)
if result < 0 then
return nil
end
return result
end
function pxl8.upload_atlas()
C.pxl8_gfx_upload_atlas(gfx)
end
-- log
function pxl8.info(msg)
C.pxl8_lua_info(msg)
@ -267,6 +283,10 @@ function pxl8.set_wireframe(wireframe)
C.pxl8_3d_set_wireframe(gfx, wireframe)
end
function pxl8.set_affine_textures(affine)
C.pxl8_3d_set_affine_textures(gfx, affine)
end
function pxl8.set_backface_culling(culling)
C.pxl8_3d_set_backface_culling(gfx, culling)
end
@ -278,6 +298,14 @@ function pxl8.draw_triangle_3d(v0, v1, v2, color)
C.pxl8_3d_draw_triangle_raw(gfx, vec0, vec1, vec2, color)
end
function pxl8.draw_triangle_3d_textured(v0, v1, v2, uv0, uv1, uv2, texture_id)
local vec0 = ffi.new("pxl8_vec3", {x = v0[1], y = v0[2], z = v0[3]})
local vec1 = ffi.new("pxl8_vec3", {x = v1[1], y = v1[2], z = v1[3]})
local vec2 = ffi.new("pxl8_vec3", {x = v2[1], y = v2[2], z = v2[3]})
C.pxl8_3d_draw_triangle_textured(gfx, vec0, vec1, vec2,
uv0[1], uv0[2], uv1[1], uv1[2], uv2[1], uv2[2], texture_id)
end
function pxl8.draw_line_3d(p0, p1, color)
local vec0 = ffi.new("pxl8_vec3", {x = p0[1], y = p0[2], z = p0[3]})
local vec1 = ffi.new("pxl8_vec3", {x = p1[1], y = p1[2], z = p1[3]})

View file

@ -245,11 +245,6 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {
return SDL_APP_FAILURE;
}
if (pxl8_gfx_init_atlas(app.gfx, 1024, 1024) != PXL8_OK) {
pxl8_error("Failed to initialize sprite atlas");
return SDL_APP_FAILURE;
}
app.ui = pxl8_ui_create(app.gfx);
if (!app.ui) {
pxl8_error("Failed to create UI");

View file

@ -260,16 +260,11 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) {
chunk_header.chunk_type = read_u16_le(chunk_data + 4);
const u8* chunk_payload = chunk_data + 6;
pxl8_debug("Found chunk: type=0x%04X, size=%d", chunk_header.chunk_type, chunk_header.chunk_size);
switch (chunk_header.chunk_type) {
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);
} else {
pxl8_debug("Ignoring old palette (0x0004) - new palette (0x2019) already loaded");
}
break;
@ -284,11 +279,6 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) {
result = parse_layer_chunk(chunk_payload, &ase_file->layers[ase_file->layer_count]);
if (result == PXL8_OK) {
pxl8_debug("Parsed layer %d: '%s', blend_mode=%d, opacity=%d",
ase_file->layer_count,
ase_file->layers[ase_file->layer_count].name ? ase_file->layers[ase_file->layer_count].name : "(unnamed)",
ase_file->layers[ase_file->layer_count].blend_mode,
ase_file->layers[ase_file->layer_count].opacity);
ase_file->layer_count++;
}
break;
@ -296,14 +286,11 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) {
case PXL8_ASE_CHUNK_CEL: { // 0x2005
pxl8_ase_cel cel = {0};
pxl8_debug("Found CEL chunk: size=%d", chunk_header.chunk_size - 6);
result = parse_cel_chunk(chunk_payload, chunk_header.chunk_size - 6, &cel);
if (result == PXL8_OK && cel.pixel_data) {
pxl8_debug("CEL data loaded: %dx%d, type=%d, first pixel = %d", cel.width, cel.height, cel.cel_type, cel.pixel_data[0]);
u32 copy_width = (cel.width < frame->width) ? cel.width : frame->width;
u32 copy_height = (cel.height < frame->height) ? cel.height : frame->height;
pxl8_debug("Copying cel to frame: cel_pos=(%d,%d), copy_size=%dx%d", cel.x, cel.y, copy_width, copy_height);
for (u32 y = 0; y < copy_height; y++) {
u32 src_offset = y * cel.width;
u32 dst_offset = (y + cel.y) * frame->width + cel.x;
@ -311,20 +298,16 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) {
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];
is_transparent = ((color >> 24) & 0xFF) == 0;
}
if (!is_transparent) {
frame->pixels[dst_offset + x] = src_pixel;
}
}
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]);
}
}
}
SDL_free(cel.pixel_data);
@ -337,8 +320,6 @@ 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);
break;
default:

File diff suppressed because it is too large Load diff

View file

@ -3,6 +3,7 @@
#include "pxl8_math.h"
#include "pxl8_types.h"
typedef struct pxl8_atlas pxl8_atlas;
typedef struct pxl8_gfx pxl8_gfx;
typedef enum pxl8_blend_mode {
@ -48,6 +49,7 @@ typedef struct pxl8_effects {
typedef struct pxl8_triangle {
pxl8_vertex v[3];
u32 texture_id;
} pxl8_triangle;
#ifdef __cplusplus
@ -61,12 +63,13 @@ pxl8_bounds pxl8_gfx_get_bounds(pxl8_gfx* gfx);
pxl8_color_mode pxl8_gfx_get_color_mode(pxl8_gfx* gfx);
u8* pxl8_gfx_get_framebuffer(pxl8_gfx* gfx);
i32 pxl8_gfx_get_height(const pxl8_gfx* gfx);
u32 pxl8_gfx_get_palette_size(const pxl8_gfx* gfx);
void pxl8_gfx_get_resolution_dimensions(pxl8_resolution resolution, i32* width, i32* height);
i32 pxl8_gfx_get_width(const pxl8_gfx* gfx);
pxl8_result pxl8_gfx_init_atlas(pxl8_gfx* gfx, u32 width, u32 height);
pxl8_result pxl8_gfx_load_font_atlas(pxl8_gfx* gfx);
pxl8_result pxl8_gfx_load_palette(pxl8_gfx* gfx, const char* path);
pxl8_result pxl8_gfx_load_sprite(pxl8_gfx* gfx, const char* path);
pxl8_result pxl8_gfx_create_texture(pxl8_gfx* gfx, const u8* pixels, u32 width, u32 height);
void pxl8_gfx_present(pxl8_gfx* gfx);
void pxl8_gfx_project(pxl8_gfx* gfx, f32 left, f32 right, f32 top, f32 bottom);
void pxl8_gfx_upload_atlas(pxl8_gfx* gfx);
@ -96,6 +99,8 @@ void pxl8_3d_clear_zbuffer(pxl8_gfx* gfx);
void pxl8_3d_draw_line_3d(pxl8_gfx* gfx, pxl8_vec3 p0, pxl8_vec3 p1, u32 color);
void pxl8_3d_draw_triangle(pxl8_gfx* gfx, pxl8_triangle tri);
void pxl8_3d_draw_triangle_raw(pxl8_gfx* gfx, pxl8_vec3 v0, pxl8_vec3 v1, pxl8_vec3 v2, u32 color);
void pxl8_3d_draw_triangle_textured(pxl8_gfx* gfx, pxl8_vec3 v0, pxl8_vec3 v1, pxl8_vec3 v2, f32 u0, f32 v0f, f32 u1, f32 v1f, f32 u2, f32 v2f, u32 texture_id);
void pxl8_3d_set_affine_textures(pxl8_gfx* gfx, bool affine);
void pxl8_3d_set_backface_culling(pxl8_gfx* gfx, bool culling);
void pxl8_3d_set_model(pxl8_gfx* gfx, pxl8_mat4 mat);
void pxl8_3d_set_projection(pxl8_gfx* gfx, pxl8_mat4 mat);

View file

@ -4,21 +4,21 @@
#include "pxl8_simd.h"
pxl8_vec2 pxl8_vec2_add(pxl8_vec2 a, pxl8_vec2 b) {
return (pxl8_vec2) {
return (pxl8_vec2){
.x = a.x + b.x,
.y = a.y + b.y,
};
}
pxl8_vec2 pxl8_vec2_sub(pxl8_vec2 a, pxl8_vec2 b) {
return (pxl8_vec2) {
return (pxl8_vec2){
.x = a.x - b.x,
.y = a.y - b.y,
};
}
pxl8_vec2 pxl8_vec2_scale(pxl8_vec2 v, f32 s) {
return (pxl8_vec2) {
return (pxl8_vec2){
.x = v.x * s,
.y = v.y * s,
};
@ -34,7 +34,9 @@ f32 pxl8_vec2_length(pxl8_vec2 v) {
pxl8_vec2 pxl8_vec2_normalize(pxl8_vec2 v) {
f32 len = pxl8_vec2_length(v);
if (len < 1e-6f) return (pxl8_vec2){0};
return pxl8_vec2_scale(v, 1.0f / len);
}
@ -43,7 +45,7 @@ pxl8_vec3 pxl8_vec3_add(pxl8_vec3 a, pxl8_vec3 b) {
pxl8_simd_vec_f32 vb = pxl8_simd_set_f32(b.x, b.y, b.z, 0);
pxl8_simd_vec_f32 result = pxl8_simd_add_f32(va, vb);
return (pxl8_vec3) {
return (pxl8_vec3){
.x = result.f32_array[0],
.y = result.f32_array[1],
.z = result.f32_array[2],
@ -55,7 +57,7 @@ pxl8_vec3 pxl8_vec3_sub(pxl8_vec3 a, pxl8_vec3 b) {
pxl8_simd_vec_f32 vb = pxl8_simd_set_f32(b.x, b.y, b.z, 0);
pxl8_simd_vec_f32 result = pxl8_simd_sub_f32(va, vb);
return (pxl8_vec3) {
return (pxl8_vec3){
.x = result.f32_array[0],
.y = result.f32_array[1],
.z = result.f32_array[2],
@ -66,7 +68,7 @@ pxl8_vec3 pxl8_vec3_scale(pxl8_vec3 v, f32 s) {
pxl8_simd_vec_f32 vv = pxl8_simd_set_f32(v.x, v.y, v.z, 0);
pxl8_simd_vec_f32 result = pxl8_simd_scale_f32(vv, s);
return (pxl8_vec3) {
return (pxl8_vec3){
.x = result.f32_array[0],
.y = result.f32_array[1],
.z = result.f32_array[2],
@ -76,11 +78,12 @@ pxl8_vec3 pxl8_vec3_scale(pxl8_vec3 v, f32 s) {
f32 pxl8_vec3_dot(pxl8_vec3 a, pxl8_vec3 b) {
pxl8_simd_vec_f32 va = pxl8_simd_set_f32(a.x, a.y, a.z, 0);
pxl8_simd_vec_f32 vb = pxl8_simd_set_f32(b.x, b.y, b.z, 0);
return pxl8_simd_dot3_f32(va, vb);
}
pxl8_vec3 pxl8_vec3_cross(pxl8_vec3 a, pxl8_vec3 b) {
return (pxl8_vec3) {
return (pxl8_vec3){
.x = a.y * b.z - a.z * b.y,
.y = a.z * b.x - a.x * b.z,
.z = a.x * b.y - a.y * b.x,
@ -93,18 +96,23 @@ f32 pxl8_vec3_length(pxl8_vec3 v) {
pxl8_vec3 pxl8_vec3_normalize(pxl8_vec3 v) {
f32 len = pxl8_vec3_length(v);
if (len < 1e-6f) return (pxl8_vec3){0};
return pxl8_vec3_scale(v, 1.0f / len);
}
pxl8_mat4 pxl8_mat4_identity(void) {
pxl8_mat4 mat = {0};
mat.m[0] = mat.m[5] = mat.m[10] = mat.m[15] = 1.0f;
return mat;
}
pxl8_mat4 pxl8_mat4_multiply(pxl8_mat4 a, pxl8_mat4 b) {
pxl8_mat4 result = {0};
pxl8_mat4 mat = {0};
for (i32 i = 0; i < 4; i++) {
for (i32 j = 0; j < 4; j++) {
pxl8_simd_vec_f32 row = pxl8_simd_set_f32(
@ -113,34 +121,35 @@ pxl8_mat4 pxl8_mat4_multiply(pxl8_mat4 a, pxl8_mat4 b) {
pxl8_simd_vec_f32 col = pxl8_simd_set_f32(
b.m[0 * 4 + j], b.m[1 * 4 + j], b.m[2 * 4 + j], b.m[3 * 4 + j]
);
result.m[i * 4 + j] = pxl8_simd_dot4_f32(row, col);
mat.m[i * 4 + j] = pxl8_simd_dot4_f32(row, col);
}
}
return result;
return mat;
}
pxl8_vec4 pxl8_mat4_multiply_vec4(pxl8_mat4 m, pxl8_vec4 v) {
pxl8_simd_vec_f32 vec = pxl8_simd_set_f32(v.x, v.y, v.z, v.w);
pxl8_vec4 result;
pxl8_simd_vec_f32 row0 = pxl8_simd_set_f32(m.m[0], m.m[1], m.m[2], m.m[3]);
pxl8_simd_vec_f32 row1 = pxl8_simd_set_f32(m.m[4], m.m[5], m.m[6], m.m[7]);
pxl8_simd_vec_f32 row2 = pxl8_simd_set_f32(m.m[8], m.m[9], m.m[10], m.m[11]);
pxl8_simd_vec_f32 row3 = pxl8_simd_set_f32(m.m[12], m.m[13], m.m[14], m.m[15]);
pxl8_simd_vec_f32 vec = pxl8_simd_set_f32(v.x, v.y, v.z, v.w);
result.x = pxl8_simd_dot4_f32(row0, vec);
result.y = pxl8_simd_dot4_f32(row1, vec);
result.z = pxl8_simd_dot4_f32(row2, vec);
result.w = pxl8_simd_dot4_f32(row3, vec);
return result;
return (pxl8_vec4){
.x = pxl8_simd_dot4_f32(row0, vec),
.y = pxl8_simd_dot4_f32(row1, vec),
.z = pxl8_simd_dot4_f32(row2, vec),
.w = pxl8_simd_dot4_f32(row3, vec),
};
}
pxl8_mat4 pxl8_mat4_translate(f32 x, f32 y, f32 z) {
pxl8_mat4 mat = pxl8_mat4_identity();
mat.m[3] = x;
mat.m[7] = y;
mat.m[11] = z;
return mat;
}
@ -148,10 +157,12 @@ pxl8_mat4 pxl8_mat4_rotate_x(f32 angle) {
pxl8_mat4 mat = pxl8_mat4_identity();
f32 c = cosf(angle);
f32 s = sinf(angle);
mat.m[5] = c;
mat.m[6] = -s;
mat.m[9] = s;
mat.m[10] = c;
return mat;
}
@ -159,10 +170,12 @@ pxl8_mat4 pxl8_mat4_rotate_y(f32 angle) {
pxl8_mat4 mat = pxl8_mat4_identity();
f32 c = cosf(angle);
f32 s = sinf(angle);
mat.m[0] = c;
mat.m[2] = s;
mat.m[8] = -s;
mat.m[10] = c;
return mat;
}
@ -170,18 +183,22 @@ pxl8_mat4 pxl8_mat4_rotate_z(f32 angle) {
pxl8_mat4 mat = pxl8_mat4_identity();
f32 c = cosf(angle);
f32 s = sinf(angle);
mat.m[0] = c;
mat.m[1] = -s;
mat.m[4] = s;
mat.m[5] = c;
return mat;
}
pxl8_mat4 pxl8_mat4_scale(f32 x, f32 y, f32 z) {
pxl8_mat4 mat = pxl8_mat4_identity();
mat.m[0] = x;
mat.m[5] = y;
mat.m[10] = z;
return mat;
}
@ -213,11 +230,11 @@ pxl8_mat4 pxl8_mat4_perspective(f32 fov, f32 aspect, f32 near, f32 far) {
}
pxl8_mat4 pxl8_mat4_lookat(pxl8_vec3 eye, pxl8_vec3 center, pxl8_vec3 up) {
pxl8_mat4 mat = pxl8_mat4_identity();
pxl8_vec3 f = pxl8_vec3_normalize(pxl8_vec3_sub(center, eye));
pxl8_vec3 s = pxl8_vec3_normalize(pxl8_vec3_cross(f, up));
pxl8_vec3 u = pxl8_vec3_cross(s, f);
pxl8_mat4 mat = pxl8_mat4_identity();
mat.m[0] = s.x;
mat.m[1] = s.y;
mat.m[2] = s.z;

View file

@ -56,6 +56,8 @@ static const char* pxl8_ffi_cdefs =
"void pxl8_gfx_fade_palette(pxl8_gfx* ctx, u8 start, u8 count, f32 amount, u32 target_color);\n"
"i32 pxl8_gfx_load_palette(pxl8_gfx* ctx, const char* filepath);\n"
"i32 pxl8_gfx_load_sprite(pxl8_gfx* ctx, const char* filepath, u32* sprite_id);\n"
"i32 pxl8_gfx_create_texture(pxl8_gfx* ctx, const u8* pixels, u32 width, u32 height);\n"
"void pxl8_gfx_upload_atlas(pxl8_gfx* ctx);\n"
"typedef struct pxl8_input_state pxl8_input_state;\n"
"bool pxl8_key_down(const pxl8_input_state* input, i32 key);\n"
"bool pxl8_key_pressed(const pxl8_input_state* input, i32 key);\n"
@ -133,6 +135,8 @@ static const char* pxl8_ffi_cdefs =
"void pxl8_3d_clear_zbuffer(pxl8_gfx* gfx);\n"
"void pxl8_3d_draw_line_3d(pxl8_gfx* gfx, pxl8_vec3 p0, pxl8_vec3 p1, u32 color);\n"
"void pxl8_3d_draw_triangle_raw(pxl8_gfx* gfx, pxl8_vec3 v0, pxl8_vec3 v1, pxl8_vec3 v2, u32 color);\n"
"void pxl8_3d_draw_triangle_textured(pxl8_gfx* gfx, pxl8_vec3 v0, pxl8_vec3 v1, pxl8_vec3 v2, f32 u0, f32 v0, f32 u1, f32 v1, f32 u2, f32 v2, u32 texture_id);\n"
"void pxl8_3d_set_affine_textures(pxl8_gfx* gfx, bool affine);\n"
"void pxl8_3d_set_backface_culling(pxl8_gfx* gfx, bool culling);\n"
"void pxl8_3d_set_model(pxl8_gfx* gfx, pxl8_mat4 mat);\n"
"void pxl8_3d_set_projection(pxl8_gfx* gfx, pxl8_mat4 mat);\n"

View file

@ -28,11 +28,11 @@ struct pxl8_particles {
void* userdata;
};
void pxl8_vfx_plasma(pxl8_gfx* ctx, f32 time, f32 scale1, f32 scale2, u8 palette_offset) {
if (!ctx || !pxl8_gfx_get_framebuffer(ctx)) return;
for (i32 y = 0; y < pxl8_gfx_get_height(ctx); y++) {
for (i32 x = 0; x < pxl8_gfx_get_width(ctx); x++) {
void pxl8_vfx_plasma(pxl8_gfx* gfx, f32 time, f32 scale1, f32 scale2, u8 palette_offset) {
if (!gfx || !pxl8_gfx_get_framebuffer(gfx)) return;
for (i32 y = 0; y < pxl8_gfx_get_height(gfx); y++) {
for (i32 x = 0; x < pxl8_gfx_get_width(gfx); x++) {
f32 v1 = sinf(x * scale1 + time);
f32 v2 = sinf(y * scale1 + time * 0.7f);
f32 v3 = sinf((x + y) * scale2 + time * 1.3f);
@ -44,13 +44,13 @@ void pxl8_vfx_plasma(pxl8_gfx* ctx, f32 time, f32 scale1, f32 scale2, u8 palette
if (normalized > 1.0f) normalized = 1.0f;
u8 color = palette_offset + (u8)(15.0f * normalized);
pxl8_pixel(ctx, x, y, color);
pxl8_pixel(gfx, x, y, color);
}
}
}
void pxl8_vfx_raster_bars(pxl8_gfx* ctx, pxl8_raster_bar* bars, u32 bar_count, f32 time) {
if (!ctx || !bars) return;
void pxl8_vfx_raster_bars(pxl8_gfx* gfx, pxl8_raster_bar* bars, u32 bar_count, f32 time) {
if (!gfx || !bars) return;
for (u32 i = 0; i < bar_count; i++) {
pxl8_raster_bar* bar = &bars[i];
@ -72,24 +72,24 @@ void pxl8_vfx_raster_bars(pxl8_gfx* ctx, pxl8_raster_bar* bars, u32 bar_count, f
color_idx = bar->color - 1;
}
pxl8_rect_fill(ctx, 0, y_int + dy, pxl8_gfx_get_width(ctx), 1, color_idx);
pxl8_rect_fill(gfx, 0, y_int + dy, pxl8_gfx_get_width(gfx), 1, color_idx);
}
}
}
void pxl8_vfx_rotozoom(pxl8_gfx* ctx, f32 angle, f32 zoom, i32 cx, i32 cy) {
if (!ctx || !pxl8_gfx_get_framebuffer(ctx)) return;
void pxl8_vfx_rotozoom(pxl8_gfx* gfx, f32 angle, f32 zoom, i32 cx, i32 cy) {
if (!gfx || !pxl8_gfx_get_framebuffer(gfx)) return;
f32 cos_a = cosf(angle);
f32 sin_a = sinf(angle);
u8* temp_buffer = (u8*)SDL_malloc(pxl8_gfx_get_width(ctx) * pxl8_gfx_get_height(ctx));
u8* temp_buffer = (u8*)SDL_malloc(pxl8_gfx_get_width(gfx) * pxl8_gfx_get_height(gfx));
if (!temp_buffer) return;
SDL_memcpy(temp_buffer, pxl8_gfx_get_framebuffer(ctx), pxl8_gfx_get_width(ctx) * pxl8_gfx_get_height(ctx));
SDL_memcpy(temp_buffer, pxl8_gfx_get_framebuffer(gfx), pxl8_gfx_get_width(gfx) * pxl8_gfx_get_height(gfx));
for (i32 y = 0; y < pxl8_gfx_get_height(ctx); y++) {
for (i32 x = 0; x < pxl8_gfx_get_width(ctx); x++) {
for (i32 y = 0; y < pxl8_gfx_get_height(gfx); y++) {
for (i32 x = 0; x < pxl8_gfx_get_width(gfx); x++) {
f32 dx = x - cx;
f32 dy = y - cy;
@ -99,8 +99,8 @@ void pxl8_vfx_rotozoom(pxl8_gfx* ctx, f32 angle, f32 zoom, i32 cx, i32 cy) {
i32 sx = (i32)src_x;
i32 sy = (i32)src_y;
if (sx >= 0 && sx < pxl8_gfx_get_width(ctx) && sy >= 0 && sy < pxl8_gfx_get_height(ctx)) {
pxl8_gfx_get_framebuffer(ctx)[y * pxl8_gfx_get_width(ctx) + x] = temp_buffer[sy * pxl8_gfx_get_width(ctx) + sx];
if (sx >= 0 && sx < pxl8_gfx_get_width(gfx) && sy >= 0 && sy < pxl8_gfx_get_height(gfx)) {
pxl8_gfx_get_framebuffer(gfx)[y * pxl8_gfx_get_width(gfx) + x] = temp_buffer[sy * pxl8_gfx_get_width(gfx) + sx];
}
}
}
@ -108,38 +108,41 @@ void pxl8_vfx_rotozoom(pxl8_gfx* ctx, f32 angle, f32 zoom, i32 cx, i32 cy) {
SDL_free(temp_buffer);
}
void pxl8_vfx_tunnel(pxl8_gfx* ctx, f32 time, f32 speed, f32 twist) {
if (!ctx || !pxl8_gfx_get_framebuffer(ctx)) return;
f32 cx = pxl8_gfx_get_width(ctx) / 2.0f;
f32 cy = pxl8_gfx_get_height(ctx) / 2.0f;
for (i32 y = 0; y < pxl8_gfx_get_height(ctx); y++) {
for (i32 x = 0; x < pxl8_gfx_get_width(ctx); x++) {
void pxl8_vfx_tunnel(pxl8_gfx* gfx, f32 time, f32 speed, f32 twist) {
if (!gfx || !pxl8_gfx_get_framebuffer(gfx)) return;
f32 cx = pxl8_gfx_get_width(gfx) / 2.0f;
f32 cy = pxl8_gfx_get_height(gfx) / 2.0f;
u32 palette_size = pxl8_gfx_get_palette_size(gfx);
if (palette_size == 0) palette_size = 256;
for (i32 y = 0; y < pxl8_gfx_get_height(gfx); y++) {
for (i32 x = 0; x < pxl8_gfx_get_width(gfx); x++) {
f32 dx = x - cx;
f32 dy = y - cy;
f32 dist = sqrtf(dx * dx + dy * dy);
if (dist > 1.0f) {
f32 angle = atan2f(dy, dx);
f32 u = angle * 0.159f + twist * sinf(time * 0.5f);
f32 v = 256.0f / dist + time * speed;
u8 tx = (u8)((i32)(u * 256.0f) & 0xFF);
u8 ty = (u8)((i32)(v * 256.0f) & 0xFF);
u8 color = tx ^ ty;
pxl8_pixel(ctx, x, y, color);
u8 pattern = tx ^ ty;
u8 color = (pattern / 8) % palette_size;
pxl8_pixel(gfx, x, y, color);
}
}
}
}
void pxl8_vfx_water_ripple(pxl8_gfx* ctx, f32* height_map, i32 drop_x, i32 drop_y, f32 damping) {
if (!ctx || !height_map) return;
void pxl8_vfx_water_ripple(pxl8_gfx* gfx, f32* height_map, i32 drop_x, i32 drop_y, f32 damping) {
if (!gfx || !height_map) return;
i32 w = pxl8_gfx_get_width(ctx);
i32 h = pxl8_gfx_get_height(ctx);
i32 w = pxl8_gfx_get_width(gfx);
i32 h = pxl8_gfx_get_height(gfx);
static f32* prev_height = NULL;
if (!prev_height) {

View file

@ -46,8 +46,8 @@ void pxl8_vfx_snow(pxl8_particles* particles, i32 width, f32 wind);
void pxl8_vfx_sparks(pxl8_particles* particles, i32 x, i32 y, u32 color);
void pxl8_vfx_starfield(pxl8_particles* particles, f32 speed, f32 spread);
void pxl8_vfx_plasma(pxl8_gfx* ctx, f32 time, f32 scale1, f32 scale2, u8 palette_offset);
void pxl8_vfx_raster_bars(pxl8_gfx* ctx, pxl8_raster_bar* bars, u32 bar_count, f32 time);
void pxl8_vfx_rotozoom(pxl8_gfx* ctx, f32 angle, f32 zoom, i32 cx, i32 cy);
void pxl8_vfx_tunnel(pxl8_gfx* ctx, f32 time, f32 speed, f32 twist);
void pxl8_vfx_water_ripple(pxl8_gfx* ctx, f32* height_map, i32 drop_x, i32 drop_y, f32 damping);
void pxl8_vfx_plasma(pxl8_gfx* gfx, f32 time, f32 scale1, f32 scale2, u8 palette_offset);
void pxl8_vfx_raster_bars(pxl8_gfx* gfx, pxl8_raster_bar* bars, u32 bar_count, f32 time);
void pxl8_vfx_rotozoom(pxl8_gfx* gfx, f32 angle, f32 zoom, i32 cx, i32 cy);
void pxl8_vfx_tunnel(pxl8_gfx* gfx, f32 time, f32 speed, f32 twist);
void pxl8_vfx_water_ripple(pxl8_gfx* gfx, f32* height_map, i32 drop_x, i32 drop_y, f32 damping);