Skip to content

Commit

Permalink
Add HSV and OKLCH Graphs
Browse files Browse the repository at this point in the history
  • Loading branch information
PixelDoted committed May 31, 2024
1 parent 96d6ead commit f177be9
Show file tree
Hide file tree
Showing 11 changed files with 495 additions and 10 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ edition = "2021"
license = "GPL-3.0"

[dependencies]
bytemuck = { version = "1.16.0", features = ["derive"] }
i18n-embed-fl = "0.8"
log = "0.4.21"
once_cell = "1.19.0"
Expand Down
9 changes: 3 additions & 6 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,14 +222,11 @@ impl Application for ColorPicker {
contents = contents.push(widget::container(
widget::column::with_capacity(2)
.push(sidebar)
.push(
content
.map(move |message| Message::ColorSpace { index, message })
.apply(widget::scrollable),
)
.push(content.map(move |message| Message::ColorSpace { index, message }))
.spacing(10.0)
.padding(10.0)
.width(300.0),
.width(300.0)
.apply(widget::scrollable),
));
}

Expand Down
20 changes: 19 additions & 1 deletion src/colorspace/hsv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ use cosmic::{
widget,
};

use crate::{colorspace::ColorSpaceMessage as Message, fl, widgets::color_slider};
use crate::{
colorspace::ColorSpaceMessage as Message, fl, shaders::hsv as shader, widgets::color_slider,
};

