pub use self::color::{Color, Luma, SRGBA8}; use crate::vector::VectorData; use crate::GraphicGroup; use crate::{registry::types::Percentage, transform::Footprint}; use bytemuck::{Pod, Zeroable}; use core::fmt::Debug; use glam::DVec2; #[cfg(target_arch = "spirv")] use spirv_std::num_traits::float::Float; pub mod adjustments; pub mod bbox; #[cfg(not(target_arch = "spirv"))] pub mod brightness_contrast; #[cfg(not(target_arch = "spirv"))] pub mod brush_cache; pub mod color; #[cfg(not(target_arch = "spirv"))] pub mod curve; pub mod discrete_srgb; pub use adjustments::*; pub trait Linear { fn from_f32(x: f32) -> Self; fn to_f32(self) -> f32; fn from_f64(x: f64) -> Self; fn to_f64(self) -> f64; fn lerp(self, other: Self, value: Self) -> Self where Self: Sized + Copy, Self: core::ops::Sub, Self: core::ops::Mul, Self: core::ops::Add, { self + (other - self) * value } } #[rustfmt::skip] impl Linear for f32 { #[inline(always)] fn from_f32(x: f32) -> Self { x } #[inline(always)] fn to_f32(self) -> f32 { self } #[inline(always)] fn from_f64(x: f64) -> Self { x as f32 } #[inline(always)] fn to_f64(self) -> f64 { self as f64 } } #[rustfmt::skip] impl Linear for f64 { #[inline(always)] fn from_f32(x: f32) -> Self { x as f64 } #[inline(always)] fn to_f32(self) -> f32 { self as f32 } #[inline(always)] fn from_f64(x: f64) -> Self { x } #[inline(always)] fn to_f64(self) -> f64 { self } } pub trait Channel: Copy + Debug { fn to_linear(self) -> Out; fn from_linear(linear: In) -> Self; } pub trait LinearChannel: Channel { fn cast_linear_channel(self) -> Out { Out::from_linear(self.to_linear::()) } } impl Channel for T { #[inline(always)] fn to_linear(self) -> Out { Out::from_f64(self.to_f64()) } #[inline(always)] fn from_linear(linear: In) -> Self { Self::from_f64(linear.to_f64()) } } impl LinearChannel for T {} use num_derive::*; #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Num, NumCast, NumOps, One, Zero, ToPrimitive, FromPrimitive)] pub struct SRGBGammaFloat(f32); impl Channel for SRGBGammaFloat { #[inline(always)] fn to_linear(self) -> Out { let x = self.0; Out::from_f32(if x <= 0.04045 { x / 12.92 } else { ((x + 0.055) / 1.055).powf(2.4) }) } #[inline(always)] fn from_linear(linear: In) -> Self { let x = linear.to_f32(); if x <= 0.0031308 { Self(x * 12.92) } else { Self(1.055 * x.powf(1. / 2.4) - 0.055) } } } pub trait RGBPrimaries { const RED: DVec2; const GREEN: DVec2; const BLUE: DVec2; const WHITE: DVec2; } pub trait Rec709Primaries {} impl RGBPrimaries for T { const RED: DVec2 = DVec2::new(0.64, 0.33); const GREEN: DVec2 = DVec2::new(0.3, 0.6); const BLUE: DVec2 = DVec2::new(0.15, 0.06); const WHITE: DVec2 = DVec2::new(0.3127, 0.329); } pub trait SRGB: Rec709Primaries {} #[cfg(feature = "serde")] pub trait Serde: serde::Serialize + for<'a> serde::Deserialize<'a> {} #[cfg(not(feature = "serde"))] pub trait Serde {} #[cfg(feature = "serde")] impl serde::Deserialize<'a>> Serde for T {} #[cfg(not(feature = "serde"))] impl Serde for T {} // TODO: Come up with a better name for this trait pub trait Pixel: Clone + Pod + Zeroable { #[cfg(not(target_arch = "spirv"))] fn to_bytes(&self) -> Vec { bytemuck::bytes_of(self).to_vec() } // TODO: use u8 for Color fn from_bytes(bytes: &[u8]) -> Self { *bytemuck::try_from_bytes(bytes).expect("Failed to convert bytes to pixel") } fn byte_size() -> usize { core::mem::size_of::() } } pub trait RGB: Pixel { type ColorChannel: Channel; fn red(&self) -> Self::ColorChannel; fn r(&self) -> Self::ColorChannel { self.red() } fn green(&self) -> Self::ColorChannel; fn g(&self) -> Self::ColorChannel { self.green() } fn blue(&self) -> Self::ColorChannel; fn b(&self) -> Self::ColorChannel { self.blue() } } pub trait RGBMut: RGB { fn set_red(&mut self, red: Self::ColorChannel); fn set_green(&mut self, green: Self::ColorChannel); fn set_blue(&mut self, blue: Self::ColorChannel); } pub trait AssociatedAlpha: RGB + Alpha { fn to_unassociated(&self) -> Out; } pub trait UnassociatedAlpha: RGB + Alpha { fn to_associated(&self) -> Out; } pub trait Alpha { type AlphaChannel: LinearChannel; const TRANSPARENT: Self; fn alpha(&self) -> Self::AlphaChannel; fn a(&self) -> Self::AlphaChannel { self.alpha() } fn multiplied_alpha(&self, alpha: Self::AlphaChannel) -> Self; } pub trait Depth { type DepthChannel: Channel; fn depth(&self) -> Self::DepthChannel; fn d(&self) -> Self::DepthChannel { self.depth() } } pub trait ExtraChannels { type ChannelType: Channel; fn extra_channels(&self) -> [Self::ChannelType; NUM]; } pub trait Luminance { type LuminanceChannel: LinearChannel; fn luminance(&self) -> Self::LuminanceChannel; fn l(&self) -> Self::LuminanceChannel { self.luminance() } } pub trait LuminanceMut: Luminance { fn set_luminance(&mut self, luminance: Self::LuminanceChannel); } // TODO: We might rename this to Raster at some point pub trait Sample { type Pixel: Pixel; // TODO: Add an area parameter fn sample(&self, pos: DVec2, area: DVec2) -> Option; } impl Sample for &T { type Pixel = T::Pixel; #[inline(always)] fn sample(&self, pos: DVec2, area: DVec2) -> Option { (**self).sample(pos, area) } } pub trait Bitmap { type Pixel: Pixel; fn width(&self) -> u32; fn height(&self) -> u32; fn get_pixel(&self, x: u32, y: u32) -> Option; } impl Bitmap for &T { type Pixel = T::Pixel; fn width(&self) -> u32 { (**self).width() } fn height(&self) -> u32 { (**self).height() } fn get_pixel(&self, x: u32, y: u32) -> Option { (**self).get_pixel(x, y) } } impl Bitmap for &mut T { type Pixel = T::Pixel; fn width(&self) -> u32 { (**self).width() } fn height(&self) -> u32 { (**self).height() } fn get_pixel(&self, x: u32, y: u32) -> Option { (**self).get_pixel(x, y) } } pub trait BitmapMut: Bitmap { fn get_pixel_mut(&mut self, x: u32, y: u32) -> Option<&mut Self::Pixel>; fn set_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) { *self.get_pixel_mut(x, y).unwrap() = pixel; } fn map_pixels Self::Pixel>(&mut self, map_fn: F) { for y in 0..self.height() { for x in 0..self.width() { let pixel = self.get_pixel(x, y).unwrap(); self.set_pixel(x, y, map_fn(pixel)); } } } } impl BitmapMut for &mut T { fn get_pixel_mut(&mut self, x: u32, y: u32) -> Option<&mut Self::Pixel> { (*self).get_pixel_mut(x, y) } } #[cfg(feature = "alloc")] pub use self::image::{Image, ImageFrame}; #[cfg(feature = "alloc")] pub(crate) mod image; trait SetBlendMode { fn set_blend_mode(&mut self, blend_mode: BlendMode); } impl SetBlendMode for VectorData { fn set_blend_mode(&mut self, blend_mode: BlendMode) { self.alpha_blending.blend_mode = blend_mode; } } impl SetBlendMode for GraphicGroup { fn set_blend_mode(&mut self, blend_mode: BlendMode) { self.alpha_blending.blend_mode = blend_mode; } } impl SetBlendMode for ImageFrame { fn set_blend_mode(&mut self, blend_mode: BlendMode) { self.alpha_blending.blend_mode = blend_mode; } } #[node_macro::node(category("Style"))] async fn blend_mode( #[implementations( (), (), (), Footprint, )] footprint: F, #[implementations( () -> GraphicGroup, () -> VectorData, () -> ImageFrame, Footprint -> GraphicGroup, Footprint -> VectorData, Footprint -> ImageFrame, )] value: impl Node, blend_mode: BlendMode, ) -> T { let mut value = value.eval(footprint).await; value.set_blend_mode(blend_mode); value } #[node_macro::node(category("Style"))] async fn opacity( #[implementations( (), (), (), Footprint, )] footprint: F, #[implementations( () -> GraphicGroup, () -> VectorData, () -> ImageFrame, Footprint -> GraphicGroup, Footprint -> VectorData, Footprint -> ImageFrame, )] value: impl Node, #[default(100.)] factor: Percentage, ) -> T { let mut value = value.eval(footprint).await; let opacity_multiplier = factor / 100.; value.multiply_alpha(opacity_multiplier); value }