Fix how transforms work with footprints and remove a redundant transforms field (#1484)

* Prune unused thumbnails in node graph executor

* Fix transform downcasting failure for GraphicElementData

* Remove more warnings

* Revert upstream transform calculation change

* Use footprint to calculate layer transforms

* Fix artboards

* Move artwork with artboard

* Remove Keavon's warnings

* Prevent misordered FrontendMessages failing to reach JS handlers

---------

Co-authored-by: 0hypercube <0hypercube@gmail.com>
Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Dennis Kobert 2023-12-03 23:17:28 +01:00 committed by GitHub
parent 1093aabc88
commit b7fe38cf31
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 116 additions and 112 deletions

View file

@ -1,4 +1,5 @@
use crate::raster::{BlendMode, ImageFrame};
use crate::transform::Footprint;
use crate::vector::VectorData;
use crate::{Color, Node};
@ -136,7 +137,8 @@ fn to_graphic_element_data<Data: Into<GraphicElementData>>(graphic_element_data:
graphic_element_data.into()
}
pub struct ConstructArtboardNode<Location, Dimensions, Background, Clip> {
pub struct ConstructArtboardNode<Contents, Location, Dimensions, Background, Clip> {
contents: Contents,
location: Location,
dimensions: Dimensions,
background: Background,
@ -144,7 +146,16 @@ pub struct ConstructArtboardNode<Location, Dimensions, Background, Clip> {
}
#[node_fn(ConstructArtboardNode)]
fn construct_artboard(graphic_group: GraphicGroup, location: IVec2, dimensions: IVec2, background: Color, clip: bool) -> Artboard {
async fn construct_artboard<Fut: Future<Output = GraphicGroup>>(
mut footprint: Footprint,
contents: impl Node<Footprint, Output = Fut>,
location: IVec2,
dimensions: IVec2,
background: Color,
clip: bool,
) -> Artboard {
footprint.transform = footprint.transform * DAffine2::from_translation(location.as_dvec2());
let graphic_group = self.contents.eval(footprint).await;
Artboard {
graphic_group,
location: location.min(location + dimensions),

View file

@ -284,15 +284,20 @@ impl GraphicElementRendered for Artboard {
"g",
|attributes| {
attributes.push("class", "artboard");
attributes.push("transform", format_transform_matrix(self.graphic_group.transform));
attributes.push(
"transform",
format_transform_matrix(DAffine2::from_translation(self.location.as_dvec2()) * self.graphic_group.transform),
);
if self.clip {
let id = format!("artboard-{}", generate_uuid());
let selector = format!("url(#{id})");
use std::fmt::Write;
write!(
&mut attributes.0.svg_defs,
r##"<clipPath id="{id}"><rect x="{}" y="{}" width="{}" height="{}"/></clipPath>"##,
self.location.x, self.location.y, self.dimensions.x, self.dimensions.y
r##"<clipPath id="{id}"><rect x="0" y="0" width="{}" height="{}" transform="{}"/></clipPath>"##,
self.dimensions.x,
self.dimensions.y,
format_transform_matrix(self.graphic_group.transform.inverse())
)
.unwrap();
attributes.push("clip-path", selector);

View file

@ -54,6 +54,10 @@ pub trait Node<'i, Input: 'i>: 'i {
fn eval(&'i self, input: Input) -> Self::Output;
/// Resets the node, e.g. the LetNode's cache is set to None.
fn reset(&self) {}
/// Returns the name of the node for diagnostic purposes.
fn node_name(&self) -> &'static str {
core::any::type_name::<Self>()
}
/// Serialize the node which is used for the `introspect` function which can retrieve values from monitor nodes.
#[cfg(feature = "std")]
fn serialize(&self) -> Option<std::sync::Arc<dyn core::any::Any>> {
@ -98,10 +102,6 @@ where
Self::Output: 'i + StaticTypeSized,
Input: 'i + StaticTypeSized,
{
fn node_name(&self) -> &'static str {
core::any::type_name::<Self>()
}
fn input_type(&self) -> TypeId {
TypeId::of::<Input::Static>()
}

View file

@ -9,6 +9,7 @@ use crate::raster::bbox::AxisAlignedBbox;
use crate::raster::ImageFrame;
use crate::raster::Pixel;
use crate::vector::VectorData;
use crate::Artboard;
use crate::GraphicElementData;
use crate::GraphicGroup;
use crate::Node;
@ -76,7 +77,7 @@ impl Transform for GraphicElementData {
GraphicElementData::ImageFrame(image_frame) => image_frame.transform(),
GraphicElementData::Text(_) => todo!("Transform of text"),
GraphicElementData::GraphicGroup(graphic_group) => graphic_group.transform(),
GraphicElementData::Artboard(artboard) => artboard.graphic_group.transform(),
GraphicElementData::Artboard(artboard) => artboard.transform(),
}
}
fn local_pivot(&self, pivot: DVec2) -> DVec2 {
@ -85,7 +86,7 @@ impl Transform for GraphicElementData {
GraphicElementData::ImageFrame(image_frame) => image_frame.local_pivot(pivot),
GraphicElementData::Text(_) => todo!("Transform of text"),
GraphicElementData::GraphicGroup(graphic_group) => graphic_group.local_pivot(pivot),
GraphicElementData::Artboard(artboard) => artboard.graphic_group.local_pivot(pivot),
GraphicElementData::Artboard(artboard) => artboard.local_pivot(pivot),
}
}
fn decompose_scale(&self) -> DVec2 {
@ -94,7 +95,7 @@ impl Transform for GraphicElementData {
GraphicElementData::ImageFrame(image_frame) => image_frame.decompose_scale(),
GraphicElementData::Text(_) => todo!("Transform of text"),
GraphicElementData::GraphicGroup(graphic_group) => graphic_group.decompose_scale(),
GraphicElementData::Artboard(artboard) => artboard.graphic_group.decompose_scale(),
GraphicElementData::Artboard(artboard) => artboard.decompose_scale(),
}
}
}
@ -105,7 +106,7 @@ impl TransformMut for GraphicElementData {
GraphicElementData::ImageFrame(image_frame) => image_frame.transform_mut(),
GraphicElementData::Text(_) => todo!("Transform of text"),
GraphicElementData::GraphicGroup(graphic_group) => graphic_group.transform_mut(),
GraphicElementData::Artboard(artboard) => artboard.graphic_group.transform_mut(),
GraphicElementData::Artboard(_) => todo!("Transform of artboard"),
}
}
}
@ -124,6 +125,15 @@ impl TransformMut for VectorData {
}
}
impl Transform for Artboard {
fn transform(&self) -> DAffine2 {
DAffine2::IDENTITY
}
fn local_pivot(&self, pivot: DVec2) -> DVec2 {
self.location.as_dvec2() + self.dimensions.as_dvec2() * pivot
}
}
impl Transform for DAffine2 {
fn transform(&self) -> DAffine2 {
*self

View file

@ -844,7 +844,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
register_node!(graphene_core::ToGraphicElementData, input: ImageFrame<Color>, params: []),
register_node!(graphene_core::ToGraphicElementData, input: GraphicGroup, params: []),
register_node!(graphene_core::ToGraphicElementData, input: Artboard, params: []),
register_node!(graphene_core::ConstructArtboardNode<_, _, _, _>, input: GraphicGroup, params: [glam::IVec2, glam::IVec2, Color, bool]),
async_node!(graphene_core::ConstructArtboardNode<_, _, _, _, _>, input: Footprint, output: Artboard, fn_params: [Footprint => GraphicGroup, () => glam::IVec2, () => glam::IVec2, () => Color, () => bool]),
];
let mut map: HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstructor>> = HashMap::new();
for (id, c, types) in node_types.into_iter().flatten() {