const COLOR_STOPS_HUE: [ColorStop; 7] = [
ColorStop {
Expand Down Expand Up @@ -163,6 +165,21 @@ impl Hsv {
.push(widget::container(red).style(cosmic::style::Container::Card))
.push(widget::container(green).style(cosmic::style::Container::Card))
.push(widget::container(blue).style(cosmic::style::Container::Card))
.push(
widget::container(
widget::container(
cosmic::iced_widget::shader(shader::ColorGraph {
hue: self.values[0],
saturation: self.values[1],
value: self.values[2],
})
.width(100)
.height(100),
)
.padding(10.0),
)
.style(cosmic::style::Container::Card),
)
.spacing(10.0);

content.into()
Expand Down Expand Up @@ -234,6 +251,7 @@ fn rgb_to_hsv(r: f32, g: f32, b: f32) -> [f32; 3] {
[h, s, x_max]
}

// ---- Tests ----
#[cfg(test)]
mod test {
use super::{hsv_to_rgb, rgb_to_hsv};
Expand Down
32 changes: 29 additions & 3 deletions src/colorspace/oklch.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
// SPDX-License-Identifier: GPL-3.0-only

use cosmic::{
iced::{gradient::ColorStop, Alignment, Color},
iced::{gradient::ColorStop, Alignment, Color, Length},
widget,
};

use crate::{colorspace::ColorSpaceMessage as Message, fl, widgets::color_slider};
use crate::{
colorspace::ColorSpaceMessage as Message, fl, shaders::oklch as shader, widgets::color_slider,
};

const COLOR_STOPS_LIGHTNESS: [ColorStop; 2] = [
ColorStop {
Expand Down Expand Up @@ -112,6 +114,14 @@ impl Oklch {
.align_items(Alignment::Center)
.spacing(10.0),
)
.push(
cosmic::iced_widget::shader(shader::ColorGraph::<0> {
lightness: self.values[0],
chroma: self.values[1],
hue: self.values[2],
})
.width(Length::Fill),
)
.push(color_slider(
0f32..=1.0f32,
values[0],
Expand All @@ -131,8 +141,16 @@ impl Oklch {
.align_items(Alignment::Center)
.spacing(10.0),
)
.push(
cosmic::iced_widget::shader(shader::ColorGraph::<1> {
lightness: self.values[0],
chroma: self.values[1],
hue: self.values[2],
})
.width(Length::Fill),
)
.push(color_slider(
0f32..=0.5f32,
0f32..=0.37f32,
values[1],
|value| Message::ChangeValue { index: 1, value },
&COLOR_STOPS_CHROMA,
Expand All @@ -150,6 +168,14 @@ impl Oklch {
.align_items(Alignment::Center)
.spacing(10.0),
)
.push(
cosmic::iced_widget::shader(shader::ColorGraph::<2> {
lightness: self.values[0],
chroma: self.values[1],
hue: self.values[2],
})
.width(Length::Fill),
)
.push(color_slider(
0f32..=360f32,
values[2],
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use app::ColorPicker;
mod app;
mod colorspace;
mod core;
mod shaders;
mod widgets;

fn main() -> cosmic::iced::Result {
Expand Down
86 changes: 86 additions & 0 deletions src/shaders/hsv.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use cosmic::iced_widget::shader::{self};

use crate::shaders::ShaderPipeline;

// ---- Shader ----
pub struct ColorGraph {
pub hue: f32,
pub saturation: f32,
pub value: f32,
}

impl<Message> shader::Program<Message> for ColorGraph {
type State = ();
type Primitive = Primitive;

fn draw(
&self,
state: &Self::State,
cursor: cosmic::iced_core::mouse::Cursor,
bounds: cosmic::iced::Rectangle,
) -> Self::Primitive {
Primitive::new(self.hue, self.saturation, self.value)
}
}

#[derive(Debug)]
pub struct Primitive {
uniforms: Uniforms,
}

impl Primitive {
pub fn new(hue: f32, saturation: f32, value: f32) -> Self {
Self {
uniforms: Uniforms {
hue,
saturation,
value,
},
}
}
}

impl shader::Primitive for Primitive {
fn prepare(
&self,
format: shader::wgpu::TextureFormat,
device: &shader::wgpu::Device,
queue: &shader::wgpu::Queue,
bounds: cosmic::iced::Rectangle,
target_size: cosmic::iced::Size<u32>,
scale_factor: f32,
storage: &mut shader::Storage,
) {
if !storage.has::<ShaderPipeline<Uniforms, 0>>() {
storage.store(ShaderPipeline::<Uniforms, 0>::new(
device,
queue,
format,
include_str!("hsv.wgsl"),
));
}

let pipeline = storage.get_mut::<ShaderPipeline<Uniforms, 0>>().unwrap();
pipeline.write(queue, &self.uniforms);
}

fn render(
&self,
storage: &shader::Storage,
target: &shader::wgpu::TextureView,
target_size: cosmic::iced::Size<u32>,
viewport: cosmic::iced::Rectangle<u32>,
encoder: &mut shader::wgpu::CommandEncoder,
) {
let pipeline = storage.get::<ShaderPipeline<Uniforms, 0>>().unwrap();
pipeline.render(target, encoder, viewport);
}
}

#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
#[repr(C)]
struct Uniforms {
hue: f32,
saturation: f32,
value: f32,
}
48 changes: 48 additions & 0 deletions src/shaders/hsv.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
struct HSV {
hue: f32,
saturation: f32,
value: f32,
}

@group(0) @binding(0) var<uniform> hsv: HSV;

@fragment
fn fs_main(
@builtin(position) _clip_pos: vec4<f32>,
@location(0) uv: vec2<f32>,
) -> @location(0) vec4<f32> {
// uv.x = saturation
// uv.y = value

// HSV to RGB
let c = uv.y * uv.x;
let h_ = hsv.hue / 60.0;
let x = c * (1.0 - abs(h_ % 2.0 - 1.0));

var r1 = 0.0;
var g1 = 0.0;
var b1 = 0.0;
if 0.0 <= h_ && h_ < 1.0 {
r1 = c;
g1 = x;
} else if 1.0 <= h_ && h_ < 2.0 {
r1 = x;
g1 = c;
} else if 2.0 <= h_ && h_ < 3.0 {
g1 = c;
b1 = x;
} else if 3.0 <= h_ && h_ < 4.0 {
g1 = x;
b1 = c;
} else if 4.0 <= h_ && h_ < 5.0 {
r1 = x;
b1 = c;
} else {
r1 = c;
b1 = x;
}

let m = uv.y - c;
let color = vec4<f32>(r1 + m, g1 + m, b1 + m, 1.0);
return color;
}
Loading

0 comments on commit f177be9

Please sign in to comment.