mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-19 02:48:12 +08:00
Use canvas as target for raster rendering (#1256)
* Implement ApplicationIo * Simplify output duplication logic * Fix let node initialization for ExtractImageFrame * Async macros * Use manual node registry impl * Fix canvas insertion into the dom
This commit is contained in:
@@ -451,8 +451,8 @@ pub struct BlendNode<BlendMode, Opacity> {
|
||||
}
|
||||
|
||||
#[node_macro::node_fn(BlendNode)]
|
||||
fn blend_node(input: (Color, Color), blend_mode: BlendMode, opacity: f32) -> Color {
|
||||
let opacity = opacity / 100.;
|
||||
fn blend_node(input: (Color, Color), blend_mode: BlendMode, opacity: f64) -> Color {
|
||||
let opacity = opacity as f32 / 100.;
|
||||
|
||||
let (foreground, background) = input;
|
||||
|
||||
|
||||
@@ -12,7 +12,92 @@ use spirv_std::num_traits::Euclid;
|
||||
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
|
||||
use super::{Alpha, AssociatedAlpha, Luminance, Pixel, RGBMut, Rec709Primaries, RGB, SRGB};
|
||||
use super::{
|
||||
discrete_srgb::{float_to_srgb_u8, srgb_u8_to_float},
|
||||
Alpha, AssociatedAlpha, Luminance, Pixel, RGBMut, Rec709Primaries, RGB, SRGB,
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "std", derive(specta::Type))]
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, DynAny, Pod, Zeroable)]
|
||||
pub struct SRGBA8 {
|
||||
red: u8,
|
||||
green: u8,
|
||||
blue: u8,
|
||||
alpha: u8,
|
||||
}
|
||||
|
||||
impl From<Color> for SRGBA8 {
|
||||
#[inline(always)]
|
||||
fn from(c: Color) -> Self {
|
||||
Self {
|
||||
red: float_to_srgb_u8(c.r()),
|
||||
green: float_to_srgb_u8(c.g()),
|
||||
blue: float_to_srgb_u8(c.b()),
|
||||
alpha: (c.a() * 255.0) as u8,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SRGBA8> for Color {
|
||||
#[inline(always)]
|
||||
fn from(color: SRGBA8) -> Self {
|
||||
Self {
|
||||
red: srgb_u8_to_float(color.red),
|
||||
green: srgb_u8_to_float(color.green),
|
||||
blue: srgb_u8_to_float(color.blue),
|
||||
alpha: color.alpha as f32 / 255.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Luminance for SRGBA8 {
|
||||
type LuminanceChannel = f32;
|
||||
#[inline(always)]
|
||||
fn luminance(&self) -> f32 {
|
||||
// TODO: verify this is correct for sRGB
|
||||
0.2126 * self.red() + 0.7152 * self.green() + 0.0722 * self.blue()
|
||||
}
|
||||
}
|
||||
|
||||
impl RGB for SRGBA8 {
|
||||
type ColorChannel = f32;
|
||||
#[inline(always)]
|
||||
fn red(&self) -> f32 {
|
||||
self.red as f32 / 255.0
|
||||
}
|
||||
#[inline(always)]
|
||||
fn green(&self) -> f32 {
|
||||
self.green as f32 / 255.0
|
||||
}
|
||||
#[inline(always)]
|
||||
fn blue(&self) -> f32 {
|
||||
self.blue as f32 / 255.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Rec709Primaries for SRGBA8 {}
|
||||
impl SRGB for SRGBA8 {}
|
||||
|
||||
impl Alpha for SRGBA8 {
|
||||
type AlphaChannel = f32;
|
||||
#[inline(always)]
|
||||
fn alpha(&self) -> f32 {
|
||||
self.alpha as f32 / 255.0
|
||||
}
|
||||
|
||||
const TRANSPARENT: Self = SRGBA8 { red: 0, green: 0, blue: 0, alpha: 0 };
|
||||
|
||||
fn multiplied_alpha(&self, alpha: Self::AlphaChannel) -> Self {
|
||||
let alpha = alpha * 255.0;
|
||||
let mut result = *self;
|
||||
result.alpha = (alpha * self.alpha()) as u8;
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl Pixel for SRGBA8 {}
|
||||
|
||||
#[repr(C)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
|
||||
@@ -325,44 +325,43 @@ impl<P: Hash + Pixel> Hash for ImageFrame<P> {
|
||||
}
|
||||
}
|
||||
|
||||
use crate::text::FontCache;
|
||||
#[derive(Clone, Debug, Hash, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct EditorApi<'a> {
|
||||
#[cfg_attr(feature = "serde", serde(skip))]
|
||||
pub image_frame: Option<ImageFrame<Color>>,
|
||||
#[cfg_attr(feature = "serde", serde(skip))]
|
||||
pub font_cache: Option<&'a FontCache>,
|
||||
}
|
||||
/* This does not work because of missing specialization
|
||||
* so we have to manually implement this for now
|
||||
impl<S: Into<P> + Pixel, P: Pixel> From<Image<S>> for Image<P> {
|
||||
fn from(image: Image<S>) -> Self {
|
||||
let data = image.data.into_iter().map(|x| x.into()).collect();
|
||||
Self {
|
||||
data,
|
||||
width: image.width,
|
||||
height: image.height,
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
unsafe impl StaticType for EditorApi<'_> {
|
||||
type Static = EditorApi<'static>;
|
||||
}
|
||||
|
||||
impl EditorApi<'_> {
|
||||
pub fn empty() -> Self {
|
||||
Self { image_frame: None, font_cache: None }
|
||||
impl From<ImageFrame<Color>> for ImageFrame<SRGBA8> {
|
||||
fn from(image: ImageFrame<Color>) -> Self {
|
||||
let data = image.image.data.into_iter().map(|x| x.into()).collect();
|
||||
Self {
|
||||
image: Image {
|
||||
data,
|
||||
width: image.image.width,
|
||||
height: image.image.height,
|
||||
},
|
||||
transform: image.transform,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsRef<EditorApi<'a>> for EditorApi<'a> {
|
||||
fn as_ref(&self) -> &EditorApi<'a> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct ExtractImageFrame;
|
||||
|
||||
impl<'a: 'input, 'input> Node<'input, &'a EditorApi<'a>> for ExtractImageFrame {
|
||||
type Output = ImageFrame<Color>;
|
||||
fn eval(&'input self, editor_api: &'a EditorApi<'a>) -> Self::Output {
|
||||
editor_api.image_frame.clone().unwrap_or(ImageFrame::identity())
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtractImageFrame {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
impl From<ImageFrame<SRGBA8>> for ImageFrame<Color> {
|
||||
fn from(image: ImageFrame<SRGBA8>) -> Self {
|
||||
let data = image.image.data.into_iter().map(|x| x.into()).collect();
|
||||
Self {
|
||||
image: Image {
|
||||
data,
|
||||
width: image.image.width,
|
||||
height: image.image.height,
|
||||
},
|
||||
transform: image.transform,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user