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:
Dennis Kobert
2023-05-30 20:12:59 +02:00
committed by Keavon Chambers
parent 57415b948b
commit 259dcdc628
27 changed files with 810 additions and 259 deletions

View File

@@ -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;

View File

@@ -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))]

View File

@@ -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,
}
}
}