mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-17 07:18:04 +08:00
Implement the Brush without relying on a stamp texture
Test Plan: Test the BrushNode in the editor Reviewers: Keavon Reviewed By: Keavon Pull Request: https://github.com/GraphiteEditor/Graphite/pull/1184
This commit is contained in:
committed by
Keavon Chambers
parent
5d9c0cb4d5
commit
1020eb6835
@@ -13,7 +13,7 @@ pub struct PushConstants {
|
||||
impl Sample for SampledImage<Image2d> {
|
||||
type Pixel = Color;
|
||||
|
||||
fn sample(&self, pos: glam::DVec2) -> Option<Self::Pixel> {
|
||||
fn sample(&self, pos: glam::DVec2, _area: glam::DVec2) -> Option<Self::Pixel> {
|
||||
let color = self.sample(pos);
|
||||
Color::from_rgbaf32(color.x, color.y, color.z, color.w)
|
||||
}
|
||||
|
||||
@@ -252,7 +252,7 @@ mod test {
|
||||
let value: ClonedNode<Result<&u32, ()>> = ClonedNode(Ok(&4u32));
|
||||
assert_eq!(value.eval(()), Ok(&4u32));
|
||||
//let type_erased_clone = clone as &dyn for<'a> Node<'a, &'a u32, Output = u32>;
|
||||
let map_result = MapResultNode::new(ValueNode::new(FnNode::new(|x: &u32| x.clone())));
|
||||
let map_result = MapResultNode::new(ValueNode::new(FnNode::new(|x: &u32| *x)));
|
||||
//et type_erased = &map_result as &dyn for<'a> Node<'a, Result<&'a u32, ()>, Output = Result<u32, ()>>;
|
||||
assert_eq!(map_result.eval(Ok(&4u32)), Ok(4u32));
|
||||
let fst = value.then(map_result);
|
||||
|
||||
@@ -171,7 +171,7 @@ pub trait Luminance {
|
||||
pub trait Sample {
|
||||
type Pixel: Pixel;
|
||||
// TODO: Add an area parameter
|
||||
fn sample(&self, pos: DVec2) -> Option<Self::Pixel>;
|
||||
fn sample(&self, pos: DVec2, area: DVec2) -> Option<Self::Pixel>;
|
||||
}
|
||||
|
||||
// TODO: We might rename this to Bitmap at some point
|
||||
|
||||
@@ -715,6 +715,9 @@ impl Color {
|
||||
}
|
||||
|
||||
pub fn to_unassociated_alpha(&self) -> Self {
|
||||
if self.alpha == 0. {
|
||||
return *self;
|
||||
}
|
||||
let unmultiply = 1. / self.alpha;
|
||||
Self {
|
||||
red: self.red * unmultiply,
|
||||
|
||||
@@ -26,7 +26,7 @@ mod base64_serde {
|
||||
{
|
||||
use serde::de::Error;
|
||||
|
||||
let color_from_chunk = |chunk: &[u8]| P::from_bytes(chunk.try_into().unwrap()).clone();
|
||||
let color_from_chunk = |chunk: &[u8]| P::from_bytes(chunk.try_into().unwrap());
|
||||
|
||||
let colors_from_bytes = |bytes: Vec<u8>| bytes.chunks_exact(P::byte_size()).map(color_from_chunk).collect();
|
||||
|
||||
@@ -129,7 +129,7 @@ where
|
||||
pub fn into_flat_u8(self) -> (Vec<u8>, u32, u32) {
|
||||
let Image { width, height, data } = self;
|
||||
|
||||
let to_gamma = |x| SRGBGammaFloat::from_linear(x);
|
||||
let to_gamma = SRGBGammaFloat::from_linear;
|
||||
let to_u8 = |x| (num_cast::<_, f32>(x).unwrap() * 255.) as u8;
|
||||
|
||||
let result_bytes = data
|
||||
@@ -201,7 +201,8 @@ pub struct ImageFrame<P: Pixel> {
|
||||
impl<P: Debug + Copy + Pixel> Sample for ImageFrame<P> {
|
||||
type Pixel = P;
|
||||
|
||||
fn sample(&self, pos: DVec2) -> Option<Self::Pixel> {
|
||||
// TODO: Improve sampling logic
|
||||
fn sample(&self, pos: DVec2, _area: DVec2) -> Option<Self::Pixel> {
|
||||
let image_size = DVec2::new(self.image.width() as f64, self.image.height() as f64);
|
||||
let pos = (DAffine2::from_scale(image_size) * self.transform.inverse()).transform_point2(pos);
|
||||
if pos.x < 0. || pos.y < 0. || pos.x >= image_size.x || pos.y >= image_size.y {
|
||||
|
||||
@@ -81,7 +81,7 @@ mod test {
|
||||
fn test_ref_eval() {
|
||||
let value = ValueNode::new(5);
|
||||
|
||||
assert_eq!((&value).eval(()), &5);
|
||||
assert_eq!(value.eval(()), &5);
|
||||
let id = IdNode::new();
|
||||
|
||||
let compose = ComposeNode::new(&value, &id);
|
||||
|
||||
@@ -7,6 +7,7 @@ pub struct IntNode<const N: u32>;
|
||||
|
||||
impl<'i, const N: u32> Node<'i, ()> for IntNode<N> {
|
||||
type Output = u32;
|
||||
#[inline(always)]
|
||||
fn eval(&'i self, _input: ()) -> Self::Output {
|
||||
N
|
||||
}
|
||||
@@ -17,6 +18,7 @@ pub struct ValueNode<T>(pub T);
|
||||
|
||||
impl<'i, T: 'i> Node<'i, ()> for ValueNode<T> {
|
||||
type Output = &'i T;
|
||||
#[inline(always)]
|
||||
fn eval(&'i self, _input: ()) -> Self::Output {
|
||||
&self.0
|
||||
}
|
||||
@@ -45,6 +47,7 @@ pub struct ClonedNode<T: Clone>(pub T);
|
||||
|
||||
impl<'i, T: Clone + 'i> Node<'i, ()> for ClonedNode<T> {
|
||||
type Output = T;
|
||||
#[inline(always)]
|
||||
fn eval(&'i self, _input: ()) -> Self::Output {
|
||||
self.0.clone()
|
||||
}
|
||||
@@ -62,11 +65,34 @@ impl<T: Clone> From<T> for ClonedNode<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
/// The DebugClonedNode logs every time it is evaluated.
|
||||
/// This is useful for debugging.
|
||||
pub struct DebugClonedNode<T: Clone>(pub T);
|
||||
|
||||
impl<'i, T: Clone + 'i> Node<'i, ()> for DebugClonedNode<T> {
|
||||
type Output = T;
|
||||
#[inline(always)]
|
||||
fn eval(&'i self, _input: ()) -> Self::Output {
|
||||
// KEEP THIS `debug!()` - It acts as the output for the debug node itself
|
||||
log::debug!("DebugClonedNode::eval");
|
||||
|
||||
self.0.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> DebugClonedNode<T> {
|
||||
pub const fn new(value: T) -> ClonedNode<T> {
|
||||
ClonedNode(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CopiedNode<T: Copy>(pub T);
|
||||
|
||||
impl<'i, T: Copy + 'i> Node<'i, ()> for CopiedNode<T> {
|
||||
type Output = T;
|
||||
#[inline(always)]
|
||||
fn eval(&'i self, _input: ()) -> Self::Output {
|
||||
self.0
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ fn set_vector_data_fill(
|
||||
positions: Vec<(f64, Option<Color>)>,
|
||||
) -> VectorData {
|
||||
vector_data.style.set_fill(match fill_type {
|
||||
FillType::None | FillType::Solid => solid_color.map_or(Fill::None, |solid_color| Fill::Solid(solid_color)),
|
||||
FillType::None | FillType::Solid => solid_color.map_or(Fill::None, Fill::Solid),
|
||||
FillType::Gradient => Fill::Gradient(Gradient {
|
||||
start,
|
||||
end,
|
||||
|
||||
Reference in New Issue
Block a user