mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-04 05:18:19 +00:00
Wrap opacity/blend_mode in alpha_blending struct for graphic elements
This commit is contained in:
parent
10f2fa92e5
commit
e459e599b4
15 changed files with 111 additions and 96 deletions
|
@ -13,38 +13,72 @@ use glam::{DAffine2, DVec2, IVec2, UVec2};
|
|||
|
||||
pub mod renderer;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, DynAny, specta::Type)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct AlphaBlending {
|
||||
pub opacity: f32,
|
||||
pub blend_mode: BlendMode,
|
||||
}
|
||||
impl Default for AlphaBlending {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
impl core::hash::Hash for AlphaBlending {
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
self.opacity.to_bits().hash(state);
|
||||
self.blend_mode.hash(state);
|
||||
}
|
||||
}
|
||||
impl AlphaBlending {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
opacity: 1.,
|
||||
blend_mode: BlendMode::Normal,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A list of [`GraphicElement`]s
|
||||
#[derive(Clone, Debug, PartialEq, DynAny, Default)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct GraphicGroup {
|
||||
elements: Vec<GraphicElement>,
|
||||
pub opacity: f32,
|
||||
pub blend_mode: BlendMode,
|
||||
pub transform: DAffine2,
|
||||
pub alpha_blending: AlphaBlending,
|
||||
}
|
||||
|
||||
impl core::hash::Hash for GraphicGroup {
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
self.transform.to_cols_array().iter().for_each(|element| element.to_bits().hash(state));
|
||||
self.elements.hash(state);
|
||||
self.opacity.to_bits().hash(state);
|
||||
self.transform.to_cols_array().iter().for_each(|element| element.to_bits().hash(state))
|
||||
self.alpha_blending.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal data for a [`GraphicElement`]. Can be [`VectorData`], [`ImageFrame`], text, or a nested [`GraphicGroup`]
|
||||
/// The possible forms of graphical content held in a Vec by the `elements` field of [`GraphicElement`].
|
||||
/// Can be another recursively nested [`GraphicGroup`], [`VectorData`], an [`ImageFrame`], text (not yet implemented), or an [`Artboard`].
|
||||
#[derive(Clone, Debug, Hash, PartialEq, DynAny)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum GraphicElement {
|
||||
VectorShape(Box<VectorData>),
|
||||
ImageFrame(ImageFrame<Color>),
|
||||
Text(String),
|
||||
/// Equivalent to the SVG <g> tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/g
|
||||
GraphicGroup(GraphicGroup),
|
||||
/// A vector shape, equivalent to the SVG <path> tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path
|
||||
VectorData(Box<VectorData>),
|
||||
/// A bitmap image with a finite position and extent, equivalent to the SVG <image> tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image
|
||||
ImageFrame(ImageFrame<Color>),
|
||||
// TODO: Switch from `String` to a proper formatted typography type
|
||||
/// Text, equivalent to the SVG <text> tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/text
|
||||
/// (Not yet implemented.)
|
||||
Text(String),
|
||||
/// The bounds for displaying a page of contained content
|
||||
Artboard(Artboard),
|
||||
}
|
||||
|
||||
// TODO: Can this be removed? It doesn't necessarily make that much sense to have a default when, instead, the entire GraphicElement just shouldn't exist if there's no specific content to assign it.
|
||||
impl Default for GraphicElement {
|
||||
fn default() -> Self {
|
||||
Self::VectorShape(Box::new(VectorData::empty()))
|
||||
Self::VectorData(Box::new(VectorData::empty()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,7 +165,7 @@ impl From<ImageFrame<Color>> for GraphicElement {
|
|||
}
|
||||
impl From<VectorData> for GraphicElement {
|
||||
fn from(vector_data: VectorData) -> Self {
|
||||
GraphicElement::VectorShape(Box::new(vector_data))
|
||||
GraphicElement::VectorData(Box::new(vector_data))
|
||||
}
|
||||
}
|
||||
impl From<GraphicGroup> for GraphicElement {
|
||||
|
@ -173,9 +207,8 @@ where
|
|||
fn from(value: T) -> Self {
|
||||
Self {
|
||||
elements: (vec![value.into()]),
|
||||
opacity: 1.,
|
||||
blend_mode: BlendMode::Normal,
|
||||
transform: DAffine2::IDENTITY,
|
||||
alpha_blending: AlphaBlending::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -183,9 +216,8 @@ where
|
|||
impl GraphicGroup {
|
||||
pub const EMPTY: Self = Self {
|
||||
elements: Vec::new(),
|
||||
opacity: 1.,
|
||||
blend_mode: BlendMode::Normal,
|
||||
transform: DAffine2::IDENTITY,
|
||||
alpha_blending: AlphaBlending::new(),
|
||||
};
|
||||
|
||||
pub fn to_usvg_tree(&self, resolution: UVec2, viewbox: [DVec2; 2]) -> usvg::Tree {
|
||||
|
@ -214,7 +246,7 @@ impl GraphicElement {
|
|||
}
|
||||
|
||||
match self {
|
||||
GraphicElement::VectorShape(vector_data) => {
|
||||
GraphicElement::VectorData(vector_data) => {
|
||||
use usvg::tiny_skia_path::PathBuilder;
|
||||
let mut builder = PathBuilder::new();
|
||||
|
||||
|
|
|
@ -223,12 +223,12 @@ impl GraphicElementRendered for GraphicGroup {
|
|||
|attributes| {
|
||||
attributes.push("transform", format_transform_matrix(self.transform));
|
||||
|
||||
if self.opacity < 1. {
|
||||
attributes.push("opacity", self.opacity.to_string());
|
||||
if self.alpha_blending.opacity < 1. {
|
||||
attributes.push("opacity", self.alpha_blending.opacity.to_string());
|
||||
}
|
||||
|
||||
if self.blend_mode != BlendMode::default() {
|
||||
attributes.push("style", self.blend_mode.render());
|
||||
if self.alpha_blending.blend_mode != BlendMode::default() {
|
||||
attributes.push("style", self.alpha_blending.blend_mode.render());
|
||||
}
|
||||
},
|
||||
|render| {
|
||||
|
@ -275,12 +275,12 @@ impl GraphicElementRendered for VectorData {
|
|||
.render(render_params.view_mode, &mut attributes.0.svg_defs, multiplied_transform, layer_bounds, transformed_bounds);
|
||||
attributes.push_val(fill_and_stroke);
|
||||
|
||||
if self.style.opacity < 1. {
|
||||
attributes.push("opacity", self.style.opacity.to_string());
|
||||
if self.alpha_blending.opacity < 1. {
|
||||
attributes.push("opacity", self.alpha_blending.opacity.to_string());
|
||||
}
|
||||
|
||||
if self.style.blend_mode != BlendMode::default() {
|
||||
attributes.push("style", self.style.blend_mode.render());
|
||||
if self.alpha_blending.blend_mode != BlendMode::default() {
|
||||
attributes.push("style", self.alpha_blending.blend_mode.render());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -426,8 +426,8 @@ impl GraphicElementRendered for ImageFrame<Color> {
|
|||
attributes.push("preserveAspectRatio", "none");
|
||||
attributes.push("transform", transform);
|
||||
attributes.push("href", SvgSegment::BlobUrl(uuid));
|
||||
if self.blend_mode != BlendMode::default() {
|
||||
attributes.push("style", self.blend_mode.render());
|
||||
if self.alpha_blending.blend_mode != BlendMode::default() {
|
||||
attributes.push("style", self.alpha_blending.blend_mode.render());
|
||||
}
|
||||
});
|
||||
render.image_data.push((uuid, self.image.clone()))
|
||||
|
@ -449,8 +449,8 @@ impl GraphicElementRendered for ImageFrame<Color> {
|
|||
attributes.push("preserveAspectRatio", "none");
|
||||
attributes.push("transform", transform);
|
||||
attributes.push("href", base64_string);
|
||||
if self.blend_mode != BlendMode::default() {
|
||||
attributes.push("style", self.blend_mode.render());
|
||||
if self.alpha_blending.blend_mode != BlendMode::default() {
|
||||
attributes.push("style", self.alpha_blending.blend_mode.render());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -493,7 +493,7 @@ impl GraphicElementRendered for ImageFrame<Color> {
|
|||
impl GraphicElementRendered for GraphicElement {
|
||||
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
|
||||
match self {
|
||||
GraphicElement::VectorShape(vector_data) => vector_data.render_svg(render, render_params),
|
||||
GraphicElement::VectorData(vector_data) => vector_data.render_svg(render, render_params),
|
||||
GraphicElement::ImageFrame(image_frame) => image_frame.render_svg(render, render_params),
|
||||
GraphicElement::Text(_) => todo!("Render a text GraphicElement"),
|
||||
GraphicElement::GraphicGroup(graphic_group) => graphic_group.render_svg(render, render_params),
|
||||
|
@ -503,7 +503,7 @@ impl GraphicElementRendered for GraphicElement {
|
|||
|
||||
fn bounding_box(&self, transform: DAffine2) -> Option<[DVec2; 2]> {
|
||||
match self {
|
||||
GraphicElement::VectorShape(vector_data) => GraphicElementRendered::bounding_box(&**vector_data, transform),
|
||||
GraphicElement::VectorData(vector_data) => GraphicElementRendered::bounding_box(&**vector_data, transform),
|
||||
GraphicElement::ImageFrame(image_frame) => image_frame.bounding_box(transform),
|
||||
GraphicElement::Text(_) => todo!("Bounds of a text GraphicElement"),
|
||||
GraphicElement::GraphicGroup(graphic_group) => graphic_group.bounding_box(transform),
|
||||
|
@ -513,7 +513,7 @@ impl GraphicElementRendered for GraphicElement {
|
|||
|
||||
fn add_click_targets(&self, click_targets: &mut Vec<ClickTarget>) {
|
||||
match self {
|
||||
GraphicElement::VectorShape(vector_data) => vector_data.add_click_targets(click_targets),
|
||||
GraphicElement::VectorData(vector_data) => vector_data.add_click_targets(click_targets),
|
||||
GraphicElement::ImageFrame(image_frame) => image_frame.add_click_targets(click_targets),
|
||||
GraphicElement::Text(_) => todo!("click target for text GraphicElement"),
|
||||
GraphicElement::GraphicGroup(graphic_group) => graphic_group.add_click_targets(click_targets),
|
||||
|
@ -523,7 +523,7 @@ impl GraphicElementRendered for GraphicElement {
|
|||
|
||||
fn to_usvg_node(&self) -> usvg::Node {
|
||||
match self {
|
||||
GraphicElement::VectorShape(vector_data) => vector_data.to_usvg_node(),
|
||||
GraphicElement::VectorData(vector_data) => vector_data.to_usvg_node(),
|
||||
GraphicElement::ImageFrame(image_frame) => image_frame.to_usvg_node(),
|
||||
GraphicElement::Text(text) => text.to_usvg_node(),
|
||||
GraphicElement::GraphicGroup(graphic_group) => graphic_group.to_usvg_node(),
|
||||
|
|
|
@ -912,14 +912,14 @@ fn opacity_node(color: Color, opacity_multiplier: f32) -> Color {
|
|||
#[node_macro::node_impl(OpacityNode)]
|
||||
fn opacity_node(mut vector_data: VectorData, opacity_multiplier: f32) -> VectorData {
|
||||
let opacity_multiplier = opacity_multiplier / 100.;
|
||||
vector_data.style.opacity *= opacity_multiplier;
|
||||
vector_data.alpha_blending.opacity *= opacity_multiplier;
|
||||
vector_data
|
||||
}
|
||||
|
||||
#[node_macro::node_impl(OpacityNode)]
|
||||
fn opacity_node(mut graphic_group: GraphicGroup, opacity_multiplier: f32) -> GraphicGroup {
|
||||
let opacity_multiplier = opacity_multiplier / 100.;
|
||||
graphic_group.opacity *= opacity_multiplier;
|
||||
graphic_group.alpha_blending.opacity *= opacity_multiplier;
|
||||
graphic_group
|
||||
}
|
||||
|
||||
|
@ -930,19 +930,19 @@ pub struct BlendModeNode<BM> {
|
|||
|
||||
#[node_macro::node_fn(BlendModeNode)]
|
||||
fn blend_mode_node(mut vector_data: VectorData, blend_mode: BlendMode) -> VectorData {
|
||||
vector_data.style.blend_mode = blend_mode;
|
||||
vector_data.alpha_blending.blend_mode = blend_mode;
|
||||
vector_data
|
||||
}
|
||||
|
||||
#[node_macro::node_impl(BlendModeNode)]
|
||||
fn blend_mode_node(mut graphic_group: GraphicGroup, blend_mode: BlendMode) -> GraphicGroup {
|
||||
graphic_group.blend_mode = blend_mode;
|
||||
graphic_group.alpha_blending.blend_mode = blend_mode;
|
||||
graphic_group
|
||||
}
|
||||
|
||||
#[node_macro::node_impl(BlendModeNode)]
|
||||
fn blend_mode_node(mut image_frame: ImageFrame<Color>, blend_mode: BlendMode) -> ImageFrame<Color> {
|
||||
image_frame.blend_mode = blend_mode;
|
||||
image_frame.alpha_blending.blend_mode = blend_mode;
|
||||
image_frame
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::discrete_srgb::float_to_srgb_u8;
|
||||
use super::{Color, ImageSlice};
|
||||
use crate::Node;
|
||||
use crate::{AlphaBlending, Node};
|
||||
use alloc::vec::Vec;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use dyn_any::StaticType;
|
||||
|
@ -260,7 +260,7 @@ pub struct ImageFrame<P: Pixel> {
|
|||
// positive going right and y axis positive going down, with the origin
|
||||
// being an unspecified quantity.
|
||||
pub transform: DAffine2,
|
||||
pub blend_mode: BlendMode,
|
||||
pub alpha_blending: AlphaBlending,
|
||||
}
|
||||
|
||||
impl<P: Debug + Copy + Pixel> Sample for ImageFrame<P> {
|
||||
|
@ -312,7 +312,7 @@ impl<P: Copy + Pixel> ImageFrame<P> {
|
|||
Self {
|
||||
image: Image::empty(),
|
||||
transform: DAffine2::ZERO,
|
||||
blend_mode: BlendMode::Normal,
|
||||
alpha_blending: AlphaBlending::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -320,7 +320,7 @@ impl<P: Copy + Pixel> ImageFrame<P> {
|
|||
Self {
|
||||
image: Image::empty(),
|
||||
transform: DAffine2::IDENTITY,
|
||||
blend_mode: BlendMode::Normal,
|
||||
alpha_blending: AlphaBlending::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -381,7 +381,7 @@ impl From<ImageFrame<Color>> for ImageFrame<SRGBA8> {
|
|||
height: image.image.height,
|
||||
},
|
||||
transform: image.transform,
|
||||
blend_mode: BlendMode::Normal,
|
||||
alpha_blending: image.alpha_blending,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -396,7 +396,7 @@ impl From<ImageFrame<SRGBA8>> for ImageFrame<Color> {
|
|||
height: image.image.height,
|
||||
},
|
||||
transform: image.transform,
|
||||
blend_mode: BlendMode::Normal,
|
||||
alpha_blending: image.alpha_blending,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ impl TransformMut for GraphicGroup {
|
|||
impl Transform for GraphicElement {
|
||||
fn transform(&self) -> DAffine2 {
|
||||
match self {
|
||||
GraphicElement::VectorShape(vector_shape) => vector_shape.transform(),
|
||||
GraphicElement::VectorData(vector_shape) => vector_shape.transform(),
|
||||
GraphicElement::ImageFrame(image_frame) => image_frame.transform(),
|
||||
GraphicElement::Text(_) => todo!("Transform of text"),
|
||||
GraphicElement::GraphicGroup(graphic_group) => graphic_group.transform(),
|
||||
|
@ -82,7 +82,7 @@ impl Transform for GraphicElement {
|
|||
}
|
||||
fn local_pivot(&self, pivot: DVec2) -> DVec2 {
|
||||
match self {
|
||||
GraphicElement::VectorShape(vector_shape) => vector_shape.local_pivot(pivot),
|
||||
GraphicElement::VectorData(vector_shape) => vector_shape.local_pivot(pivot),
|
||||
GraphicElement::ImageFrame(image_frame) => image_frame.local_pivot(pivot),
|
||||
GraphicElement::Text(_) => todo!("Transform of text"),
|
||||
GraphicElement::GraphicGroup(graphic_group) => graphic_group.local_pivot(pivot),
|
||||
|
@ -91,7 +91,7 @@ impl Transform for GraphicElement {
|
|||
}
|
||||
fn decompose_scale(&self) -> DVec2 {
|
||||
match self {
|
||||
GraphicElement::VectorShape(vector_shape) => vector_shape.decompose_scale(),
|
||||
GraphicElement::VectorData(vector_shape) => vector_shape.decompose_scale(),
|
||||
GraphicElement::ImageFrame(image_frame) => image_frame.decompose_scale(),
|
||||
GraphicElement::Text(_) => todo!("Transform of text"),
|
||||
GraphicElement::GraphicGroup(graphic_group) => graphic_group.decompose_scale(),
|
||||
|
@ -102,7 +102,7 @@ impl Transform for GraphicElement {
|
|||
impl TransformMut for GraphicElement {
|
||||
fn transform_mut(&mut self) -> &mut DAffine2 {
|
||||
match self {
|
||||
GraphicElement::VectorShape(vector_shape) => vector_shape.transform_mut(),
|
||||
GraphicElement::VectorData(vector_shape) => vector_shape.transform_mut(),
|
||||
GraphicElement::ImageFrame(image_frame) => image_frame.transform_mut(),
|
||||
GraphicElement::Text(_) => todo!("Transform of text"),
|
||||
GraphicElement::GraphicGroup(graphic_group) => graphic_group.transform_mut(),
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
//! Contains stylistic options for SVG elements.
|
||||
|
||||
use crate::consts::{LAYER_OUTLINE_STROKE_COLOR, LAYER_OUTLINE_STROKE_WEIGHT};
|
||||
use crate::raster::BlendMode;
|
||||
use crate::Color;
|
||||
|
||||
use dyn_any::{DynAny, StaticType};
|
||||
|
@ -410,27 +409,18 @@ impl Default for Stroke {
|
|||
pub struct PathStyle {
|
||||
stroke: Option<Stroke>,
|
||||
fill: Fill,
|
||||
pub opacity: f32,
|
||||
pub blend_mode: BlendMode,
|
||||
}
|
||||
|
||||
impl core::hash::Hash for PathStyle {
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
self.stroke.hash(state);
|
||||
self.fill.hash(state);
|
||||
self.opacity.to_bits().hash(state);
|
||||
self.blend_mode.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl PathStyle {
|
||||
pub const fn new(stroke: Option<Stroke>, fill: Fill) -> Self {
|
||||
Self {
|
||||
stroke,
|
||||
fill,
|
||||
opacity: 1.,
|
||||
blend_mode: BlendMode::Normal,
|
||||
}
|
||||
Self { stroke, fill }
|
||||
}
|
||||
|
||||
/// Get the current path's [Fill].
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::style::{PathStyle, Stroke};
|
||||
use crate::uuid::ManipulatorGroupId;
|
||||
use crate::Color;
|
||||
use crate::{uuid::ManipulatorGroupId, AlphaBlending};
|
||||
|
||||
use bezier_rs::ManipulatorGroup;
|
||||
use dyn_any::{DynAny, StaticType};
|
||||
|
@ -8,13 +8,14 @@ use dyn_any::{DynAny, StaticType};
|
|||
use glam::{DAffine2, DVec2};
|
||||
|
||||
/// [VectorData] is passed between nodes.
|
||||
/// It contains a list of subpaths (that may be open or closed), a transform and some style information.
|
||||
/// It contains a list of subpaths (that may be open or closed), a transform, and some style information.
|
||||
#[derive(Clone, Debug, PartialEq, DynAny)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct VectorData {
|
||||
pub subpaths: Vec<bezier_rs::Subpath<ManipulatorGroupId>>,
|
||||
pub transform: DAffine2,
|
||||
pub style: PathStyle,
|
||||
pub alpha_blending: AlphaBlending,
|
||||
// TODO: Keavon asks: what is this for? Is it dead code? It seems to only be set, never read.
|
||||
pub mirror_angle: Vec<ManipulatorGroupId>,
|
||||
}
|
||||
|
@ -24,6 +25,7 @@ impl core::hash::Hash for VectorData {
|
|||
self.subpaths.hash(state);
|
||||
self.transform.to_cols_array().iter().for_each(|x| x.to_bits().hash(state));
|
||||
self.style.hash(state);
|
||||
self.alpha_blending.hash(state);
|
||||
self.mirror_angle.hash(state);
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +37,7 @@ impl VectorData {
|
|||
subpaths: Vec::new(),
|
||||
transform: DAffine2::IDENTITY,
|
||||
style: PathStyle::new(Some(Stroke::new(Some(Color::BLACK), 0.)), super::style::Fill::None),
|
||||
alpha_blending: AlphaBlending::new(),
|
||||
mirror_angle: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -356,7 +356,7 @@ async fn brush(image: ImageFrame<Color>, bounds: ImageFrame<Color>, strokes: Vec
|
|||
let opaque_image = ImageFrame {
|
||||
image: Image::new(bbox.size().x as u32, bbox.size().y as u32, Color::WHITE),
|
||||
transform: background_bounds,
|
||||
blend_mode: BlendMode::Normal,
|
||||
..Default::default()
|
||||
};
|
||||
let mut erase_restore_mask = opaque_image;
|
||||
|
||||
|
@ -410,11 +410,7 @@ mod test {
|
|||
#[test]
|
||||
fn test_translate_node() {
|
||||
let image = Image::new(10, 10, Color::TRANSPARENT);
|
||||
let mut image = ImageFrame {
|
||||
image,
|
||||
transform: DAffine2::IDENTITY,
|
||||
blend_mode: BlendMode::Normal,
|
||||
};
|
||||
let mut image = ImageFrame { image, ..Default::default() };
|
||||
image.translate(DVec2::new(1., 2.));
|
||||
let translate_node = TranslateNode::new(ClonedNode::new(image));
|
||||
let image = translate_node.eval(DVec2::new(1., 2.));
|
||||
|
|
|
@ -90,7 +90,7 @@ async fn map_gpu<'a: 'input>(image: ImageFrame<Color>, node: DocumentNode, edito
|
|||
height: image.image.height,
|
||||
},
|
||||
transform: image.transform,
|
||||
blend_mode: image.blend_mode,
|
||||
alpha_blending: image.alpha_blending,
|
||||
};
|
||||
|
||||
// TODO: The cache should be based on the network topology not the node name
|
||||
|
@ -142,7 +142,7 @@ async fn map_gpu<'a: 'input>(image: ImageFrame<Color>, node: DocumentNode, edito
|
|||
height: image.image.height,
|
||||
},
|
||||
transform: image.transform,
|
||||
blend_mode: image.blend_mode,
|
||||
alpha_blending: image.alpha_blending,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -588,6 +588,6 @@ async fn blend_gpu_image(foreground: ImageFrame<Color>, background: ImageFrame<C
|
|||
height: background.image.height,
|
||||
},
|
||||
transform: background.transform,
|
||||
blend_mode: background.blend_mode,
|
||||
alpha_blending: background.alpha_blending,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use graphene_core::transform::{Footprint, Transform};
|
|||
use crate::wasm_application_io::WasmEditorApi;
|
||||
use graphene_core::raster::bbox::{AxisAlignedBbox, Bbox};
|
||||
use graphene_core::value::CopiedNode;
|
||||
use graphene_core::{Color, Node};
|
||||
use graphene_core::{AlphaBlending, Color, Node};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Debug;
|
||||
|
@ -115,7 +115,7 @@ fn sample(footprint: Footprint, image_frame: ImageFrame<Color>) -> ImageFrame<Co
|
|||
ImageFrame {
|
||||
image,
|
||||
transform: new_transform,
|
||||
blend_mode: image_frame.blend_mode,
|
||||
alpha_blending: image_frame.alpha_blending,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -309,7 +309,7 @@ where
|
|||
let mut new_background = ImageFrame {
|
||||
image: new_background,
|
||||
transform: transfrom,
|
||||
blend_mode: background.blend_mode,
|
||||
alpha_blending: background.alpha_blending,
|
||||
};
|
||||
|
||||
new_background = blend_image(background, new_background, map_fn);
|
||||
|
@ -422,7 +422,7 @@ fn extend_image_to_bounds_node(image: ImageFrame<Color>, bounds: DAffine2) -> Im
|
|||
ImageFrame {
|
||||
image: new_img,
|
||||
transform: new_texture_to_layer_space,
|
||||
blend_mode: image.blend_mode,
|
||||
alpha_blending: image.alpha_blending,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -457,8 +457,11 @@ fn empty_image<_P: Pixel>(transform: DAffine2, color: _P) -> ImageFrame<_P> {
|
|||
|
||||
let image = Image::new(width, height, color);
|
||||
|
||||
let blend_mode = BlendMode::Normal;
|
||||
ImageFrame { image, transform, blend_mode }
|
||||
ImageFrame {
|
||||
image,
|
||||
transform,
|
||||
alpha_blending: AlphaBlending::default(),
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! generate_imaginate_node {
|
||||
|
@ -495,7 +498,7 @@ macro_rules! generate_imaginate_node {
|
|||
use std::hash::Hasher;
|
||||
let mut hasher = rustc_hash::FxHasher::default();
|
||||
frame.image.hash(&mut hasher);
|
||||
let hash =hasher.finish();
|
||||
let hash = hasher.finish();
|
||||
|
||||
Box::pin(async move {
|
||||
let controller: std::pin::Pin<Box<dyn std::future::Future<Output = ImaginateController>>> = controller;
|
||||
|
@ -505,16 +508,12 @@ macro_rules! generate_imaginate_node {
|
|||
let image = super::imaginate::imaginate(frame.image, editor_api, controller, $($val,)*).await;
|
||||
|
||||
self.cache.lock().unwrap().insert(hash, image.clone());
|
||||
return ImageFrame {
|
||||
image,
|
||||
..frame
|
||||
}
|
||||
|
||||
return ImageFrame { image, ..frame }
|
||||
}
|
||||
let image = self.cache.lock().unwrap().get(&hash).cloned().unwrap_or_default();
|
||||
ImageFrame {
|
||||
image,
|
||||
..frame
|
||||
}
|
||||
|
||||
ImageFrame { image, ..frame }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -549,7 +548,7 @@ fn image_frame<_P: Pixel>(image: Image<_P>, transform: DAffine2) -> graphene_cor
|
|||
graphene_core::raster::ImageFrame {
|
||||
image,
|
||||
transform,
|
||||
blend_mode: BlendMode::Normal,
|
||||
alpha_blending: AlphaBlending::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -576,7 +575,7 @@ fn pixel_noise(width: u32, height: u32, seed: u32, noise_type: NoiseType) -> gra
|
|||
ImageFrame::<Color> {
|
||||
image,
|
||||
transform: DAffine2::from_scale(DVec2::new(width as f64, height as f64)),
|
||||
blend_mode: BlendMode::Normal,
|
||||
alpha_blending: AlphaBlending::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -621,7 +620,7 @@ fn mandelbrot_node(footprint: Footprint) -> ImageFrame<Color> {
|
|||
ImageFrame {
|
||||
image: Image { width, height, data },
|
||||
transform: DAffine2::from_translation(offset) * DAffine2::from_scale(size),
|
||||
blend_mode: BlendMode::Normal,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -279,8 +279,7 @@ fn decode_image_node<'a: 'input>(data: Arc<[u8]>) -> ImageFrame<Color> {
|
|||
width: image.width(),
|
||||
height: image.height(),
|
||||
},
|
||||
transform: glam::DAffine2::IDENTITY,
|
||||
blend_mode: graphene_core::raster::BlendMode::Normal,
|
||||
..Default::default()
|
||||
};
|
||||
image
|
||||
}
|
||||
|
|
|
@ -312,7 +312,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||
let empty_image = ImageFrame {
|
||||
image: Image::new(bounds.x, bounds.y, Color::BLACK),
|
||||
transform,
|
||||
blend_mode: BlendMode::Normal,
|
||||
..Default::default()
|
||||
};
|
||||
let final_image = ClonedNode::new(empty_image).then(complete_node);
|
||||
let final_image = FutureWrapperNode::new(final_image);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue