pxl8/src/pxl8_transition.c

252 lines
8.3 KiB
C
Raw Normal View History

#include "pxl8_transition.h"
#include <stdlib.h>
#include <math.h>
#include "pxl8_macros.h"
#include "pxl8_math.h"
pxl8_transition* pxl8_transition_create(pxl8_transition_type type, f32 duration) {
if (duration <= 0.0f) {
pxl8_error("Invalid transition duration: %f", duration);
return NULL;
}
pxl8_transition* transition = (pxl8_transition*)calloc(1, sizeof(pxl8_transition));
if (!transition) {
pxl8_error("Failed to allocate transition");
return NULL;
}
transition->type = type;
transition->duration = duration;
transition->time = 0.0f;
transition->active = false;
transition->reverse = false;
transition->color = 0xFF000000;
transition->on_complete = NULL;
transition->userdata = NULL;
return transition;
}
void pxl8_transition_destroy(pxl8_transition* transition) {
if (!transition) return;
free(transition);
}
f32 pxl8_transition_get_progress(const pxl8_transition* transition) {
if (!transition) return 0.0f;
f32 t = transition->time / transition->duration;
if (t < 0.0f) t = 0.0f;
if (t > 1.0f) t = 1.0f;
return transition->reverse ? 1.0f - t : t;
}
bool pxl8_transition_is_active(const pxl8_transition* transition) {
return transition && transition->active;
}
bool pxl8_transition_is_complete(const pxl8_transition* transition) {
if (!transition) return true;
return transition->time >= transition->duration;
}
void pxl8_transition_render(const pxl8_transition* transition, pxl8_gfx* gfx) {
if (!transition || !gfx || !transition->active) return;
f32 progress = pxl8_transition_get_progress(transition);
i32 width = pxl8_gfx_get_width(gfx);
i32 height = pxl8_gfx_get_height(gfx);
switch (transition->type) {
case PXL8_TRANSITION_FADE: {
u8 alpha = (u8)(progress * 255.0f);
u32 fade_color = (transition->color & 0x00FFFFFF) | (alpha << 24);
for (i32 y = 0; y < height; y++) {
for (i32 x = 0; x < width; x++) {
u32 bg = pxl8_get_pixel(gfx, x, y);
u32 r_bg = (bg >> 16) & 0xFF;
u32 g_bg = (bg >> 8) & 0xFF;
u32 b_bg = bg & 0xFF;
u32 r_fg = (fade_color >> 16) & 0xFF;
u32 g_fg = (fade_color >> 8) & 0xFF;
u32 b_fg = fade_color & 0xFF;
u32 r = (r_bg * (255 - alpha) + r_fg * alpha) / 255;
u32 g = (g_bg * (255 - alpha) + g_fg * alpha) / 255;
u32 b = (b_bg * (255 - alpha) + b_fg * alpha) / 255;
pxl8_pixel(gfx, x, y, 0xFF000000 | (r << 16) | (g << 8) | b);
}
}
break;
}
case PXL8_TRANSITION_WIPE_LEFT: {
i32 wipe_x = (i32)(width * progress);
pxl8_rect_fill(gfx, 0, 0, wipe_x, height, transition->color);
break;
}
case PXL8_TRANSITION_WIPE_RIGHT: {
i32 wipe_x = (i32)(width * (1.0f - progress));
pxl8_rect_fill(gfx, wipe_x, 0, width - wipe_x, height, transition->color);
break;
}
case PXL8_TRANSITION_WIPE_UP: {
i32 wipe_y = (i32)(height * progress);
pxl8_rect_fill(gfx, 0, 0, width, wipe_y, transition->color);
break;
}
case PXL8_TRANSITION_WIPE_DOWN: {
i32 wipe_y = (i32)(height * (1.0f - progress));
pxl8_rect_fill(gfx, 0, wipe_y, width, height - wipe_y, transition->color);
break;
}
case PXL8_TRANSITION_CIRCLE_CLOSE: {
i32 center_x = width / 2;
i32 center_y = height / 2;
i32 max_radius = (i32)sqrtf((f32)(center_x * center_x + center_y * center_y));
i32 radius = (i32)(max_radius * (1.0f - progress));
for (i32 y = 0; y < height; y++) {
for (i32 x = 0; x < width; x++) {
i32 dx = x - center_x;
i32 dy = y - center_y;
i32 dist = (i32)sqrtf((f32)(dx * dx + dy * dy));
if (dist > radius) {
pxl8_pixel(gfx, x, y, transition->color);
}
}
}
break;
}
case PXL8_TRANSITION_CIRCLE_OPEN: {
i32 center_x = width / 2;
i32 center_y = height / 2;
i32 max_radius = (i32)sqrtf((f32)(center_x * center_x + center_y * center_y));
i32 radius = (i32)(max_radius * progress);
for (i32 y = 0; y < height; y++) {
for (i32 x = 0; x < width; x++) {
i32 dx = x - center_x;
i32 dy = y - center_y;
i32 dist = (i32)sqrtf((f32)(dx * dx + dy * dy));
if (dist < radius) {
pxl8_pixel(gfx, x, y, transition->color);
}
}
}
break;
}
case PXL8_TRANSITION_DISSOLVE: {
u32 seed = 12345;
for (i32 y = 0; y < height; y++) {
for (i32 x = 0; x < width; x++) {
seed = seed * 1103515245 + 12345;
f32 noise = (f32)((seed / 65536) % 1000) / 1000.0f;
if (noise < progress) {
pxl8_pixel(gfx, x, y, transition->color);
}
}
}
break;
}
case PXL8_TRANSITION_PIXELATE: {
i32 max_block_size = 32;
i32 block_size = (i32)(max_block_size * progress);
if (block_size < 1) block_size = 1;
2025-11-28 14:41:35 -06:00
pxl8_color_mode mode = pxl8_gfx_get_color_mode(gfx);
bool has_fb = (mode == PXL8_COLOR_MODE_HICOLOR)
? (pxl8_gfx_get_framebuffer_hicolor(gfx) != NULL)
: (pxl8_gfx_get_framebuffer_indexed(gfx) != NULL);
if (!has_fb) break;
for (i32 y = 0; y < height; y += block_size) {
for (i32 x = 0; x < width; x += block_size) {
u32 color_sum_r = 0, color_sum_g = 0, color_sum_b = 0;
i32 count = 0;
for (i32 by = 0; by < block_size && y + by < height; by++) {
for (i32 bx = 0; bx < block_size && x + bx < width; bx++) {
u32 color = pxl8_get_pixel(gfx, x + bx, y + by);
color_sum_r += (color >> 16) & 0xFF;
color_sum_g += (color >> 8) & 0xFF;
color_sum_b += color & 0xFF;
count++;
}
}
if (count > 0) {
u32 avg_color = 0xFF000000 |
((color_sum_r / count) << 16) |
((color_sum_g / count) << 8) |
(color_sum_b / count);
for (i32 by = 0; by < block_size && y + by < height; by++) {
for (i32 bx = 0; bx < block_size && x + bx < width; bx++) {
pxl8_pixel(gfx, x + bx, y + by, avg_color);
}
}
}
}
}
break;
}
}
}
void pxl8_transition_reset(pxl8_transition* transition) {
if (!transition) return;
transition->time = 0.0f;
transition->active = false;
}
void pxl8_transition_set_color(pxl8_transition* transition, u32 color) {
if (!transition) return;
transition->color = color;
}
void pxl8_transition_set_reverse(pxl8_transition* transition, bool reverse) {
if (!transition) return;
transition->reverse = reverse;
}
void pxl8_transition_start(pxl8_transition* transition) {
if (!transition) return;
transition->active = true;
transition->time = 0.0f;
}
void pxl8_transition_stop(pxl8_transition* transition) {
if (!transition) return;
transition->active = false;
}
void pxl8_transition_update(pxl8_transition* transition, f32 dt) {
if (!transition || !transition->active) return;
transition->time += dt;
if (transition->time >= transition->duration) {
transition->time = transition->duration;
transition->active = false;
if (transition->on_complete) {
transition->on_complete(transition->userdata);
}
}
}