diff --git a/metadata/extra-animations.xml b/metadata/extra-animations.xml index 5f435fd..e27f5c6 100644 --- a/metadata/extra-animations.xml +++ b/metadata/extra-animations.xml @@ -135,7 +135,7 @@ diff --git a/src/extra-animations/carpet.hpp b/src/extra-animations/carpet.hpp index 9f5f790..a90a9f3 100644 --- a/src/extra-animations/carpet.hpp +++ b/src/extra-animations/carpet.hpp @@ -2,6 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2025 Scott Moreau + * Copyright (c) 2025 Andrew Pliatsikas * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -60,7 +61,8 @@ uniform int direction; #define M_PI 3.1415926535897932384626433832795 -void main() +// Original single roll effect +vec4 single_roll(vec2 uvpos_var, float progress, int direction) { vec4 wfrag; vec2 uv; @@ -180,6 +182,154 @@ void main() wfrag = mix(wfrag, pfrag, pfrag.a); } + return wfrag; +} + +// Dual scroll effect (both sides rolling toward/from middle) by Phodius +vec4 dual_scroll(vec2 uvpos_var, float progress, int dir) +{ + vec4 wfrag = vec4(0.0); + vec2 uv; + + float coord; + float other_coord; + + // dir 5 = vertical, dir 4 = horizontal + if (dir == 5) + { + coord = uvpos_var.y; + other_coord = uvpos_var.x; + } + else + { + coord = uvpos_var.x; + other_coord = uvpos_var.y; + } + + // Determine which half we're on + bool second_half = (coord > 0.5); + + // Map to local coordinate: 0 at middle, 1 at edge + float local_coord; + if (second_half) + { + local_coord = (coord - 0.5) * 2.0; + } + else + { + local_coord = (0.5 - coord) * 2.0; + } + + float offset = 0.1; + float p = progress * 1.2 - 0.2; + + // Get pixel from default position if before peel line + if (local_coord < p + offset + 0.05) + { + if (uvpos_var.x >= 0.0 && uvpos_var.x <= 1.0 && + uvpos_var.y >= 0.0 && uvpos_var.y <= 1.0) + { + wfrag = get_pixel(uvpos_var); + } + } + + // Back of roll + if (local_coord > p + offset + 0.05 && local_coord < p + offset + 0.1) + { + float tsin = (local_coord - (p + offset + 0.05)) * 20.0; + float angle = asin(tsin); + + float local_sample = (angle / M_PI) * 0.15 + p + offset + 0.05; + + float global_sample; + if (second_half) + { + global_sample = 0.5 + local_sample * 0.5; + } + else + { + global_sample = 0.5 - local_sample * 0.5; + } + + float perp_sample = (other_coord - 0.5) * pow(cos(angle), 0.02) + 0.5; + + if (dir == 5) + { + uv.y = global_sample; + uv.x = perp_sample; + } + else + { + uv.x = global_sample; + uv.y = perp_sample; + } + + vec4 pfrag = vec4(0.0); + if (uv.x >= 0.0 && uv.x <= 1.0 && uv.y >= 0.0 && uv.y <= 1.0) + { + pfrag = get_pixel(uv); + } + wfrag = mix(pfrag, wfrag, wfrag.a); + } + + // Front of roll + if (local_coord > p + offset && local_coord < p + offset + 0.1) + { + float tsin = (local_coord - (p + offset + 0.1)) * 20.0 + 1.0; + float angle = asin(tsin); + + float local_sample = (angle / (-M_PI)) * 0.1 + p + offset + 0.2; + + float global_sample; + if (second_half) + { + global_sample = 0.5 + local_sample * 0.5; + } + else + { + global_sample = 0.5 - local_sample * 0.5; + } + + float perp_sample = (other_coord - 0.5) * 0.9 * pow(cos(angle), -0.04) + 0.5; + + if (dir == 5) + { + uv.y = global_sample; + uv.x = perp_sample; + } + else + { + uv.x = global_sample; + uv.y = perp_sample; + } + + vec4 pfrag = vec4(0.0); + if (uv.x >= 0.0 && uv.x <= 1.0 && uv.y >= 0.0 && uv.y <= 1.0) + { + pfrag = get_pixel(uv); + } + pfrag = vec4(clamp(pfrag.rgb + (angle / -M_PI), 0.0, 1.0), pfrag.a); + wfrag = mix(wfrag, pfrag, pfrag.a); + } + + return wfrag; +} + +void main() +{ + vec4 wfrag; + + if (direction <= 3) + { + // single roll: left, right, top, bottom + wfrag = single_roll(uvpos_var, progress, direction); + } + else + { + // dual scroll: horizontal or vertical from middle + wfrag = dual_scroll(uvpos_var, progress, direction); + } + gl_FragColor = wfrag; } )";