mirror of
https://github.com/Noratrieb/colouncher.git
synced 2026-03-14 21:26:10 +01:00
start voronoi
This commit is contained in:
parent
c883f37739
commit
6ff558826a
4 changed files with 254 additions and 90 deletions
|
|
@ -17,16 +17,17 @@ impl DesktopEntries {
|
||||||
pub fn count(&self) -> usize {
|
pub fn count(&self) -> usize {
|
||||||
self.entries.len()
|
self.entries.len()
|
||||||
}
|
}
|
||||||
|
pub fn colors(&self) -> impl Iterator<Item = Oklab> + ExactSizeIterator {
|
||||||
|
self.entries.iter().map(|entry| entry.avg_icon_color)
|
||||||
|
}
|
||||||
pub fn find_entry(&self, color: Oklab) -> Option<&DesktopEntry> {
|
pub fn find_entry(&self, color: Oklab) -> Option<&DesktopEntry> {
|
||||||
self.entries.iter().min_by(|x, y| {
|
self.entries
|
||||||
f32::total_cmp(
|
.iter()
|
||||||
&diff_color(x.avg_icon_color, color),
|
.min_by_key(|x| OrdFloat(diff_color(x.avg_icon_color, color)))
|
||||||
&diff_color(y.avg_icon_color, color),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// keep it in sync with the gpu implementation
|
||||||
fn diff_color(icon: Oklab, color: Oklab) -> f32 {
|
fn diff_color(icon: Oklab, color: Oklab) -> f32 {
|
||||||
icon.distance_squared(color)
|
icon.distance_squared(color)
|
||||||
}
|
}
|
||||||
|
|
@ -98,9 +99,14 @@ pub(crate) fn find_desktop_files() -> Result<DesktopEntries> {
|
||||||
.wrap_err_with(|| format!("{}", base.display()))?;
|
.wrap_err_with(|| format!("{}", base.display()))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(DesktopEntries {
|
let mut entries = results.into_values().collect::<Vec<_>>();
|
||||||
entries: results.into_values().collect(),
|
|
||||||
})
|
entries.sort_by_key(|entry| {
|
||||||
|
let (l, a, b) = entry.avg_icon_color.into_components();
|
||||||
|
(OrdFloat(a), OrdFloat(b), OrdFloat(l))
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(DesktopEntries { entries })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn average_color(image: &image::DynamicImage) -> palette::Oklab {
|
fn average_color(image: &image::DynamicImage) -> palette::Oklab {
|
||||||
|
|
@ -131,3 +137,22 @@ fn average_color(image: &image::DynamicImage) -> palette::Oklab {
|
||||||
b: total_b / count,
|
b: total_b / count,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct OrdFloat(f32);
|
||||||
|
|
||||||
|
impl PartialEq for OrdFloat {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.cmp(other).is_eq()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Eq for OrdFloat {}
|
||||||
|
impl PartialOrd for OrdFloat {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
Some(self.cmp(&other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Ord for OrdFloat {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
self.0.total_cmp(&other.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
143
src/gpu.rs
143
src/gpu.rs
|
|
@ -1,6 +1,7 @@
|
||||||
use std::ptr::NonNull;
|
use std::{mem::offset_of, ptr::NonNull};
|
||||||
|
|
||||||
use eyre::{Context, Result};
|
use eyre::{Context, Result};
|
||||||
|
use palette::Oklab;
|
||||||
use raw_window_handle::{
|
use raw_window_handle::{
|
||||||
RawDisplayHandle, RawWindowHandle, WaylandDisplayHandle, WaylandWindowHandle,
|
RawDisplayHandle, RawWindowHandle, WaylandDisplayHandle, WaylandWindowHandle,
|
||||||
};
|
};
|
||||||
|
|
@ -9,27 +10,42 @@ use wgpu::util::DeviceExt;
|
||||||
|
|
||||||
pub struct AppGpuState {
|
pub struct AppGpuState {
|
||||||
instance: wgpu::Instance,
|
instance: wgpu::Instance,
|
||||||
adapter: wgpu::Adapter,
|
|
||||||
device: wgpu::Device,
|
device: wgpu::Device,
|
||||||
queue: wgpu::Queue,
|
queue: wgpu::Queue,
|
||||||
render_pipeline: wgpu::RenderPipeline,
|
render_pipeline: wgpu::RenderPipeline,
|
||||||
screen_size_bind_group_layout: wgpu::BindGroupLayout,
|
screen_size_bind_group_layout: wgpu::BindGroupLayout,
|
||||||
|
desktop_colors_bind_group: wgpu::BindGroup,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SurfaceGpuState {
|
pub struct SurfaceGpuState {
|
||||||
surface: wgpu::Surface<'static>,
|
surface: wgpu::Surface<'static>,
|
||||||
screen_size_buffer: wgpu::Buffer,
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
input_buffer: wgpu::Buffer,
|
||||||
screen_size_bind_group: wgpu::BindGroup,
|
screen_size_bind_group: wgpu::BindGroup,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
struct ScreenSizeUniform {
|
struct InputUniform {
|
||||||
size: [f32; 2], // width, height
|
size: [f32; 2], // width, height
|
||||||
|
voronoi_progress: f32,
|
||||||
|
_pad: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
|
struct DesktopColorsStorage {
|
||||||
|
l: f32,
|
||||||
|
a: f32,
|
||||||
|
b: f32,
|
||||||
|
_pad: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppGpuState {
|
impl AppGpuState {
|
||||||
pub fn new() -> Result<Self> {
|
pub fn new(
|
||||||
|
desktop_colors: impl IntoIterator<Item = Oklab> + ExactSizeIterator,
|
||||||
|
) -> Result<Self> {
|
||||||
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::default());
|
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::default());
|
||||||
|
|
||||||
let adapter =
|
let adapter =
|
||||||
|
|
@ -54,10 +70,28 @@ impl AppGpuState {
|
||||||
count: None,
|
count: None,
|
||||||
}],
|
}],
|
||||||
});
|
});
|
||||||
|
let desktop_colors_bind_group_layout =
|
||||||
|
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
|
label: Some("desktop_colors_bind_group_layout"),
|
||||||
|
entries: &[wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 0,
|
||||||
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Buffer {
|
||||||
|
ty: wgpu::BufferBindingType::Storage { read_only: true },
|
||||||
|
has_dynamic_offset: false,
|
||||||
|
min_binding_size: None,
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
|
||||||
let render_pipeline_layout =
|
let render_pipeline_layout =
|
||||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
label: Some("Render Pipeline Layout"),
|
label: Some("Render Pipeline Layout"),
|
||||||
bind_group_layouts: &[&screen_size_bind_group_layout],
|
bind_group_layouts: &[
|
||||||
|
&screen_size_bind_group_layout,
|
||||||
|
&desktop_colors_bind_group_layout,
|
||||||
|
],
|
||||||
immediate_size: 0,
|
immediate_size: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -73,11 +107,7 @@ impl AppGpuState {
|
||||||
fragment: Some(wgpu::FragmentState {
|
fragment: Some(wgpu::FragmentState {
|
||||||
module: &shader,
|
module: &shader,
|
||||||
entry_point: Some("fs_main"),
|
entry_point: Some("fs_main"),
|
||||||
targets: &[Some(wgpu::ColorTargetState {
|
targets: &[Some(wgpu::TextureFormat::Bgra8UnormSrgb.into())],
|
||||||
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
|
||||||
blend: Some(wgpu::BlendState::REPLACE),
|
|
||||||
write_mask: wgpu::ColorWrites::ALL,
|
|
||||||
})],
|
|
||||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||||
}),
|
}),
|
||||||
primitive: wgpu::PrimitiveState {
|
primitive: wgpu::PrimitiveState {
|
||||||
|
|
@ -99,13 +129,42 @@ impl AppGpuState {
|
||||||
cache: None,
|
cache: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let desktop_colors = desktop_colors
|
||||||
|
.into_iter()
|
||||||
|
.map(|color| DesktopColorsStorage {
|
||||||
|
l: color.l,
|
||||||
|
a: color.a,
|
||||||
|
b: color.b,
|
||||||
|
_pad: 0.0,
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let desktop_colors_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: Some("desktop_colors_buffer"),
|
||||||
|
contents: bytemuck::cast_slice::<DesktopColorsStorage, u8>(&desktop_colors),
|
||||||
|
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
|
||||||
|
});
|
||||||
|
|
||||||
|
let desktop_colors_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
layout: &desktop_colors_bind_group_layout,
|
||||||
|
entries: &[wgpu::BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
|
||||||
|
buffer: &desktop_colors_buffer,
|
||||||
|
offset: 0,
|
||||||
|
size: None,
|
||||||
|
}),
|
||||||
|
}],
|
||||||
|
label: Some("desktop_colors_bind_group"),
|
||||||
|
});
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
instance,
|
instance,
|
||||||
adapter,
|
|
||||||
device,
|
device,
|
||||||
queue,
|
queue,
|
||||||
render_pipeline,
|
render_pipeline,
|
||||||
screen_size_bind_group_layout,
|
screen_size_bind_group_layout,
|
||||||
|
desktop_colors_bind_group,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -135,7 +194,11 @@ impl SurfaceGpuState {
|
||||||
.device
|
.device
|
||||||
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
label: Some("Screen Size Uniform Buffer"),
|
label: Some("Screen Size Uniform Buffer"),
|
||||||
contents: bytemuck::bytes_of(&ScreenSizeUniform { size: [0.0, 0.0] }),
|
contents: bytemuck::bytes_of(&InputUniform {
|
||||||
|
size: [0.0, 0.0],
|
||||||
|
voronoi_progress: 0.0,
|
||||||
|
_pad: 0.0,
|
||||||
|
}),
|
||||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -157,38 +220,63 @@ impl SurfaceGpuState {
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
surface,
|
surface,
|
||||||
screen_size_buffer,
|
input_buffer: screen_size_buffer,
|
||||||
screen_size_bind_group,
|
screen_size_bind_group,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resize(&self, gpu_state: &AppGpuState, width: u32, height: u32) {
|
pub fn resize(&mut self, gpu_state: &AppGpuState, width: u32, height: u32) {
|
||||||
|
self.width = width;
|
||||||
|
self.height = height;
|
||||||
|
|
||||||
gpu_state.queue.write_buffer(
|
gpu_state.queue.write_buffer(
|
||||||
&self.screen_size_buffer,
|
&self.input_buffer,
|
||||||
0,
|
0,
|
||||||
bytemuck::bytes_of(&ScreenSizeUniform {
|
bytemuck::bytes_of(&InputUniform {
|
||||||
size: [width as f32, height as f32],
|
size: [width as f32, height as f32],
|
||||||
|
voronoi_progress: 0.0,
|
||||||
|
_pad: 0.0,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
let cap = self.surface.get_capabilities(&gpu_state.adapter);
|
self.configure(gpu_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn configure(&self, gpu_state: &AppGpuState) {
|
||||||
let surface_config = wgpu::SurfaceConfiguration {
|
let surface_config = wgpu::SurfaceConfiguration {
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
format: cap.formats[0],
|
format: wgpu::TextureFormat::Bgra8UnormSrgb,
|
||||||
view_formats: vec![cap.formats[0]],
|
view_formats: vec![wgpu::TextureFormat::Bgra8UnormSrgb],
|
||||||
alpha_mode: wgpu::CompositeAlphaMode::Auto,
|
alpha_mode: wgpu::CompositeAlphaMode::Auto,
|
||||||
width,
|
width: self.width,
|
||||||
height,
|
height: self.height,
|
||||||
desired_maximum_frame_latency: 2,
|
desired_maximum_frame_latency: 2,
|
||||||
// Wayland is inherently a mailbox system.
|
// Wayland is inherently a mailbox system.
|
||||||
present_mode: wgpu::PresentMode::Mailbox,
|
present_mode: wgpu::PresentMode::Mailbox,
|
||||||
};
|
};
|
||||||
self.surface.configure(&gpu_state.device, &surface_config);
|
self.surface.configure(&gpu_state.device, &surface_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_voronoi_progress(&self, gpu_state: &AppGpuState, voronoi_progress: f32) {
|
||||||
|
gpu_state.queue.write_buffer(
|
||||||
|
&self.input_buffer,
|
||||||
|
offset_of!(InputUniform, voronoi_progress) as u64,
|
||||||
|
bytemuck::bytes_of(&voronoi_progress),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(&self, gpu_state: &AppGpuState) {
|
||||||
|
let surface_texture = match self.surface.get_current_texture() {
|
||||||
|
Ok(texture) => texture,
|
||||||
|
Err(wgpu::SurfaceError::Outdated | wgpu::SurfaceError::Lost) => {
|
||||||
|
self.configure(gpu_state);
|
||||||
|
self.surface.get_current_texture().unwrap()
|
||||||
|
}
|
||||||
|
Err(e) => panic!("failed to acquire next swapchain texture: {e}"),
|
||||||
|
};
|
||||||
|
|
||||||
let surface_texture = self
|
|
||||||
.surface
|
|
||||||
.get_current_texture()
|
|
||||||
.expect("failed to acquire next swapchain texture");
|
|
||||||
let texture_view: wgpu::TextureView = surface_texture
|
let texture_view: wgpu::TextureView = surface_texture
|
||||||
.texture
|
.texture
|
||||||
.create_view(&wgpu::TextureViewDescriptor::default());
|
.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
|
@ -219,7 +307,8 @@ impl SurfaceGpuState {
|
||||||
});
|
});
|
||||||
|
|
||||||
render_pass.set_pipeline(&gpu_state.render_pipeline);
|
render_pass.set_pipeline(&gpu_state.render_pipeline);
|
||||||
render_pass.set_bind_group(0, Some(&self.screen_size_bind_group), &[]);
|
render_pass.set_bind_group(0, &self.screen_size_bind_group, &[]);
|
||||||
|
render_pass.set_bind_group(1, &gpu_state.desktop_colors_bind_group, &[]);
|
||||||
render_pass.draw(0..6, 0..1);
|
render_pass.draw(0..6, 0..1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
56
src/main.rs
56
src/main.rs
|
|
@ -9,7 +9,7 @@ use std::{
|
||||||
use eyre::{Context, Result, bail, eyre};
|
use eyre::{Context, Result, bail, eyre};
|
||||||
use freedesktop_file_parser::EntryType;
|
use freedesktop_file_parser::EntryType;
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use palette::{FromColor, IntoColor, Oklab};
|
use palette::Oklab;
|
||||||
use smithay_client_toolkit::{
|
use smithay_client_toolkit::{
|
||||||
compositor::{CompositorHandler, CompositorState},
|
compositor::{CompositorHandler, CompositorState},
|
||||||
output::{OutputHandler, OutputState},
|
output::{OutputHandler, OutputState},
|
||||||
|
|
@ -18,7 +18,7 @@ use smithay_client_toolkit::{
|
||||||
registry_handlers,
|
registry_handlers,
|
||||||
seat::{
|
seat::{
|
||||||
SeatHandler, SeatState,
|
SeatHandler, SeatState,
|
||||||
pointer::{BTN_LEFT, PointerEventKind, PointerHandler},
|
pointer::{BTN_LEFT, BTN_RIGHT, PointerEventKind, PointerHandler},
|
||||||
},
|
},
|
||||||
shell::{
|
shell::{
|
||||||
WaylandSurface,
|
WaylandSurface,
|
||||||
|
|
@ -70,7 +70,7 @@ fn main() -> Result<()> {
|
||||||
shm: Shm::bind(&globals, qh).wrap_err("failed to bind shm")?,
|
shm: Shm::bind(&globals, qh).wrap_err("failed to bind shm")?,
|
||||||
seat_state: SeatState::new(&globals, qh),
|
seat_state: SeatState::new(&globals, qh),
|
||||||
|
|
||||||
gpu: AppGpuState::new()?,
|
gpu: AppGpuState::new(desktop_files.colors())?,
|
||||||
|
|
||||||
desktop_files,
|
desktop_files,
|
||||||
pointers: HashMap::new(),
|
pointers: HashMap::new(),
|
||||||
|
|
@ -114,6 +114,7 @@ struct OutputSurface {
|
||||||
layer_surface: LayerSurface,
|
layer_surface: LayerSurface,
|
||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
|
voronoi_progress: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProvidesRegistryState for App {
|
impl ProvidesRegistryState for App {
|
||||||
|
|
@ -165,6 +166,7 @@ impl OutputHandler for App {
|
||||||
layer_surface,
|
layer_surface,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
|
voronoi_progress: 0.0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Err(err) => error!(
|
Err(err) => error!(
|
||||||
|
|
@ -233,6 +235,7 @@ impl CompositorHandler for App {
|
||||||
_surface: &wayland_client::protocol::wl_surface::WlSurface,
|
_surface: &wayland_client::protocol::wl_surface::WlSurface,
|
||||||
_time: u32,
|
_time: u32,
|
||||||
) {
|
) {
|
||||||
|
dbg!("yeet");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn surface_enter(
|
fn surface_enter(
|
||||||
|
|
@ -293,20 +296,20 @@ impl LayerShellHandler for App {
|
||||||
surface.height = height;
|
surface.height = height;
|
||||||
|
|
||||||
surface.gpu.resize(&self.gpu, width, height);
|
surface.gpu.resize(&self.gpu, width, height);
|
||||||
|
surface.gpu.draw(&self.gpu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// keep it in sync with the gpu implementation
|
// keep it in sync with the gpu implementation
|
||||||
fn color_for_pixel(x: u32, y: u32, width: u32, height: u32) -> palette::Srgb<u8> {
|
fn color_for_pixel(x: u32, y: u32, width: u32, height: u32) -> Oklab {
|
||||||
let xf = x as f32 / width as f32;
|
let xf = x as f32 / width as f32;
|
||||||
let yf = y as f32 / height as f32;
|
let yf = y as f32 / height as f32;
|
||||||
|
|
||||||
palette::Srgb::from_color(palette::Oklab {
|
palette::Oklab {
|
||||||
l: 0.7,
|
l: 0.7,
|
||||||
a: xf * 0.8 - 0.4,
|
a: xf * 0.8 - 0.4,
|
||||||
b: yf * 0.8 - 0.4,
|
b: yf * 0.7 - 0.4,
|
||||||
})
|
}
|
||||||
.into_format::<u8>()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShmHandler for App {
|
impl ShmHandler for App {
|
||||||
|
|
@ -373,27 +376,25 @@ impl PointerHandler for App {
|
||||||
events: &[smithay_client_toolkit::seat::pointer::PointerEvent],
|
events: &[smithay_client_toolkit::seat::pointer::PointerEvent],
|
||||||
) {
|
) {
|
||||||
for event in events {
|
for event in events {
|
||||||
if let PointerEventKind::Release {
|
|
||||||
button: BTN_LEFT, ..
|
|
||||||
} = event.kind
|
|
||||||
{
|
|
||||||
let Some(surface) = self
|
let Some(surface) = self
|
||||||
.layer_surfaces
|
.layer_surfaces
|
||||||
.iter()
|
.iter_mut()
|
||||||
.find(|surface| *surface.layer_surface.wl_surface() == event.surface)
|
.find(|surface| *surface.layer_surface.wl_surface() == event.surface)
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let srgb = color_for_pixel(
|
match event.kind {
|
||||||
|
PointerEventKind::Release {
|
||||||
|
button: BTN_LEFT, ..
|
||||||
|
} => {
|
||||||
|
let oklab = color_for_pixel(
|
||||||
event.position.0 as u32,
|
event.position.0 as u32,
|
||||||
event.position.1 as u32,
|
event.position.1 as u32,
|
||||||
surface.width,
|
surface.width,
|
||||||
surface.height,
|
surface.height,
|
||||||
);
|
);
|
||||||
|
|
||||||
let oklab: Oklab = srgb.into_format::<f32>().into_color();
|
|
||||||
|
|
||||||
let best_match = self.desktop_files.find_entry(oklab);
|
let best_match = self.desktop_files.find_entry(oklab);
|
||||||
|
|
||||||
if let Some(best_match) = best_match
|
if let Some(best_match) = best_match
|
||||||
|
|
@ -415,6 +416,29 @@ impl PointerHandler for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PointerEventKind::Press {
|
||||||
|
button: BTN_RIGHT, ..
|
||||||
|
} => {
|
||||||
|
surface.voronoi_progress = 1.0;
|
||||||
|
|
||||||
|
surface
|
||||||
|
.gpu
|
||||||
|
.set_voronoi_progress(&self.gpu, surface.voronoi_progress);
|
||||||
|
surface.gpu.draw(&self.gpu);
|
||||||
|
}
|
||||||
|
PointerEventKind::Release {
|
||||||
|
button: BTN_RIGHT, ..
|
||||||
|
}
|
||||||
|
| PointerEventKind::Leave { .. } => {
|
||||||
|
surface.voronoi_progress = 0.0;
|
||||||
|
|
||||||
|
surface
|
||||||
|
.gpu
|
||||||
|
.set_voronoi_progress(&self.gpu, surface.voronoi_progress);
|
||||||
|
surface.gpu.draw(&self.gpu);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,19 @@
|
||||||
struct Screen {
|
struct Input {
|
||||||
size: vec2<f32>,
|
size: vec2<f32>,
|
||||||
|
voronoi_progress: f32,
|
||||||
};
|
};
|
||||||
|
|
||||||
@group(0) @binding(0)
|
@group(0) @binding(0)
|
||||||
var<uniform> screen: Screen;
|
var<uniform> input: Input;
|
||||||
|
|
||||||
|
@group(1) @binding(0)
|
||||||
|
var<storage, read> desktop_colors: array<vec4f>;
|
||||||
|
|
||||||
@vertex
|
@vertex
|
||||||
fn vs_main(
|
fn vs_main(
|
||||||
@builtin(vertex_index) in_vertex_index: u32,
|
@builtin(vertex_index) in_vertex_index: u32,
|
||||||
) -> @builtin(position) vec4<f32> {
|
) -> @builtin(position) vec4<f32> {
|
||||||
|
// full-screen quad
|
||||||
var pos = array<vec2f, 6>(
|
var pos = array<vec2f, 6>(
|
||||||
vec2(-1.0, 1.0),
|
vec2(-1.0, 1.0),
|
||||||
vec2(-1.0, -1.0),
|
vec2(-1.0, -1.0),
|
||||||
|
|
@ -23,20 +28,42 @@ fn vs_main(
|
||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
fn fs_main(@builtin(position) pos: vec4<f32>) -> @location(0) vec4<f32> {
|
fn fs_main(@builtin(position) pos: vec4<f32>) -> @location(0) vec4<f32> {
|
||||||
var posf = pos.xy / screen.size;
|
var posf = pos.xy / input.size;
|
||||||
|
|
||||||
// keep it in sync with the cpu implementation
|
var color = vec3<f32>(
|
||||||
var color = oklab_to_linear_srgb(vec3<f32>(
|
|
||||||
0.7,
|
0.7,
|
||||||
posf.x * 0.8 - 0.4,
|
posf.x * 0.8 - 0.4,
|
||||||
posf.y * 0.8 - 0.4,
|
posf.y * 0.7 - 0.4,
|
||||||
));
|
);
|
||||||
|
|
||||||
return vec4<f32>(color.x, color.y, color.z, 1.0);
|
var best = vec3f(0.0, 0.0, 0.0);
|
||||||
|
var best_score = 1000000000000.0;
|
||||||
|
for (var i: u32 = 0; i < arrayLength(&desktop_colors); i++) {
|
||||||
|
var elem = desktop_colors[i].xyz;
|
||||||
|
var score = diff_colors(elem, color);
|
||||||
|
if (score < best_score) {
|
||||||
|
best = elem;
|
||||||
|
best_score = score;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var voronoi_color = best;
|
||||||
|
|
||||||
|
color = mix(color, voronoi_color, input.voronoi_progress);
|
||||||
|
|
||||||
|
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// keep it in sync with the cpu implementation
|
||||||
|
fn diff_colors(oklab_a: vec3f, oklab_b: vec3f) -> f32 {
|
||||||
|
var diff = oklab_a - oklab_b;
|
||||||
|
var diff_sq = diff * diff;
|
||||||
|
return diff_sq.x + diff_sq.y + diff_sq.z;
|
||||||
|
}
|
||||||
|
|
||||||
fn oklab_to_linear_srgb(oklab: vec3<f32>) -> vec3<f32> {
|
fn oklab_to_linear_srgb(oklab: vec3f) -> vec3f {
|
||||||
let l_ = 0.2158037573 * oklab.z + (0.3963377774 * oklab.y + oklab.x);
|
let l_ = 0.2158037573 * oklab.z + (0.3963377774 * oklab.y + oklab.x);
|
||||||
let m_ = -0.0638541728 * oklab.z + (-0.1055613458 * oklab.y + oklab.x);
|
let m_ = -0.0638541728 * oklab.z + (-0.1055613458 * oklab.y + oklab.x);
|
||||||
let s_ = -1.2914855480 * oklab.z + (-0.0894841775 * oklab.y + oklab.x);
|
let s_ = -1.2914855480 * oklab.z + (-0.0894841775 * oklab.y + oklab.x);
|
||||||
|
|
@ -49,4 +76,3 @@ fn oklab_to_linear_srgb(oklab: vec3<f32>) -> vec3<f32> {
|
||||||
1.7076147010 * s + (-0.0041960863 * l + -0.7034186147 * m),
|
1.7076147010 * s + (-0.0041960863 * l + -0.7034186147 * m),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue