Instance tables refactor part 4: replace ArtboardGroups with multi-row Instances<Artboard> (#2265)

* Clean up dyn_any usages

* Migrate ArtboardGroup to ArtboardGroupTable (not yet flattened)

* Reorder graphical data imports

* Flatten and remove ArtboardGroup in favor of ArtboardGroupTable

* Fix test
This commit is contained in:
Keavon Chambers
2025-03-02 17:30:29 -08:00
parent 2f6c6e28f0
commit 19a140682e
32 changed files with 233 additions and 156 deletions

View File

@@ -49,6 +49,7 @@ impl TransformMut for SurfaceFrame {
}
}
#[cfg(feature = "dyn-any")]
unsafe impl StaticType for SurfaceFrame {
type Static = SurfaceFrame;
}
@@ -90,6 +91,7 @@ impl PartialEq for ImageTexture {
}
}
#[cfg(feature = "dyn-any")]
unsafe impl StaticType for ImageTexture {
type Static = ImageTexture;
}
@@ -128,6 +130,7 @@ impl<S: Size> Size for SurfaceHandle<S> {
}
}
#[cfg(feature = "dyn-any")]
unsafe impl<T: 'static> StaticType for SurfaceHandle<T> {
type Static = SurfaceHandle<T>;
}
@@ -138,6 +141,7 @@ pub struct SurfaceHandleFrame<Surface> {
pub transform: DAffine2,
}
#[cfg(feature = "dyn-any")]
unsafe impl<T: 'static> StaticType for SurfaceHandleFrame<T> {
type Static = SurfaceHandleFrame<T>;
}
@@ -317,6 +321,7 @@ impl<T> Debug for EditorApi<T> {
}
}
#[cfg(feature = "dyn-any")]
unsafe impl<T: StaticTypeSized> StaticType for EditorApi<T> {
type Static = EditorApi<T::Static>;
}

View File

@@ -238,6 +238,12 @@ pub struct Artboard {
pub clip: bool,
}
impl Default for Artboard {
fn default() -> Self {
Self::new(IVec2::ZERO, IVec2::new(1920, 1080))
}
}
impl Artboard {
pub fn new(location: IVec2, dimensions: IVec2) -> Self {
Self {
@@ -251,23 +257,38 @@ impl Artboard {
}
}
/// Contains multiple artboards.
#[derive(Clone, Default, Debug, Hash, PartialEq, DynAny)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ArtboardGroup {
pub artboards: Vec<(Artboard, Option<NodeId>)>,
}
// TODO: Eventually remove this migration document upgrade code
pub fn migrate_artboard_group<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<ArtboardGroupTable, D::Error> {
use serde::Deserialize;
impl ArtboardGroup {
pub fn new() -> Self {
Default::default()
#[derive(Clone, Default, Debug, Hash, PartialEq, DynAny)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ArtboardGroup {
pub artboards: Vec<(Artboard, Option<NodeId>)>,
}
fn append_artboard(&mut self, artboard: Artboard, node_id: Option<NodeId>) {
self.artboards.push((artboard, node_id));
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(untagged)]
enum EitherFormat {
ArtboardGroup(ArtboardGroup),
ArtboardGroupTable(ArtboardGroupTable),
}
Ok(match EitherFormat::deserialize(deserializer)? {
EitherFormat::ArtboardGroup(artboard_group) => {
let mut table = ArtboardGroupTable::empty();
for (artboard, source_node_id) in artboard_group.artboards {
table.push(artboard);
*table.instances_mut().last().unwrap().source_node_id = source_node_id;
}
table
}
EitherFormat::ArtboardGroupTable(artboard_group_table) => artboard_group_table,
})
}
pub type ArtboardGroupTable = Instances<Artboard>;
#[node_macro::node(category(""))]
async fn layer(_: impl Ctx, stack: GraphicGroupTable, mut element: GraphicElement, node_path: Vec<NodeId>) -> GraphicGroupTable {
let mut stack = stack;
@@ -385,15 +406,13 @@ async fn to_artboard<Data: Into<GraphicGroupTable> + 'n>(
}
#[node_macro::node(category(""))]
async fn append_artboard(_ctx: impl Ctx, mut artboards: ArtboardGroup, artboard: Artboard, node_path: Vec<NodeId>) -> ArtboardGroup {
// let mut artboards = artboards.eval(ctx.clone()).await;
// let artboard = artboard.eval(ctx).await;
// let foot = ctx.footprint();
// log::debug!("{:?}", foot);
async fn append_artboard(_ctx: impl Ctx, mut artboards: ArtboardGroupTable, artboard: Artboard, node_path: Vec<NodeId>) -> ArtboardGroupTable {
// Get the penultimate element of the node path, or None if the path is too short.
// This is used to get the ID of the user-facing "Artboard" node (which encapsulates this internal "Append Artboard" node).
let encapsulating_node_id = node_path.get(node_path.len().wrapping_sub(2)).copied();
artboards.append_artboard(artboard, encapsulating_node_id);
artboards.push(artboard);
*artboards.instances_mut().last().unwrap().source_node_id = encapsulating_node_id;
artboards
}

View File

@@ -9,7 +9,7 @@ use crate::transform::{Footprint, Transform};
use crate::uuid::{generate_uuid, NodeId};
use crate::vector::style::{Fill, Stroke, ViewMode};
use crate::vector::{PointId, VectorDataTable};
use crate::{Artboard, ArtboardGroup, Color, GraphicElement, GraphicGroupTable, RasterFrame};
use crate::{Artboard, ArtboardGroupTable, Color, GraphicElement, GraphicGroupTable, RasterFrame};
use bezier_rs::Subpath;
use dyn_any::DynAny;
@@ -790,38 +790,38 @@ impl GraphicElementRendered for Artboard {
}
}
impl GraphicElementRendered for ArtboardGroup {
impl GraphicElementRendered for ArtboardGroupTable {
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
for (artboard, _) in &self.artboards {
artboard.render_svg(render, render_params);
for artboard in self.instances() {
artboard.instance.render_svg(render, render_params);
}
}
fn bounding_box(&self, transform: DAffine2) -> Option<[DVec2; 2]> {
self.artboards.iter().filter_map(|(element, _)| element.bounding_box(transform)).reduce(Quad::combine_bounds)
self.instances().filter_map(|instance| instance.instance.bounding_box(transform)).reduce(Quad::combine_bounds)
}
fn collect_metadata(&self, metadata: &mut RenderMetadata, footprint: Footprint, _element_id: Option<NodeId>) {
for (artboard, element_id) in &self.artboards {
artboard.collect_metadata(metadata, footprint, *element_id);
for instance in self.instances() {
instance.instance.collect_metadata(metadata, footprint, *instance.source_node_id);
}
}
fn add_upstream_click_targets(&self, click_targets: &mut Vec<ClickTarget>) {
for (artboard, _) in &self.artboards {
artboard.add_upstream_click_targets(click_targets);
for instance in self.instances() {
instance.instance.add_upstream_click_targets(click_targets);
}
}
#[cfg(feature = "vello")]
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext) {
for (artboard, _) in &self.artboards {
artboard.render_to_vello(scene, transform, context)
for instance in self.instances() {
instance.instance.render_to_vello(scene, transform, context)
}
}
fn contains_artboard(&self) -> bool {
!self.artboards.is_empty()
self.instances().count() > 0
}
}

View File

@@ -2,18 +2,17 @@ use crate::application_io::{ImageTexture, TextureFrameTable};
use crate::raster::image::{Image, ImageFrameTable};
use crate::raster::Pixel;
use crate::transform::{Transform, TransformMut};
use crate::uuid::NodeId;
use crate::vector::{InstanceId, VectorData, VectorDataTable};
use crate::{AlphaBlending, GraphicElement, GraphicGroup, GraphicGroupTable, RasterFrame};
use dyn_any::StaticType;
use glam::{DAffine2, DVec2};
use std::hash::Hash;
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct Instances<T>
where
T: Into<GraphicElement> + StaticType + 'static,
{
pub struct Instances<T> {
id: Vec<InstanceId>,
#[serde(alias = "instances")]
instance: Vec<T>,
@@ -21,15 +20,44 @@ where
transform: Vec<DAffine2>,
#[serde(default = "one_alpha_blending_default")]
alpha_blending: Vec<AlphaBlending>,
#[serde(default = "one_source_node_id_default")]
source_node_id: Vec<Option<NodeId>>,
}
impl<T: Into<GraphicElement> + StaticType + 'static> Instances<T> {
impl<T> Instances<T> {
pub fn new(instance: T) -> Self {
Self {
id: vec![InstanceId::generate()],
instance: vec![instance],
transform: vec![DAffine2::IDENTITY],
alpha_blending: vec![AlphaBlending::default()],
source_node_id: vec![None],
}
}
pub fn empty() -> Self {
Self {
id: Vec::new(),
instance: Vec::new(),
transform: Vec::new(),
alpha_blending: Vec::new(),
source_node_id: Vec::new(),
}
}
pub fn push(&mut self, instance: T) -> InstanceMut<T> {
self.id.push(InstanceId::generate());
self.instance.push(instance);
self.transform.push(DAffine2::IDENTITY);
self.alpha_blending.push(AlphaBlending::default());
self.source_node_id.push(None);
InstanceMut {
id: self.id.last_mut().expect("Shouldn't be empty"),
instance: self.instance.last_mut().expect("Shouldn't be empty"),
transform: self.transform.last_mut().expect("Shouldn't be empty"),
alpha_blending: self.alpha_blending.last_mut().expect("Shouldn't be empty"),
source_node_id: self.source_node_id.last_mut().expect("Shouldn't be empty"),
}
}
@@ -39,6 +67,7 @@ impl<T: Into<GraphicElement> + StaticType + 'static> Instances<T> {
instance: self.instance.first().unwrap_or_else(|| panic!("ONE INSTANCE EXPECTED, FOUND {}", self.instance.len())),
transform: self.transform.first().unwrap_or_else(|| panic!("ONE INSTANCE EXPECTED, FOUND {}", self.instance.len())),
alpha_blending: self.alpha_blending.first().unwrap_or_else(|| panic!("ONE INSTANCE EXPECTED, FOUND {}", self.instance.len())),
source_node_id: self.source_node_id.first().unwrap_or_else(|| panic!("ONE INSTANCE EXPECTED, FOUND {}", self.instance.len())),
}
}
@@ -50,47 +79,52 @@ impl<T: Into<GraphicElement> + StaticType + 'static> Instances<T> {
instance: self.instance.first_mut().unwrap_or_else(|| panic!("ONE INSTANCE EXPECTED, FOUND {}", length)),
transform: self.transform.first_mut().unwrap_or_else(|| panic!("ONE INSTANCE EXPECTED, FOUND {}", length)),
alpha_blending: self.alpha_blending.first_mut().unwrap_or_else(|| panic!("ONE INSTANCE EXPECTED, FOUND {}", length)),
source_node_id: self.source_node_id.first_mut().unwrap_or_else(|| panic!("ONE INSTANCE EXPECTED, FOUND {}", length)),
}
}
pub fn instances(&self) -> impl Iterator<Item = Instance<T>> {
assert!(self.instance.len() == 1, "ONE INSTANCE EXPECTED, FOUND {} (instances)", self.instance.len());
// assert!(self.instance.len() == 1, "ONE INSTANCE EXPECTED, FOUND {} (instances)", self.instance.len());
self.id
.iter()
.zip(self.instance.iter())
.zip(self.transform.iter())
.zip(self.alpha_blending.iter())
.map(|(((id, instance), transform), alpha_blending)| Instance {
.zip(self.source_node_id.iter())
.map(|((((id, instance), transform), alpha_blending), source_node_id)| Instance {
id,
instance,
transform,
alpha_blending,
source_node_id,
})
}
pub fn instances_mut(&mut self) -> impl Iterator<Item = InstanceMut<T>> {
assert!(self.instance.len() == 1, "ONE INSTANCE EXPECTED, FOUND {} (instances_mut)", self.instance.len());
// assert!(self.instance.len() == 1, "ONE INSTANCE EXPECTED, FOUND {} (instances_mut)", self.instance.len());
self.id
.iter_mut()
.zip(self.instance.iter_mut())
.zip(self.transform.iter_mut())
.zip(self.alpha_blending.iter_mut())
.map(|(((id, instance), transform), alpha_blending)| InstanceMut {
.zip(self.source_node_id.iter_mut())
.map(|((((id, instance), transform), alpha_blending), source_node_id)| InstanceMut {
id,
instance,
transform,
alpha_blending,
source_node_id,
})
}
}
impl<T: Into<GraphicElement> + Default + Hash + StaticType + 'static> Default for Instances<T> {
impl<T: Default + Hash> Default for Instances<T> {
fn default() -> Self {
Self::new(T::default())
}
}
impl<T: Into<GraphicElement> + Hash + StaticType + 'static> core::hash::Hash for Instances<T> {
impl<T: Hash> core::hash::Hash for Instances<T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.id.hash(state);
for instance in &self.instance {
@@ -99,13 +133,14 @@ impl<T: Into<GraphicElement> + Hash + StaticType + 'static> core::hash::Hash for
}
}
impl<T: Into<GraphicElement> + PartialEq + StaticType + 'static> PartialEq for Instances<T> {
impl<T: PartialEq> PartialEq for Instances<T> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id && self.instance.len() == other.instance.len() && { self.instance.iter().zip(other.instance.iter()).all(|(a, b)| a == b) }
}
}
unsafe impl<T: Into<GraphicElement> + StaticType + 'static> dyn_any::StaticType for Instances<T> {
#[cfg(feature = "dyn-any")]
unsafe impl<T: StaticType + 'static> StaticType for Instances<T> {
type Static = Instances<T>;
}
@@ -115,6 +150,9 @@ fn one_daffine2_default() -> Vec<DAffine2> {
fn one_alpha_blending_default() -> Vec<AlphaBlending> {
vec![AlphaBlending::default()]
}
fn one_source_node_id_default() -> Vec<Option<NodeId>> {
vec![None]
}
#[derive(Copy, Clone, Debug)]
pub struct Instance<'a, T> {
@@ -122,6 +160,7 @@ pub struct Instance<'a, T> {
pub instance: &'a T,
pub transform: &'a DAffine2,
pub alpha_blending: &'a AlphaBlending,
pub source_node_id: &'a Option<NodeId>,
}
#[derive(Debug)]
pub struct InstanceMut<'a, T> {
@@ -129,6 +168,7 @@ pub struct InstanceMut<'a, T> {
pub instance: &'a mut T,
pub transform: &'a mut DAffine2,
pub alpha_blending: &'a mut AlphaBlending,
pub source_node_id: &'a mut Option<NodeId>,
}
// GRAPHIC ELEMENT
@@ -235,8 +275,6 @@ impl<P: Pixel> TransformMut for InstanceMut<'_, Image<P>> {
// IMAGE FRAME TABLE
impl<P: Pixel> Transform for ImageFrameTable<P>
where
P: dyn_any::StaticType,
P::Static: Pixel,
GraphicElement: From<Image<P>>,
{
fn transform(&self) -> DAffine2 {
@@ -245,8 +283,6 @@ where
}
impl<P: Pixel> TransformMut for ImageFrameTable<P>
where
P: dyn_any::StaticType,
P::Static: Pixel,
GraphicElement: From<Image<P>>,
{
fn transform_mut(&mut self) -> &mut DAffine2 {

View File

@@ -51,6 +51,8 @@ pub mod registry;
pub use context::*;
use core::any::TypeId;
use core::pin::Pin;
pub use dyn_any::{StaticTypeSized, WasmNotSend, WasmNotSync};
pub use memo::MemoHash;
pub use raster::Color;
pub use types::Cow;
@@ -148,10 +150,6 @@ impl<'i, I: 'i, O: 'i, N: Node<'i, I, Output = O> + ?Sized> Node<'i, I> for allo
}
}
use dyn_any::StaticTypeSized;
use core::pin::Pin;
#[cfg(feature = "alloc")]
impl<'i, I, O: 'i> Node<'i, I> for Pin<Box<dyn Node<'i, I, Output = O> + 'i>> {
type Output = O;
@@ -172,5 +170,3 @@ pub use crate::application_io::{SurfaceFrame, SurfaceId};
pub type WasmSurfaceHandle = application_io::SurfaceHandle<web_sys::HtmlCanvasElement>;
#[cfg(feature = "wasm")]
pub type WasmSurfaceHandleFrame = application_io::SurfaceHandleFrame<web_sys::HtmlCanvasElement>;
pub use dyn_any::{WasmNotSend, WasmNotSync};

View File

@@ -734,8 +734,6 @@ impl Adjust<Color> for GradientStops {
}
impl<P: Pixel> Adjust<P> for ImageFrameTable<P>
where
P: dyn_any::StaticType,
P::Static: Pixel,
GraphicElement: From<Image<P>>,
{
fn adjust(&mut self, map_fn: impl Fn(&P) -> P) {
@@ -1382,8 +1380,6 @@ impl MultiplyAlpha for GraphicGroupTable {
}
impl<P: Pixel> MultiplyAlpha for ImageFrameTable<P>
where
P: dyn_any::StaticType,
P::Static: Pixel,
GraphicElement: From<Image<P>>,
{
fn multiply_alpha(&mut self, factor: f64) {

View File

@@ -1,4 +1,5 @@
use dyn_any::DynAny;
use glam::{DAffine2, DVec2};
#[cfg_attr(not(target_arch = "spirv"), derive(Debug))]

View File

@@ -4,8 +4,9 @@ use crate::vector::brush_stroke::BrushStroke;
use crate::vector::brush_stroke::BrushStyle;
use crate::Color;
use core::hash::Hash;
use dyn_any::DynAny;
use core::hash::Hash;
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::Mutex;
@@ -57,7 +58,7 @@ impl BrushCacheImpl {
background = core::mem::take(&mut self.blended_image);
// Check if the first non-blended stroke is an extension of the last one.
let mut first_stroke_texture = ImageFrameTable::empty();
let mut first_stroke_texture = ImageFrameTable::one_empty_image();
let mut first_stroke_point_skip = 0;
let strokes = input[num_blended_strokes..].to_vec();
if !strokes.is_empty() && self.prev_input.len() > num_blended_strokes {

View File

@@ -176,6 +176,7 @@ pub struct ValueMapperNode<C> {
lut: Vec<C>,
}
#[cfg(feature = "dyn-any")]
unsafe impl<C: StaticTypeSized> StaticType for ValueMapperNode<C> {
type Static = ValueMapperNode<C::Static>;
}

View File

@@ -1,7 +1,9 @@
use super::discrete_srgb::float_to_srgb_u8;
use super::Color;
use crate::{instances::Instances, transform::TransformMut};
use crate::{AlphaBlending, GraphicElement};
use crate::instances::Instances;
use crate::transform::TransformMut;
use crate::AlphaBlending;
use crate::GraphicElement;
use alloc::vec::Vec;
use core::hash::{Hash, Hasher};
use dyn_any::StaticType;
@@ -68,6 +70,7 @@ impl<P: Pixel + Debug> Debug for Image<P> {
}
}
#[cfg(feature = "dyn-any")]
unsafe impl<P> StaticType for Image<P>
where
P: dyn_any::StaticTypeSized + Pixel,
@@ -235,6 +238,8 @@ pub fn migrate_image_frame<'de, D: serde::Deserializer<'de>>(deserializer: D) ->
}
}
}
#[cfg(feature = "dyn-any")]
unsafe impl<P> StaticType for ImageFrame<P>
where
P: dyn_any::StaticTypeSized + Pixel,
@@ -279,7 +284,7 @@ pub type ImageFrameTable<P> = Instances<Image<P>>;
/// Construct a 0x0 image frame table. This is useful because ImageFrameTable::default() will return a 1x1 image frame table.
impl ImageFrameTable<Color> {
pub fn empty() -> Self {
pub fn one_empty_image() -> Self {
let mut result = Self::new(Image::default());
*result.transform_mut() = DAffine2::ZERO;
result
@@ -302,8 +307,7 @@ impl<P: Debug + Copy + Pixel> Sample for Image<P> {
impl<P> Sample for ImageFrameTable<P>
where
P: Debug + Copy + Pixel + dyn_any::StaticType,
P::Static: Pixel,
P: Debug + Copy + Pixel,
GraphicElement: From<Image<P>>,
{
type Pixel = P;
@@ -323,8 +327,7 @@ where
impl<P> Bitmap for ImageFrameTable<P>
where
P: Copy + Pixel + dyn_any::StaticType,
P::Static: Pixel,
P: Copy + Pixel,
GraphicElement: From<Image<P>>,
{
type Pixel = P;
@@ -350,8 +353,7 @@ where
impl<P> BitmapMut for ImageFrameTable<P>
where
P: Copy + Pixel + dyn_any::StaticType,
P::Static: Pixel,
P: Copy + Pixel,
GraphicElement: From<Image<P>>,
{
fn get_pixel_mut(&mut self, x: u32, y: u32) -> Option<&mut Self::Pixel> {

View File

@@ -1,9 +1,10 @@
use crate::transform::Footprint;
use crate::{NodeIO, NodeIOTypes, Type};
use crate::{Node, NodeIO, NodeIOTypes, Type, WasmNotSend};
use dyn_any::DynAny;
use dyn_any::{DynAny, StaticType};
use std::collections::HashMap;
use std::marker::PhantomData;
use std::ops::Deref;
use std::pin::Pin;
use std::sync::{LazyLock, Mutex};
@@ -153,11 +154,6 @@ impl NodeContainer {
}
}
use crate::Node;
use crate::WasmNotSend;
use dyn_any::StaticType;
use std::marker::PhantomData;
/// Boxes the input and downcasts the output.
/// Wraps around a node taking Box<dyn DynAny> and returning Box<dyn DynAny>
#[derive(Clone)]
@@ -166,7 +162,11 @@ pub struct DowncastBothNode<I, O> {
_i: PhantomData<I>,
_o: PhantomData<O>,
}
impl<'input, O: 'input + StaticType + WasmNotSend, I: 'input + StaticType + WasmNotSend> Node<'input, I> for DowncastBothNode<I, O> {
impl<'input, O, I> Node<'input, I> for DowncastBothNode<I, O>
where
O: 'input + StaticType + WasmNotSend,
I: 'input + StaticType + WasmNotSend,
{
type Output = DynFuture<'input, O>;
#[inline]
fn eval(&'input self, input: I) -> Self::Output {
@@ -234,9 +234,11 @@ pub struct DynAnyNode<I, O, Node> {
_o: PhantomData<O>,
}
impl<'input, _I: 'input + StaticType + WasmNotSend, _O: 'input + StaticType + WasmNotSend, N: 'input> Node<'input, Any<'input>> for DynAnyNode<_I, _O, N>
impl<'input, _I, _O, N> Node<'input, Any<'input>> for DynAnyNode<_I, _O, N>
where
N: Node<'input, _I, Output = DynFuture<'input, _O>>,
_I: 'input + dyn_any::StaticType + WasmNotSend,
_O: 'input + dyn_any::StaticType + WasmNotSend,
N: 'input + Node<'input, _I, Output = DynFuture<'input, _O>>,
{
type Output = FutureAny<'input>;
#[inline]
@@ -275,9 +277,11 @@ where
self.node.serialize()
}
}
impl<'input, _I: 'input + StaticType, _O: 'input + StaticType, N: 'input> DynAnyNode<_I, _O, N>
impl<'input, _I, _O, N> DynAnyNode<_I, _O, N>
where
N: Node<'input, _I, Output = DynFuture<'input, _O>>,
_I: 'input + dyn_any::StaticType,
_O: 'input + dyn_any::StaticType,
N: 'input + Node<'input, _I, Output = DynFuture<'input, _O>>,
{
pub const fn new(node: N) -> Self {
Self {

View File

@@ -2,7 +2,7 @@ use crate::application_io::TextureFrameTable;
use crate::raster::bbox::AxisAlignedBbox;
use crate::raster::image::ImageFrameTable;
use crate::vector::VectorDataTable;
use crate::{Artboard, ArtboardGroup, CloneVarArgs, Color, Context, Ctx, ExtractAll, GraphicGroupTable, OwnedContextImpl};
use crate::{Artboard, ArtboardGroupTable, CloneVarArgs, Color, Context, Ctx, ExtractAll, GraphicGroupTable, OwnedContextImpl};
use glam::{DAffine2, DVec2};
@@ -132,7 +132,7 @@ impl From<()> for Footprint {
}
#[node_macro::node(category("Debug"))]
fn cull<T>(_: impl Ctx, #[implementations(VectorDataTable, GraphicGroupTable, Artboard, ImageFrameTable<Color>, ArtboardGroup)] data: T) -> T {
fn cull<T>(_: impl Ctx, #[implementations(VectorDataTable, GraphicGroupTable, Artboard, ImageFrameTable<Color>, ArtboardGroupTable)] data: T) -> T {
data
}

View File

@@ -2,7 +2,6 @@ use core::any::TypeId;
#[cfg(not(feature = "std"))]
pub use alloc::borrow::Cow;
use dyn_any::StaticType;
#[cfg(feature = "std")]
pub use std::borrow::Cow;
@@ -220,7 +219,8 @@ impl Default for Type {
}
}
unsafe impl StaticType for Type {
#[cfg(feature = "dyn-any")]
unsafe impl dyn_any::StaticType for Type {
type Static = Self;
}
@@ -269,7 +269,7 @@ impl Type {
}
impl Type {
pub fn new<T: StaticType + Sized>() -> Self {
pub fn new<T: dyn_any::StaticType + Sized>() -> Self {
Self::Concrete(TypeDescriptor {
id: Some(TypeId::of::<T::Static>()),
name: Cow::Borrowed(core::any::type_name::<T::Static>()),
@@ -278,6 +278,7 @@ impl Type {
align: core::mem::align_of::<T>(),
})
}
pub fn size(&self) -> Option<usize> {
match self {
Self::Generic(_) => None,

View File

@@ -1,6 +1,7 @@
use dyn_any::DynAny;
pub use uuid_generation::*;
use dyn_any::DynAny;
#[derive(Clone, Copy, serde::Serialize, serde::Deserialize, specta::Type)]
pub struct Uuid(
#[serde(with = "u64_string")]

View File

@@ -3,6 +3,7 @@ use crate::raster::BlendMode;
use crate::Color;
use dyn_any::DynAny;
use glam::DVec2;
use std::hash::{Hash, Hasher};

View File

@@ -5,6 +5,7 @@ use crate::renderer::format_transform_matrix;
use crate::Color;
use dyn_any::DynAny;
use glam::{DAffine2, DVec2};
use std::fmt::{self, Display, Write};

View File

@@ -670,6 +670,7 @@ async fn subpath_segment_lengths(_: impl Ctx, vector_data: VectorDataTable) -> V
#[node_macro::node(name("Spline"), category("Vector"), path(graphene_core::vector))]
async fn spline(_: impl Ctx, mut vector_data: VectorDataTable) -> VectorDataTable {
let original_transform = vector_data.transform();
let vector_data = vector_data.one_instance_mut().instance;
// Exit early if there are no points to generate splines from.
@@ -707,7 +708,9 @@ async fn spline(_: impl Ctx, mut vector_data: VectorDataTable) -> VectorDataTabl
}
vector_data.segment_domain = segment_domain;
VectorDataTable::new(vector_data.clone())
let mut result = VectorDataTable::new(vector_data.clone());
*result.transform_mut() = original_transform;
result
}
#[node_macro::node(category("Vector"), path(graphene_core::vector))]