#include "pxl8_transition.h" #include #include #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; pxl8_pixel_mode mode = pxl8_gfx_get_pixel_mode(gfx); bool has_fb = (mode == PXL8_PIXEL_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); } } }