trying to animate

This commit is contained in:
nora 2026-03-08 18:22:11 +01:00
parent a68d0dff63
commit 9a255f9a7d
3 changed files with 128 additions and 9 deletions

8
TODO.md Normal file
View file

@ -0,0 +1,8 @@
# TODOs
Nicely animate the transition into the voronoi diagram.
Actually making a cool animation with movement likely requires knowing the distance to the voronoi center of any point.
To know this we will likely have to construct the voronoi diagram on the CPU beforehand and having it as geometry.
To do this, we probably need to generate it in 3D (using something like Bowyer-Watson) and then project it into 2D somehow (using magic) and then do things.
Actually use a good gradient that doesn't look kinda bad.

View file

@ -106,6 +106,12 @@ struct App {
pointers: HashMap<WlSeat, WlPointer>,
layer_surfaces: Vec<OutputSurface>,
}
#[derive(Debug, PartialEq)]
enum AnimationState {
Descending { last_time: Option<u32> },
Paused,
Ascending { last_time: Option<u32> },
}
struct OutputSurface {
// must be first to be dropped before the Wayland surface
@ -115,6 +121,71 @@ struct OutputSurface {
width: u32,
height: u32,
voronoi_progress: f32,
animation_running: AnimationState,
}
const VORONOI_SPEED: f32 = 1000.;
impl OutputSurface {
fn request_frame_if_necessary(&self, qh: &QueueHandle<App>) {
if self.animation_running != AnimationState::Paused {
self.layer_surface
.wl_surface()
.frame(qh, self.layer_surface.wl_surface().clone());
}
}
fn tick_animation(&mut self, new_time: u32) {
match self.animation_running {
AnimationState::Paused => {}
AnimationState::Descending { last_time: None } => {
self.animation_running = AnimationState::Descending {
last_time: Some(new_time),
}
}
AnimationState::Ascending { last_time: None } => {
self.animation_running = AnimationState::Ascending {
last_time: Some(new_time),
}
}
AnimationState::Ascending {
last_time: Some(last_time),
} => {
let delta_time = new_time - last_time;
self.voronoi_progress = f32::min(
self.voronoi_progress + delta_time as f32 / VORONOI_SPEED,
1.0,
);
if self.voronoi_progress >= 1.0 {
self.animation_running = AnimationState::Paused;
} else {
self.animation_running = AnimationState::Ascending {
last_time: Some(new_time),
};
}
}
AnimationState::Descending {
last_time: Some(last_time),
} => {
let delta_time = new_time - last_time;
self.voronoi_progress = f32::max(
self.voronoi_progress - delta_time as f32 / VORONOI_SPEED,
0.0,
);
if self.voronoi_progress <= 0.0 {
self.animation_running = AnimationState::Paused;
} else {
self.animation_running = AnimationState::Descending {
last_time: Some(new_time),
};
}
}
}
}
}
impl ProvidesRegistryState for App {
@ -167,6 +238,7 @@ impl OutputHandler for App {
width: 0,
height: 0,
voronoi_progress: 0.0,
animation_running: AnimationState::Paused,
});
}
Err(err) => error!(
@ -231,11 +303,26 @@ impl CompositorHandler for App {
fn frame(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_surface: &wayland_client::protocol::wl_surface::WlSurface,
_time: u32,
qh: &QueueHandle<Self>,
wl_surface: &wayland_client::protocol::wl_surface::WlSurface,
time: u32,
) {
dbg!("yeet");
let Some(surface) = self
.layer_surfaces
.iter_mut()
.find(|surface| surface.layer_surface.wl_surface() == wl_surface)
else {
return;
};
surface.tick_animation(time);
surface
.gpu
.set_voronoi_progress(&self.gpu, surface.voronoi_progress);
surface.request_frame_if_necessary(qh);
surface.gpu.draw(&self.gpu);
dbg!((&surface.animation_running, surface.voronoi_progress));
}
fn surface_enter(
@ -371,7 +458,7 @@ impl PointerHandler for App {
fn pointer_frame(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
qh: &QueueHandle<Self>,
_pointer: &wayland_client::protocol::wl_pointer::WlPointer,
events: &[smithay_client_toolkit::seat::pointer::PointerEvent],
) {
@ -419,22 +506,28 @@ impl PointerHandler for App {
PointerEventKind::Press {
button: BTN_RIGHT, ..
} => {
surface.voronoi_progress = 1.0;
surface.animation_running = AnimationState::Ascending { last_time: None };
surface
.gpu
.set_voronoi_progress(&self.gpu, surface.voronoi_progress);
surface.request_frame_if_necessary(qh);
surface.gpu.draw(&self.gpu);
}
PointerEventKind::Release {
button: BTN_RIGHT, ..
}
| PointerEventKind::Leave { .. } => {
surface.voronoi_progress = 0.0;
surface.animation_running = AnimationState::Descending { last_time: None };
surface
.gpu
.set_voronoi_progress(&self.gpu, surface.voronoi_progress);
surface.request_frame_if_necessary(qh);
surface.gpu.draw(&self.gpu);
}
_ => (),

View file

@ -47,15 +47,33 @@ fn fs_main(@builtin(position) pos: vec4<f32>) -> @location(0) vec4<f32> {
}
}
var voronoi_color = best;
color = mix(color, voronoi_color, input.voronoi_progress);
var distance_to_center = sqrt(best_score); // a value like 0.1 is pretty good in the grand scheme
var badness = clamp(distance_to_center * 5, 0, 0.5); // 0..1, 1=terrible 0=perfect
// badness determines at which point in the animation progress the animation should start.
// if it's 0.3, we start the animation at 0.3 and end it at 1.0
// so we need to scale and shift input progress (0.3=>0.0, 0.65=>0.5, 1.0=>1.0)
var voronoi_progress_shifted = transform_progress(input.voronoi_progress, badness);
var final_progress = clamp(voronoi_progress_shifted, 0, 1);
// mix with red to see how terrible it looks
color = mix(color, voronoi_color, final_progress);
//color.x = distance_to_center;
// keep it in sync with the cpu implementation
var srgbcolor = oklab_to_linear_srgb(color);
return vec4<f32>(srgbcolor.x, srgbcolor.y, srgbcolor.z, 1.0);
}
fn transform_progress(x: f32, badness: f32) -> f32 {
return ((x) - badness) * (1 / (1 - badness));
}
fn wobble(x: f32) -> f32 {
var wobble_factor = 0.0;
return sin(x * wobble_factor) / 2.0 + 1;
}
// keep it in sync with the cpu implementation
fn diff_colors(oklab_a: vec3f, oklab_b: vec3f) -> f32 {
var diff = oklab_a - oklab_b;