mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-07-24 16:13:44 +00:00
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:
parent
2f6c6e28f0
commit
19a140682e
32 changed files with 233 additions and 156 deletions
|
@ -2414,7 +2414,7 @@ impl DocumentMessageHandler {
|
||||||
/// Create a network interface with a single export
|
/// Create a network interface with a single export
|
||||||
fn default_document_network_interface() -> NodeNetworkInterface {
|
fn default_document_network_interface() -> NodeNetworkInterface {
|
||||||
let mut network_interface = NodeNetworkInterface::default();
|
let mut network_interface = NodeNetworkInterface::default();
|
||||||
network_interface.add_export(TaggedValue::ArtboardGroup(graphene_core::ArtboardGroup::default()), -1, "", &[]);
|
network_interface.add_export(TaggedValue::ArtboardGroup(graphene_core::ArtboardGroupTable::default()), -1, "", &[]);
|
||||||
network_interface
|
network_interface
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,7 @@ impl<'a> ModifyInputsContext<'a> {
|
||||||
/// Creates an artboard as the primary export for the document network
|
/// Creates an artboard as the primary export for the document network
|
||||||
pub fn create_artboard(&mut self, new_id: NodeId, artboard: Artboard) -> LayerNodeIdentifier {
|
pub fn create_artboard(&mut self, new_id: NodeId, artboard: Artboard) -> LayerNodeIdentifier {
|
||||||
let artboard_node_template = resolve_document_node_type("Artboard").expect("Node").node_template_input_override([
|
let artboard_node_template = resolve_document_node_type("Artboard").expect("Node").node_template_input_override([
|
||||||
Some(NodeInput::value(TaggedValue::ArtboardGroup(graphene_std::ArtboardGroup::default()), true)),
|
Some(NodeInput::value(TaggedValue::ArtboardGroup(graphene_std::ArtboardGroupTable::default()), true)),
|
||||||
Some(NodeInput::value(TaggedValue::GraphicGroup(graphene_core::GraphicGroupTable::default()), true)),
|
Some(NodeInput::value(TaggedValue::GraphicGroup(graphene_core::GraphicGroupTable::default()), true)),
|
||||||
Some(NodeInput::value(TaggedValue::IVec2(artboard.location), false)),
|
Some(NodeInput::value(TaggedValue::IVec2(artboard.location), false)),
|
||||||
Some(NodeInput::value(TaggedValue::IVec2(artboard.dimensions), false)),
|
Some(NodeInput::value(TaggedValue::IVec2(artboard.dimensions), false)),
|
||||||
|
|
|
@ -295,7 +295,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
manual_composition: Some(concrete!(Context)),
|
manual_composition: Some(concrete!(Context)),
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
NodeInput::network(graphene_core::Type::Fn(Box::new(concrete!(Context)), Box::new(concrete!(ArtboardGroup))), 0),
|
NodeInput::network(graphene_core::Type::Fn(Box::new(concrete!(Context)), Box::new(concrete!(ArtboardGroupTable))), 0),
|
||||||
NodeInput::node(NodeId(1), 0),
|
NodeInput::node(NodeId(1), 0),
|
||||||
NodeInput::Reflection(graph_craft::document::DocumentNodeMetadata::DocumentNodePath),
|
NodeInput::Reflection(graph_craft::document::DocumentNodeMetadata::DocumentNodePath),
|
||||||
],
|
],
|
||||||
|
@ -310,7 +310,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
NodeInput::value(TaggedValue::ArtboardGroup(ArtboardGroup::default()), true),
|
NodeInput::value(TaggedValue::ArtboardGroup(ArtboardGroupTable::default()), true),
|
||||||
NodeInput::value(TaggedValue::GraphicGroup(GraphicGroupTable::default()), true),
|
NodeInput::value(TaggedValue::GraphicGroup(GraphicGroupTable::default()), true),
|
||||||
NodeInput::value(TaggedValue::IVec2(glam::IVec2::ZERO), false),
|
NodeInput::value(TaggedValue::IVec2(glam::IVec2::ZERO), false),
|
||||||
NodeInput::value(TaggedValue::IVec2(glam::IVec2::new(1920, 1080)), false),
|
NodeInput::value(TaggedValue::IVec2(glam::IVec2::new(1920, 1080)), false),
|
||||||
|
@ -544,7 +544,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
nodes: [
|
nodes: [
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
inputs: vec![NodeInput::network(concrete!(ImageFrameTable<Color>), 0)],
|
inputs: vec![NodeInput::network(concrete!(ImageFrameTable<Color>), 0)],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IntoNode<_, ImageFrame>")), // TODO: Possibly change `ImageFrame` to something else
|
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IntoNode<_, ImageFrameTable>")),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
|
@ -571,7 +571,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
.collect(),
|
.collect(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true)],
|
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true)],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||||
|
@ -809,8 +809,8 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
document_node: DocumentNode {
|
document_node: DocumentNode {
|
||||||
implementation: DocumentNodeImplementation::proto("graphene_std::raster::MaskImageNode"),
|
implementation: DocumentNodeImplementation::proto("graphene_std::raster::MaskImageNode"),
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true),
|
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true),
|
||||||
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true),
|
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true),
|
||||||
],
|
],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
@ -832,8 +832,8 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
document_node: DocumentNode {
|
document_node: DocumentNode {
|
||||||
implementation: DocumentNodeImplementation::proto("graphene_std::raster::InsertChannelNode"),
|
implementation: DocumentNodeImplementation::proto("graphene_std::raster::InsertChannelNode"),
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true),
|
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true),
|
||||||
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true),
|
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true),
|
||||||
NodeInput::value(TaggedValue::RedGreenBlue(RedGreenBlue::default()), false),
|
NodeInput::value(TaggedValue::RedGreenBlue(RedGreenBlue::default()), false),
|
||||||
],
|
],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -856,10 +856,10 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
implementation: DocumentNodeImplementation::proto("graphene_std::raster::CombineChannelsNode"),
|
implementation: DocumentNodeImplementation::proto("graphene_std::raster::CombineChannelsNode"),
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
NodeInput::value(TaggedValue::None, false),
|
NodeInput::value(TaggedValue::None, false),
|
||||||
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true),
|
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true),
|
||||||
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true),
|
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true),
|
||||||
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true),
|
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true),
|
||||||
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true),
|
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true),
|
||||||
],
|
],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
@ -929,7 +929,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true)],
|
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true)],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||||
|
@ -1011,8 +1011,8 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true),
|
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true),
|
||||||
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true),
|
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true),
|
||||||
NodeInput::value(TaggedValue::BrushStrokes(Vec::new()), false),
|
NodeInput::value(TaggedValue::BrushStrokes(Vec::new()), false),
|
||||||
NodeInput::value(TaggedValue::BrushCache(BrushCache::new_proto()), false),
|
NodeInput::value(TaggedValue::BrushCache(BrushCache::new_proto()), false),
|
||||||
],
|
],
|
||||||
|
@ -1061,7 +1061,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
node_template: NodeTemplate {
|
node_template: NodeTemplate {
|
||||||
document_node: DocumentNode {
|
document_node: DocumentNode {
|
||||||
implementation: DocumentNodeImplementation::proto("graphene_core::memo::MemoNode"),
|
implementation: DocumentNodeImplementation::proto("graphene_core::memo::MemoNode"),
|
||||||
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true)],
|
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true)],
|
||||||
manual_composition: Some(concrete!(Context)),
|
manual_composition: Some(concrete!(Context)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
@ -1080,7 +1080,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
node_template: NodeTemplate {
|
node_template: NodeTemplate {
|
||||||
document_node: DocumentNode {
|
document_node: DocumentNode {
|
||||||
implementation: DocumentNodeImplementation::proto("graphene_core::memo::ImpureMemoNode"),
|
implementation: DocumentNodeImplementation::proto("graphene_core::memo::ImpureMemoNode"),
|
||||||
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true)],
|
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true)],
|
||||||
manual_composition: Some(concrete!(Context)),
|
manual_composition: Some(concrete!(Context)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
@ -1112,7 +1112,10 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
.collect(),
|
.collect(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
inputs: vec![NodeInput::value(TaggedValue::None, false), NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), false)],
|
inputs: vec![
|
||||||
|
NodeInput::value(TaggedValue::None, false),
|
||||||
|
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), false),
|
||||||
|
],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||||
|
@ -1825,7 +1828,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
.collect(),
|
.collect(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true)],
|
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true)],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||||
|
@ -1881,7 +1884,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
document_node: DocumentNode {
|
document_node: DocumentNode {
|
||||||
implementation: DocumentNodeImplementation::proto("graphene_std::executor::MapGpuSingleImageNode"),
|
implementation: DocumentNodeImplementation::proto("graphene_std::executor::MapGpuSingleImageNode"),
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true),
|
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true),
|
||||||
NodeInput::value(TaggedValue::DocumentNode(DocumentNode::default()), true),
|
NodeInput::value(TaggedValue::DocumentNode(DocumentNode::default()), true),
|
||||||
],
|
],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -1923,7 +1926,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
document_node: DocumentNode {
|
document_node: DocumentNode {
|
||||||
implementation: DocumentNodeImplementation::proto("graphene_core::raster::BrightnessContrastNode"),
|
implementation: DocumentNodeImplementation::proto("graphene_core::raster::BrightnessContrastNode"),
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true),
|
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true),
|
||||||
NodeInput::value(TaggedValue::F64(0.), false),
|
NodeInput::value(TaggedValue::F64(0.), false),
|
||||||
NodeInput::value(TaggedValue::F64(0.), false),
|
NodeInput::value(TaggedValue::F64(0.), false),
|
||||||
NodeInput::value(TaggedValue::Bool(false), false),
|
NodeInput::value(TaggedValue::Bool(false), false),
|
||||||
|
@ -2799,7 +2802,7 @@ pub static IMAGINATE_NODE: Lazy<DocumentNodeDefinition> = Lazy::new(|| DocumentN
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true),
|
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true),
|
||||||
NodeInput::scope("editor-api"),
|
NodeInput::scope("editor-api"),
|
||||||
NodeInput::value(TaggedValue::ImaginateController(Default::default()), false),
|
NodeInput::value(TaggedValue::ImaginateController(Default::default()), false),
|
||||||
NodeInput::value(TaggedValue::F64(0.), false), // Remember to keep index used in `ImaginateRandom` updated with this entry's index
|
NodeInput::value(TaggedValue::F64(0.), false), // Remember to keep index used in `ImaginateRandom` updated with this entry's index
|
||||||
|
|
|
@ -468,8 +468,8 @@ impl NodeNetworkInterface {
|
||||||
InputConnector::Node { node_id, input_index } => (node_id, input_index),
|
InputConnector::Node { node_id, input_index } => (node_id, input_index),
|
||||||
InputConnector::Export(export_index) => {
|
InputConnector::Export(export_index) => {
|
||||||
let Some((encapsulating_node_id, encapsulating_node_id_path)) = network_path.split_last() else {
|
let Some((encapsulating_node_id, encapsulating_node_id_path)) = network_path.split_last() else {
|
||||||
// The outermost network export defaults to an ArtboardGroup.
|
// The outermost network export defaults to an ArtboardGroupTable.
|
||||||
return Some((concrete!(graphene_core::ArtboardGroup), TypeSource::OuterMostExportDefault));
|
return Some((concrete!(graphene_core::ArtboardGroupTable), TypeSource::OuterMostExportDefault));
|
||||||
};
|
};
|
||||||
|
|
||||||
let output_type = self.output_types(encapsulating_node_id, encapsulating_node_id_path).into_iter().nth(export_index).flatten();
|
let output_type = self.output_types(encapsulating_node_id, encapsulating_node_id_path).into_iter().nth(export_index).flatten();
|
||||||
|
|
|
@ -49,6 +49,7 @@ impl TransformMut for SurfaceFrame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "dyn-any")]
|
||||||
unsafe impl StaticType for SurfaceFrame {
|
unsafe impl StaticType for SurfaceFrame {
|
||||||
type Static = SurfaceFrame;
|
type Static = SurfaceFrame;
|
||||||
}
|
}
|
||||||
|
@ -90,6 +91,7 @@ impl PartialEq for ImageTexture {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "dyn-any")]
|
||||||
unsafe impl StaticType for ImageTexture {
|
unsafe impl StaticType for ImageTexture {
|
||||||
type Static = 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> {
|
unsafe impl<T: 'static> StaticType for SurfaceHandle<T> {
|
||||||
type Static = SurfaceHandle<T>;
|
type Static = SurfaceHandle<T>;
|
||||||
}
|
}
|
||||||
|
@ -138,6 +141,7 @@ pub struct SurfaceHandleFrame<Surface> {
|
||||||
pub transform: DAffine2,
|
pub transform: DAffine2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "dyn-any")]
|
||||||
unsafe impl<T: 'static> StaticType for SurfaceHandleFrame<T> {
|
unsafe impl<T: 'static> StaticType for SurfaceHandleFrame<T> {
|
||||||
type Static = 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> {
|
unsafe impl<T: StaticTypeSized> StaticType for EditorApi<T> {
|
||||||
type Static = EditorApi<T::Static>;
|
type Static = EditorApi<T::Static>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,6 +238,12 @@ pub struct Artboard {
|
||||||
pub clip: bool,
|
pub clip: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Artboard {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new(IVec2::ZERO, IVec2::new(1920, 1080))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Artboard {
|
impl Artboard {
|
||||||
pub fn new(location: IVec2, dimensions: IVec2) -> Self {
|
pub fn new(location: IVec2, dimensions: IVec2) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -251,23 +257,38 @@ impl Artboard {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Contains multiple artboards.
|
// TODO: Eventually remove this migration document upgrade code
|
||||||
#[derive(Clone, Default, Debug, Hash, PartialEq, DynAny)]
|
pub fn migrate_artboard_group<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<ArtboardGroupTable, D::Error> {
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
use serde::Deserialize;
|
||||||
pub struct ArtboardGroup {
|
|
||||||
pub artboards: Vec<(Artboard, Option<NodeId>)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ArtboardGroup {
|
#[derive(Clone, Default, Debug, Hash, PartialEq, DynAny)]
|
||||||
pub fn new() -> Self {
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
Default::default()
|
pub struct ArtboardGroup {
|
||||||
|
pub artboards: Vec<(Artboard, Option<NodeId>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append_artboard(&mut self, artboard: Artboard, node_id: Option<NodeId>) {
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
self.artboards.push((artboard, node_id));
|
#[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(""))]
|
#[node_macro::node(category(""))]
|
||||||
async fn layer(_: impl Ctx, stack: GraphicGroupTable, mut element: GraphicElement, node_path: Vec<NodeId>) -> GraphicGroupTable {
|
async fn layer(_: impl Ctx, stack: GraphicGroupTable, mut element: GraphicElement, node_path: Vec<NodeId>) -> GraphicGroupTable {
|
||||||
let mut stack = stack;
|
let mut stack = stack;
|
||||||
|
@ -385,15 +406,13 @@ async fn to_artboard<Data: Into<GraphicGroupTable> + 'n>(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node(category(""))]
|
#[node_macro::node(category(""))]
|
||||||
async fn append_artboard(_ctx: impl Ctx, mut artboards: ArtboardGroup, artboard: Artboard, node_path: Vec<NodeId>) -> ArtboardGroup {
|
async fn append_artboard(_ctx: impl Ctx, mut artboards: ArtboardGroupTable, artboard: Artboard, node_path: Vec<NodeId>) -> ArtboardGroupTable {
|
||||||
// let mut artboards = artboards.eval(ctx.clone()).await;
|
|
||||||
// let artboard = artboard.eval(ctx).await;
|
|
||||||
// let foot = ctx.footprint();
|
|
||||||
// log::debug!("{:?}", foot);
|
|
||||||
// Get the penultimate element of the node path, or None if the path is too short.
|
// 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).
|
// 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();
|
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
|
artboards
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use crate::transform::{Footprint, Transform};
|
||||||
use crate::uuid::{generate_uuid, NodeId};
|
use crate::uuid::{generate_uuid, NodeId};
|
||||||
use crate::vector::style::{Fill, Stroke, ViewMode};
|
use crate::vector::style::{Fill, Stroke, ViewMode};
|
||||||
use crate::vector::{PointId, VectorDataTable};
|
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 bezier_rs::Subpath;
|
||||||
use dyn_any::DynAny;
|
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) {
|
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
|
||||||
for (artboard, _) in &self.artboards {
|
for artboard in self.instances() {
|
||||||
artboard.render_svg(render, render_params);
|
artboard.instance.render_svg(render, render_params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bounding_box(&self, transform: DAffine2) -> Option<[DVec2; 2]> {
|
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>) {
|
fn collect_metadata(&self, metadata: &mut RenderMetadata, footprint: Footprint, _element_id: Option<NodeId>) {
|
||||||
for (artboard, element_id) in &self.artboards {
|
for instance in self.instances() {
|
||||||
artboard.collect_metadata(metadata, footprint, *element_id);
|
instance.instance.collect_metadata(metadata, footprint, *instance.source_node_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_upstream_click_targets(&self, click_targets: &mut Vec<ClickTarget>) {
|
fn add_upstream_click_targets(&self, click_targets: &mut Vec<ClickTarget>) {
|
||||||
for (artboard, _) in &self.artboards {
|
for instance in self.instances() {
|
||||||
artboard.add_upstream_click_targets(click_targets);
|
instance.instance.add_upstream_click_targets(click_targets);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "vello")]
|
#[cfg(feature = "vello")]
|
||||||
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext) {
|
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext) {
|
||||||
for (artboard, _) in &self.artboards {
|
for instance in self.instances() {
|
||||||
artboard.render_to_vello(scene, transform, context)
|
instance.instance.render_to_vello(scene, transform, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contains_artboard(&self) -> bool {
|
fn contains_artboard(&self) -> bool {
|
||||||
!self.artboards.is_empty()
|
self.instances().count() > 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,18 +2,17 @@ use crate::application_io::{ImageTexture, TextureFrameTable};
|
||||||
use crate::raster::image::{Image, ImageFrameTable};
|
use crate::raster::image::{Image, ImageFrameTable};
|
||||||
use crate::raster::Pixel;
|
use crate::raster::Pixel;
|
||||||
use crate::transform::{Transform, TransformMut};
|
use crate::transform::{Transform, TransformMut};
|
||||||
|
use crate::uuid::NodeId;
|
||||||
use crate::vector::{InstanceId, VectorData, VectorDataTable};
|
use crate::vector::{InstanceId, VectorData, VectorDataTable};
|
||||||
use crate::{AlphaBlending, GraphicElement, GraphicGroup, GraphicGroupTable, RasterFrame};
|
use crate::{AlphaBlending, GraphicElement, GraphicGroup, GraphicGroupTable, RasterFrame};
|
||||||
|
|
||||||
use dyn_any::StaticType;
|
use dyn_any::StaticType;
|
||||||
|
|
||||||
use glam::{DAffine2, DVec2};
|
use glam::{DAffine2, DVec2};
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
|
||||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct Instances<T>
|
pub struct Instances<T> {
|
||||||
where
|
|
||||||
T: Into<GraphicElement> + StaticType + 'static,
|
|
||||||
{
|
|
||||||
id: Vec<InstanceId>,
|
id: Vec<InstanceId>,
|
||||||
#[serde(alias = "instances")]
|
#[serde(alias = "instances")]
|
||||||
instance: Vec<T>,
|
instance: Vec<T>,
|
||||||
|
@ -21,15 +20,44 @@ where
|
||||||
transform: Vec<DAffine2>,
|
transform: Vec<DAffine2>,
|
||||||
#[serde(default = "one_alpha_blending_default")]
|
#[serde(default = "one_alpha_blending_default")]
|
||||||
alpha_blending: Vec<AlphaBlending>,
|
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 {
|
pub fn new(instance: T) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: vec![InstanceId::generate()],
|
id: vec![InstanceId::generate()],
|
||||||
instance: vec![instance],
|
instance: vec![instance],
|
||||||
transform: vec![DAffine2::IDENTITY],
|
transform: vec![DAffine2::IDENTITY],
|
||||||
alpha_blending: vec![AlphaBlending::default()],
|
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())),
|
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())),
|
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())),
|
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)),
|
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)),
|
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)),
|
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>> {
|
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
|
self.id
|
||||||
.iter()
|
.iter()
|
||||||
.zip(self.instance.iter())
|
.zip(self.instance.iter())
|
||||||
.zip(self.transform.iter())
|
.zip(self.transform.iter())
|
||||||
.zip(self.alpha_blending.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,
|
id,
|
||||||
instance,
|
instance,
|
||||||
transform,
|
transform,
|
||||||
alpha_blending,
|
alpha_blending,
|
||||||
|
source_node_id,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn instances_mut(&mut self) -> impl Iterator<Item = InstanceMut<T>> {
|
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
|
self.id
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.zip(self.instance.iter_mut())
|
.zip(self.instance.iter_mut())
|
||||||
.zip(self.transform.iter_mut())
|
.zip(self.transform.iter_mut())
|
||||||
.zip(self.alpha_blending.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,
|
id,
|
||||||
instance,
|
instance,
|
||||||
transform,
|
transform,
|
||||||
alpha_blending,
|
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 {
|
fn default() -> Self {
|
||||||
Self::new(T::default())
|
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) {
|
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||||
self.id.hash(state);
|
self.id.hash(state);
|
||||||
for instance in &self.instance {
|
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 {
|
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) }
|
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>;
|
type Static = Instances<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,6 +150,9 @@ fn one_daffine2_default() -> Vec<DAffine2> {
|
||||||
fn one_alpha_blending_default() -> Vec<AlphaBlending> {
|
fn one_alpha_blending_default() -> Vec<AlphaBlending> {
|
||||||
vec![AlphaBlending::default()]
|
vec![AlphaBlending::default()]
|
||||||
}
|
}
|
||||||
|
fn one_source_node_id_default() -> Vec<Option<NodeId>> {
|
||||||
|
vec![None]
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct Instance<'a, T> {
|
pub struct Instance<'a, T> {
|
||||||
|
@ -122,6 +160,7 @@ pub struct Instance<'a, T> {
|
||||||
pub instance: &'a T,
|
pub instance: &'a T,
|
||||||
pub transform: &'a DAffine2,
|
pub transform: &'a DAffine2,
|
||||||
pub alpha_blending: &'a AlphaBlending,
|
pub alpha_blending: &'a AlphaBlending,
|
||||||
|
pub source_node_id: &'a Option<NodeId>,
|
||||||
}
|
}
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InstanceMut<'a, T> {
|
pub struct InstanceMut<'a, T> {
|
||||||
|
@ -129,6 +168,7 @@ pub struct InstanceMut<'a, T> {
|
||||||
pub instance: &'a mut T,
|
pub instance: &'a mut T,
|
||||||
pub transform: &'a mut DAffine2,
|
pub transform: &'a mut DAffine2,
|
||||||
pub alpha_blending: &'a mut AlphaBlending,
|
pub alpha_blending: &'a mut AlphaBlending,
|
||||||
|
pub source_node_id: &'a mut Option<NodeId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// GRAPHIC ELEMENT
|
// GRAPHIC ELEMENT
|
||||||
|
@ -235,8 +275,6 @@ impl<P: Pixel> TransformMut for InstanceMut<'_, Image<P>> {
|
||||||
// IMAGE FRAME TABLE
|
// IMAGE FRAME TABLE
|
||||||
impl<P: Pixel> Transform for ImageFrameTable<P>
|
impl<P: Pixel> Transform for ImageFrameTable<P>
|
||||||
where
|
where
|
||||||
P: dyn_any::StaticType,
|
|
||||||
P::Static: Pixel,
|
|
||||||
GraphicElement: From<Image<P>>,
|
GraphicElement: From<Image<P>>,
|
||||||
{
|
{
|
||||||
fn transform(&self) -> DAffine2 {
|
fn transform(&self) -> DAffine2 {
|
||||||
|
@ -245,8 +283,6 @@ where
|
||||||
}
|
}
|
||||||
impl<P: Pixel> TransformMut for ImageFrameTable<P>
|
impl<P: Pixel> TransformMut for ImageFrameTable<P>
|
||||||
where
|
where
|
||||||
P: dyn_any::StaticType,
|
|
||||||
P::Static: Pixel,
|
|
||||||
GraphicElement: From<Image<P>>,
|
GraphicElement: From<Image<P>>,
|
||||||
{
|
{
|
||||||
fn transform_mut(&mut self) -> &mut DAffine2 {
|
fn transform_mut(&mut self) -> &mut DAffine2 {
|
||||||
|
|
|
@ -51,6 +51,8 @@ pub mod registry;
|
||||||
|
|
||||||
pub use context::*;
|
pub use context::*;
|
||||||
use core::any::TypeId;
|
use core::any::TypeId;
|
||||||
|
use core::pin::Pin;
|
||||||
|
pub use dyn_any::{StaticTypeSized, WasmNotSend, WasmNotSync};
|
||||||
pub use memo::MemoHash;
|
pub use memo::MemoHash;
|
||||||
pub use raster::Color;
|
pub use raster::Color;
|
||||||
pub use types::Cow;
|
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")]
|
#[cfg(feature = "alloc")]
|
||||||
impl<'i, I, O: 'i> Node<'i, I> for Pin<Box<dyn Node<'i, I, Output = O> + 'i>> {
|
impl<'i, I, O: 'i> Node<'i, I> for Pin<Box<dyn Node<'i, I, Output = O> + 'i>> {
|
||||||
type Output = O;
|
type Output = O;
|
||||||
|
@ -172,5 +170,3 @@ pub use crate::application_io::{SurfaceFrame, SurfaceId};
|
||||||
pub type WasmSurfaceHandle = application_io::SurfaceHandle<web_sys::HtmlCanvasElement>;
|
pub type WasmSurfaceHandle = application_io::SurfaceHandle<web_sys::HtmlCanvasElement>;
|
||||||
#[cfg(feature = "wasm")]
|
#[cfg(feature = "wasm")]
|
||||||
pub type WasmSurfaceHandleFrame = application_io::SurfaceHandleFrame<web_sys::HtmlCanvasElement>;
|
pub type WasmSurfaceHandleFrame = application_io::SurfaceHandleFrame<web_sys::HtmlCanvasElement>;
|
||||||
|
|
||||||
pub use dyn_any::{WasmNotSend, WasmNotSync};
|
|
||||||
|
|
|
@ -734,8 +734,6 @@ impl Adjust<Color> for GradientStops {
|
||||||
}
|
}
|
||||||
impl<P: Pixel> Adjust<P> for ImageFrameTable<P>
|
impl<P: Pixel> Adjust<P> for ImageFrameTable<P>
|
||||||
where
|
where
|
||||||
P: dyn_any::StaticType,
|
|
||||||
P::Static: Pixel,
|
|
||||||
GraphicElement: From<Image<P>>,
|
GraphicElement: From<Image<P>>,
|
||||||
{
|
{
|
||||||
fn adjust(&mut self, map_fn: impl Fn(&P) -> 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>
|
impl<P: Pixel> MultiplyAlpha for ImageFrameTable<P>
|
||||||
where
|
where
|
||||||
P: dyn_any::StaticType,
|
|
||||||
P::Static: Pixel,
|
|
||||||
GraphicElement: From<Image<P>>,
|
GraphicElement: From<Image<P>>,
|
||||||
{
|
{
|
||||||
fn multiply_alpha(&mut self, factor: f64) {
|
fn multiply_alpha(&mut self, factor: f64) {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use dyn_any::DynAny;
|
use dyn_any::DynAny;
|
||||||
|
|
||||||
use glam::{DAffine2, DVec2};
|
use glam::{DAffine2, DVec2};
|
||||||
|
|
||||||
#[cfg_attr(not(target_arch = "spirv"), derive(Debug))]
|
#[cfg_attr(not(target_arch = "spirv"), derive(Debug))]
|
||||||
|
|
|
@ -4,8 +4,9 @@ use crate::vector::brush_stroke::BrushStroke;
|
||||||
use crate::vector::brush_stroke::BrushStyle;
|
use crate::vector::brush_stroke::BrushStyle;
|
||||||
use crate::Color;
|
use crate::Color;
|
||||||
|
|
||||||
use core::hash::Hash;
|
|
||||||
use dyn_any::DynAny;
|
use dyn_any::DynAny;
|
||||||
|
|
||||||
|
use core::hash::Hash;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
@ -57,7 +58,7 @@ impl BrushCacheImpl {
|
||||||
background = core::mem::take(&mut self.blended_image);
|
background = core::mem::take(&mut self.blended_image);
|
||||||
|
|
||||||
// Check if the first non-blended stroke is an extension of the last one.
|
// 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 mut first_stroke_point_skip = 0;
|
||||||
let strokes = input[num_blended_strokes..].to_vec();
|
let strokes = input[num_blended_strokes..].to_vec();
|
||||||
if !strokes.is_empty() && self.prev_input.len() > num_blended_strokes {
|
if !strokes.is_empty() && self.prev_input.len() > num_blended_strokes {
|
||||||
|
|
|
@ -176,6 +176,7 @@ pub struct ValueMapperNode<C> {
|
||||||
lut: Vec<C>,
|
lut: Vec<C>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "dyn-any")]
|
||||||
unsafe impl<C: StaticTypeSized> StaticType for ValueMapperNode<C> {
|
unsafe impl<C: StaticTypeSized> StaticType for ValueMapperNode<C> {
|
||||||
type Static = ValueMapperNode<C::Static>;
|
type Static = ValueMapperNode<C::Static>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
use super::discrete_srgb::float_to_srgb_u8;
|
use super::discrete_srgb::float_to_srgb_u8;
|
||||||
use super::Color;
|
use super::Color;
|
||||||
use crate::{instances::Instances, transform::TransformMut};
|
use crate::instances::Instances;
|
||||||
use crate::{AlphaBlending, GraphicElement};
|
use crate::transform::TransformMut;
|
||||||
|
use crate::AlphaBlending;
|
||||||
|
use crate::GraphicElement;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::hash::{Hash, Hasher};
|
use core::hash::{Hash, Hasher};
|
||||||
use dyn_any::StaticType;
|
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>
|
unsafe impl<P> StaticType for Image<P>
|
||||||
where
|
where
|
||||||
P: dyn_any::StaticTypeSized + Pixel,
|
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>
|
unsafe impl<P> StaticType for ImageFrame<P>
|
||||||
where
|
where
|
||||||
P: dyn_any::StaticTypeSized + Pixel,
|
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.
|
/// Construct a 0x0 image frame table. This is useful because ImageFrameTable::default() will return a 1x1 image frame table.
|
||||||
impl ImageFrameTable<Color> {
|
impl ImageFrameTable<Color> {
|
||||||
pub fn empty() -> Self {
|
pub fn one_empty_image() -> Self {
|
||||||
let mut result = Self::new(Image::default());
|
let mut result = Self::new(Image::default());
|
||||||
*result.transform_mut() = DAffine2::ZERO;
|
*result.transform_mut() = DAffine2::ZERO;
|
||||||
result
|
result
|
||||||
|
@ -302,8 +307,7 @@ impl<P: Debug + Copy + Pixel> Sample for Image<P> {
|
||||||
|
|
||||||
impl<P> Sample for ImageFrameTable<P>
|
impl<P> Sample for ImageFrameTable<P>
|
||||||
where
|
where
|
||||||
P: Debug + Copy + Pixel + dyn_any::StaticType,
|
P: Debug + Copy + Pixel,
|
||||||
P::Static: Pixel,
|
|
||||||
GraphicElement: From<Image<P>>,
|
GraphicElement: From<Image<P>>,
|
||||||
{
|
{
|
||||||
type Pixel = P;
|
type Pixel = P;
|
||||||
|
@ -323,8 +327,7 @@ where
|
||||||
|
|
||||||
impl<P> Bitmap for ImageFrameTable<P>
|
impl<P> Bitmap for ImageFrameTable<P>
|
||||||
where
|
where
|
||||||
P: Copy + Pixel + dyn_any::StaticType,
|
P: Copy + Pixel,
|
||||||
P::Static: Pixel,
|
|
||||||
GraphicElement: From<Image<P>>,
|
GraphicElement: From<Image<P>>,
|
||||||
{
|
{
|
||||||
type Pixel = P;
|
type Pixel = P;
|
||||||
|
@ -350,8 +353,7 @@ where
|
||||||
|
|
||||||
impl<P> BitmapMut for ImageFrameTable<P>
|
impl<P> BitmapMut for ImageFrameTable<P>
|
||||||
where
|
where
|
||||||
P: Copy + Pixel + dyn_any::StaticType,
|
P: Copy + Pixel,
|
||||||
P::Static: Pixel,
|
|
||||||
GraphicElement: From<Image<P>>,
|
GraphicElement: From<Image<P>>,
|
||||||
{
|
{
|
||||||
fn get_pixel_mut(&mut self, x: u32, y: u32) -> Option<&mut Self::Pixel> {
|
fn get_pixel_mut(&mut self, x: u32, y: u32) -> Option<&mut Self::Pixel> {
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::transform::Footprint;
|
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::collections::HashMap;
|
||||||
|
use std::marker::PhantomData;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::{LazyLock, Mutex};
|
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.
|
/// Boxes the input and downcasts the output.
|
||||||
/// Wraps around a node taking Box<dyn DynAny> and returning Box<dyn DynAny>
|
/// Wraps around a node taking Box<dyn DynAny> and returning Box<dyn DynAny>
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -166,7 +162,11 @@ pub struct DowncastBothNode<I, O> {
|
||||||
_i: PhantomData<I>,
|
_i: PhantomData<I>,
|
||||||
_o: PhantomData<O>,
|
_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>;
|
type Output = DynFuture<'input, O>;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eval(&'input self, input: I) -> Self::Output {
|
fn eval(&'input self, input: I) -> Self::Output {
|
||||||
|
@ -234,9 +234,11 @@ pub struct DynAnyNode<I, O, Node> {
|
||||||
_o: PhantomData<O>,
|
_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
|
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>;
|
type Output = FutureAny<'input>;
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -275,9 +277,11 @@ where
|
||||||
self.node.serialize()
|
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
|
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 {
|
pub const fn new(node: N) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::application_io::TextureFrameTable;
|
||||||
use crate::raster::bbox::AxisAlignedBbox;
|
use crate::raster::bbox::AxisAlignedBbox;
|
||||||
use crate::raster::image::ImageFrameTable;
|
use crate::raster::image::ImageFrameTable;
|
||||||
use crate::vector::VectorDataTable;
|
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};
|
use glam::{DAffine2, DVec2};
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ impl From<()> for Footprint {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node(category("Debug"))]
|
#[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
|
data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ use core::any::TypeId;
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
pub use alloc::borrow::Cow;
|
pub use alloc::borrow::Cow;
|
||||||
use dyn_any::StaticType;
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use std::borrow::Cow;
|
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;
|
type Static = Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,7 +269,7 @@ impl Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Type {
|
impl Type {
|
||||||
pub fn new<T: StaticType + Sized>() -> Self {
|
pub fn new<T: dyn_any::StaticType + Sized>() -> Self {
|
||||||
Self::Concrete(TypeDescriptor {
|
Self::Concrete(TypeDescriptor {
|
||||||
id: Some(TypeId::of::<T::Static>()),
|
id: Some(TypeId::of::<T::Static>()),
|
||||||
name: Cow::Borrowed(core::any::type_name::<T::Static>()),
|
name: Cow::Borrowed(core::any::type_name::<T::Static>()),
|
||||||
|
@ -278,6 +278,7 @@ impl Type {
|
||||||
align: core::mem::align_of::<T>(),
|
align: core::mem::align_of::<T>(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size(&self) -> Option<usize> {
|
pub fn size(&self) -> Option<usize> {
|
||||||
match self {
|
match self {
|
||||||
Self::Generic(_) => None,
|
Self::Generic(_) => None,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use dyn_any::DynAny;
|
|
||||||
pub use uuid_generation::*;
|
pub use uuid_generation::*;
|
||||||
|
|
||||||
|
use dyn_any::DynAny;
|
||||||
|
|
||||||
#[derive(Clone, Copy, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(Clone, Copy, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
pub struct Uuid(
|
pub struct Uuid(
|
||||||
#[serde(with = "u64_string")]
|
#[serde(with = "u64_string")]
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::raster::BlendMode;
|
||||||
use crate::Color;
|
use crate::Color;
|
||||||
|
|
||||||
use dyn_any::DynAny;
|
use dyn_any::DynAny;
|
||||||
|
|
||||||
use glam::DVec2;
|
use glam::DVec2;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ use crate::renderer::format_transform_matrix;
|
||||||
use crate::Color;
|
use crate::Color;
|
||||||
|
|
||||||
use dyn_any::DynAny;
|
use dyn_any::DynAny;
|
||||||
|
|
||||||
use glam::{DAffine2, DVec2};
|
use glam::{DAffine2, DVec2};
|
||||||
use std::fmt::{self, Display, Write};
|
use std::fmt::{self, Display, Write};
|
||||||
|
|
||||||
|
|
|
@ -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))]
|
#[node_macro::node(name("Spline"), category("Vector"), path(graphene_core::vector))]
|
||||||
async fn spline(_: impl Ctx, mut vector_data: VectorDataTable) -> VectorDataTable {
|
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;
|
let vector_data = vector_data.one_instance_mut().instance;
|
||||||
|
|
||||||
// Exit early if there are no points to generate splines from.
|
// 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;
|
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))]
|
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use dyn_any::{StaticType, StaticTypeSized};
|
|
||||||
use graphene_core::raster::{color::RGBA16F, Image, Pixel, SRGBA8};
|
use graphene_core::raster::{color::RGBA16F, Image, Pixel, SRGBA8};
|
||||||
use graphene_core::*;
|
use graphene_core::*;
|
||||||
|
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
|
use dyn_any::{StaticType, StaticTypeSized};
|
||||||
use glam::UVec3;
|
use glam::UVec3;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
|
|
@ -115,6 +115,19 @@ macro_rules! tagged_value {
|
||||||
}
|
}
|
||||||
|
|
||||||
tagged_value! {
|
tagged_value! {
|
||||||
|
// TODO: Eventually remove this migration document upgrade code
|
||||||
|
#[cfg_attr(feature = "serde", serde(deserialize_with = "graphene_core::raster::image::migrate_image_frame"))]
|
||||||
|
ImageFrame(graphene_core::raster::image::ImageFrameTable<Color>),
|
||||||
|
// TODO: Eventually remove this migration document upgrade code
|
||||||
|
#[cfg_attr(feature = "serde", serde(deserialize_with = "graphene_core::vector::migrate_vector_data"))]
|
||||||
|
VectorData(graphene_core::vector::VectorDataTable),
|
||||||
|
// TODO: Eventually remove this migration document upgrade code
|
||||||
|
#[cfg_attr(feature = "serde", serde(deserialize_with = "graphene_core::migrate_graphic_group"))]
|
||||||
|
GraphicGroup(graphene_core::GraphicGroupTable),
|
||||||
|
// TODO: Eventually remove this migration document upgrade code
|
||||||
|
#[cfg_attr(feature = "serde", serde(deserialize_with = "graphene_core::migrate_artboard_group"))]
|
||||||
|
ArtboardGroup(graphene_core::ArtboardGroupTable),
|
||||||
|
GraphicElement(graphene_core::GraphicElement),
|
||||||
String(String),
|
String(String),
|
||||||
U32(u32),
|
U32(u32),
|
||||||
U64(u64),
|
U64(u64),
|
||||||
|
@ -130,19 +143,14 @@ tagged_value! {
|
||||||
DAffine2(DAffine2),
|
DAffine2(DAffine2),
|
||||||
Image(graphene_core::raster::Image<Color>),
|
Image(graphene_core::raster::Image<Color>),
|
||||||
ImaginateCache(ImaginateCache),
|
ImaginateCache(ImaginateCache),
|
||||||
// TODO: Eventually remove this migration document upgrade code
|
|
||||||
#[cfg_attr(feature = "serde", serde(deserialize_with = "graphene_core::raster::image::migrate_image_frame"))]
|
|
||||||
ImageFrame(graphene_core::raster::image::ImageFrameTable<Color>),
|
|
||||||
Color(graphene_core::raster::color::Color),
|
Color(graphene_core::raster::color::Color),
|
||||||
|
OptionalColor(Option<graphene_core::raster::color::Color>),
|
||||||
Subpaths(Vec<bezier_rs::Subpath<graphene_core::vector::PointId>>),
|
Subpaths(Vec<bezier_rs::Subpath<graphene_core::vector::PointId>>),
|
||||||
BlendMode(BlendMode),
|
BlendMode(BlendMode),
|
||||||
LuminanceCalculation(LuminanceCalculation),
|
LuminanceCalculation(LuminanceCalculation),
|
||||||
ImaginateSamplingMethod(ImaginateSamplingMethod),
|
ImaginateSamplingMethod(ImaginateSamplingMethod),
|
||||||
ImaginateMaskStartingFill(ImaginateMaskStartingFill),
|
ImaginateMaskStartingFill(ImaginateMaskStartingFill),
|
||||||
ImaginateController(ImaginateController),
|
ImaginateController(ImaginateController),
|
||||||
// TODO: Eventually remove this migration document upgrade code
|
|
||||||
#[cfg_attr(feature = "serde", serde(deserialize_with = "graphene_core::vector::migrate_vector_data"))]
|
|
||||||
VectorData(graphene_core::vector::VectorDataTable),
|
|
||||||
Fill(graphene_core::vector::style::Fill),
|
Fill(graphene_core::vector::style::Fill),
|
||||||
Stroke(graphene_core::vector::style::Stroke),
|
Stroke(graphene_core::vector::style::Stroke),
|
||||||
F64Array4([f64; 4]),
|
F64Array4([f64; 4]),
|
||||||
|
@ -170,7 +178,6 @@ tagged_value! {
|
||||||
// TODO: Eventually remove this alias document upgrade code
|
// TODO: Eventually remove this alias document upgrade code
|
||||||
#[cfg_attr(feature = "serde", serde(alias = "GradientPositions"))]
|
#[cfg_attr(feature = "serde", serde(alias = "GradientPositions"))]
|
||||||
GradientStops(graphene_core::vector::style::GradientStops),
|
GradientStops(graphene_core::vector::style::GradientStops),
|
||||||
OptionalColor(Option<graphene_core::raster::color::Color>),
|
|
||||||
// TODO: Eventually remove this alias document upgrade code
|
// TODO: Eventually remove this alias document upgrade code
|
||||||
#[cfg_attr(feature = "serde", serde(alias = "ManipulatorGroupIds"))]
|
#[cfg_attr(feature = "serde", serde(alias = "ManipulatorGroupIds"))]
|
||||||
PointIds(Vec<graphene_core::vector::PointId>),
|
PointIds(Vec<graphene_core::vector::PointId>),
|
||||||
|
@ -178,11 +185,6 @@ tagged_value! {
|
||||||
BrushStrokes(Vec<graphene_core::vector::brush_stroke::BrushStroke>),
|
BrushStrokes(Vec<graphene_core::vector::brush_stroke::BrushStroke>),
|
||||||
BrushCache(BrushCache),
|
BrushCache(BrushCache),
|
||||||
DocumentNode(DocumentNode),
|
DocumentNode(DocumentNode),
|
||||||
// TODO: Eventually remove this migration document upgrade code
|
|
||||||
#[cfg_attr(feature = "serde", serde(deserialize_with = "graphene_core::migrate_graphic_group"))]
|
|
||||||
GraphicGroup(graphene_core::GraphicGroupTable),
|
|
||||||
GraphicElement(graphene_core::GraphicElement),
|
|
||||||
ArtboardGroup(graphene_core::ArtboardGroup),
|
|
||||||
Curve(graphene_core::raster::curve::Curve),
|
Curve(graphene_core::raster::curve::Curve),
|
||||||
Footprint(graphene_core::transform::Footprint),
|
Footprint(graphene_core::transform::Footprint),
|
||||||
Palette(Vec<Color>),
|
Palette(Vec<Color>),
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
use dyn_any::DynAny;
|
use dyn_any::DynAny;
|
||||||
use graphene_core::Color;
|
use graphene_core::Color;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::sync::{
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
atomic::{AtomicBool, Ordering},
|
use std::sync::{Arc, Mutex};
|
||||||
Arc, Mutex,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, DynAny, specta::Type)]
|
#[derive(Default, Debug, Clone, DynAny, specta::Type)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
|
|
@ -923,12 +923,12 @@ mod test {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ids,
|
ids,
|
||||||
vec![
|
vec![
|
||||||
NodeId(12083027370457564588),
|
NodeId(907133870432995942),
|
||||||
NodeId(10127202135369428481),
|
NodeId(13049623730817360317),
|
||||||
NodeId(3781642984881236270),
|
NodeId(2177355904460308500),
|
||||||
NodeId(12160249450476233602),
|
NodeId(17479234042764485524),
|
||||||
NodeId(17962581471057044127),
|
NodeId(10988236038173832469),
|
||||||
NodeId(7906594012485169109)
|
NodeId(11097818235165626738),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use dyn_any::StaticType;
|
|
||||||
use graphene_core::application_io::SurfaceHandleFrame;
|
use graphene_core::application_io::SurfaceHandleFrame;
|
||||||
use graphene_core::application_io::{ApplicationError, ApplicationIo, ResourceFuture, SurfaceHandle, SurfaceId};
|
use graphene_core::application_io::{ApplicationError, ApplicationIo, ResourceFuture, SurfaceHandle, SurfaceId};
|
||||||
use wgpu_executor::WgpuExecutor;
|
use wgpu_executor::WgpuExecutor;
|
||||||
|
|
||||||
|
use dyn_any::StaticType;
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use js_sys::{Object, Reflect};
|
use js_sys::{Object, Reflect};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
|
use dyn_any::StaticType;
|
||||||
pub use graph_craft::proto::{Any, NodeContainer, TypeErasedBox, TypeErasedNode};
|
pub use graph_craft::proto::{Any, NodeContainer, TypeErasedBox, TypeErasedNode};
|
||||||
use graph_craft::proto::{DynFuture, FutureAny, SharedNodeContainer};
|
use graph_craft::proto::{DynFuture, FutureAny, SharedNodeContainer};
|
||||||
|
pub use graphene_core::registry::{DowncastBothNode, DynAnyNode, FutureWrapperNode, PanicNode};
|
||||||
use graphene_core::NodeIO;
|
use graphene_core::NodeIO;
|
||||||
use graphene_core::WasmNotSend;
|
use graphene_core::WasmNotSend;
|
||||||
pub use graphene_core::{generic, ops, Node};
|
pub use graphene_core::{generic, ops, Node};
|
||||||
|
|
||||||
use dyn_any::StaticType;
|
|
||||||
|
|
||||||
pub use graphene_core::registry::{DowncastBothNode, DynAnyNode, FutureWrapperNode, PanicNode};
|
|
||||||
|
|
||||||
pub trait IntoTypeErasedNode<'n> {
|
pub trait IntoTypeErasedNode<'n> {
|
||||||
fn into_type_erased(self) -> TypeErasedBox<'n>;
|
fn into_type_erased(self) -> TypeErasedBox<'n>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,8 +90,7 @@ fn brush_stamp_generator(diameter: f64, color: Color, hardness: f64, flow: f64)
|
||||||
#[node_macro::node(skip_impl)]
|
#[node_macro::node(skip_impl)]
|
||||||
fn blit<P, BlendFn>(mut target: ImageFrameTable<P>, texture: Image<P>, positions: Vec<DVec2>, blend_mode: BlendFn) -> ImageFrameTable<P>
|
fn blit<P, BlendFn>(mut target: ImageFrameTable<P>, texture: Image<P>, positions: Vec<DVec2>, blend_mode: BlendFn) -> ImageFrameTable<P>
|
||||||
where
|
where
|
||||||
P: Pixel + Alpha + std::fmt::Debug + dyn_any::StaticType,
|
P: Pixel + Alpha + std::fmt::Debug,
|
||||||
P::Static: Pixel,
|
|
||||||
BlendFn: for<'any_input> Node<'any_input, (P, P), Output = P>,
|
BlendFn: for<'any_input> Node<'any_input, (P, P), Output = P>,
|
||||||
GraphicElement: From<Image<P>>,
|
GraphicElement: From<Image<P>>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,8 +14,7 @@ use wgpu_executor::{Bindgroup, PipelineLayout, Shader, ShaderIO, ShaderInput, Wg
|
||||||
use glam::{DAffine2, DVec2, Mat2, Vec2};
|
use glam::{DAffine2, DVec2, Mat2, Vec2};
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc, Mutex};
|
||||||
use std::sync::Mutex;
|
|
||||||
|
|
||||||
use crate::wasm_application_io::WasmApplicationIo;
|
use crate::wasm_application_io::WasmApplicationIo;
|
||||||
|
|
||||||
|
@ -81,7 +80,7 @@ async fn map_gpu<'a: 'input>(image: ImageFrameTable<Color>, node: DocumentNode,
|
||||||
let name = "placeholder".to_string();
|
let name = "placeholder".to_string();
|
||||||
let Ok(compute_pass_descriptor) = create_compute_pass_descriptor(node, image_frame_table, executor).await else {
|
let Ok(compute_pass_descriptor) = create_compute_pass_descriptor(node, image_frame_table, executor).await else {
|
||||||
log::error!("Error creating compute pass descriptor in 'map_gpu()");
|
log::error!("Error creating compute pass descriptor in 'map_gpu()");
|
||||||
return ImageFrameTable::empty();
|
return ImageFrameTable::one_empty_image();
|
||||||
};
|
};
|
||||||
self.cache.lock().as_mut().unwrap().insert(name, compute_pass_descriptor.clone());
|
self.cache.lock().as_mut().unwrap().insert(name, compute_pass_descriptor.clone());
|
||||||
log::error!("created compute pass");
|
log::error!("created compute pass");
|
||||||
|
@ -338,7 +337,7 @@ async fn blend_gpu_image(_: impl Ctx, foreground: ImageFrameTable<Color>, backgr
|
||||||
let proto_networks: Result<Vec<_>, _> = compiler.compile(network.clone()).collect();
|
let proto_networks: Result<Vec<_>, _> = compiler.compile(network.clone()).collect();
|
||||||
let Ok(proto_networks_result) = proto_networks else {
|
let Ok(proto_networks_result) = proto_networks else {
|
||||||
log::error!("Error compiling network in 'blend_gpu_image()");
|
log::error!("Error compiling network in 'blend_gpu_image()");
|
||||||
return ImageFrameTable::empty();
|
return ImageFrameTable::one_empty_image();
|
||||||
};
|
};
|
||||||
let proto_networks = proto_networks_result;
|
let proto_networks = proto_networks_result;
|
||||||
log::debug!("compiling shader");
|
log::debug!("compiling shader");
|
||||||
|
|
|
@ -47,7 +47,7 @@ fn sample_image(ctx: impl ExtractFootprint + Clone + Send, image_frame: ImageFra
|
||||||
|
|
||||||
// If the image would not be visible, return an empty image
|
// If the image would not be visible, return an empty image
|
||||||
if size.x <= 0. || size.y <= 0. {
|
if size.x <= 0. || size.y <= 0. {
|
||||||
return ImageFrameTable::empty();
|
return ImageFrameTable::one_empty_image();
|
||||||
}
|
}
|
||||||
|
|
||||||
let image_buffer = image::Rgba32FImage::from_raw(image.width, image.height, data).expect("Failed to convert internal image format into image-rs data type.");
|
let image_buffer = image::Rgba32FImage::from_raw(image.width, image.height, data).expect("Failed to convert internal image format into image-rs data type.");
|
||||||
|
@ -257,8 +257,7 @@ fn mask_image<
|
||||||
#[node_macro::node(skip_impl)]
|
#[node_macro::node(skip_impl)]
|
||||||
async fn blend_image_tuple<_P, MapFn, _Fg>(images: (ImageFrameTable<_P>, _Fg), map_fn: &'n MapFn) -> ImageFrameTable<_P>
|
async fn blend_image_tuple<_P, MapFn, _Fg>(images: (ImageFrameTable<_P>, _Fg), map_fn: &'n MapFn) -> ImageFrameTable<_P>
|
||||||
where
|
where
|
||||||
_P: Alpha + Pixel + Debug + Send + dyn_any::StaticType,
|
_P: Alpha + Pixel + Debug + Send,
|
||||||
_P::Static: Pixel,
|
|
||||||
MapFn: for<'any_input> Node<'any_input, (_P, _P), Output = _P> + 'n + Clone,
|
MapFn: for<'any_input> Node<'any_input, (_P, _P), Output = _P> + 'n + Clone,
|
||||||
_Fg: Sample<Pixel = _P> + Transform + Clone + Send + 'n,
|
_Fg: Sample<Pixel = _P> + Transform + Clone + Send + 'n,
|
||||||
GraphicElement: From<Image<_P>>,
|
GraphicElement: From<Image<_P>>,
|
||||||
|
@ -513,7 +512,7 @@ fn noise_pattern(
|
||||||
|
|
||||||
// If the image would not be visible, return an empty image
|
// If the image would not be visible, return an empty image
|
||||||
if size.x <= 0. || size.y <= 0. {
|
if size.x <= 0. || size.y <= 0. {
|
||||||
return ImageFrameTable::empty();
|
return ImageFrameTable::one_empty_image();
|
||||||
}
|
}
|
||||||
|
|
||||||
let footprint_scale = footprint.scale();
|
let footprint_scale = footprint.scale();
|
||||||
|
@ -639,7 +638,7 @@ fn mandelbrot(ctx: impl ExtractFootprint + Send) -> ImageFrameTable<Color> {
|
||||||
|
|
||||||
// If the image would not be visible, return an empty image
|
// If the image would not be visible, return an empty image
|
||||||
if size.x <= 0. || size.y <= 0. {
|
if size.x <= 0. || size.y <= 0. {
|
||||||
return ImageFrameTable::empty();
|
return ImageFrameTable::one_empty_image();
|
||||||
}
|
}
|
||||||
|
|
||||||
let scale = footprint.scale();
|
let scale = footprint.scale();
|
||||||
|
|
|
@ -77,7 +77,7 @@ async fn load_resource<'a: 'n>(_: impl Ctx, _primary: (), #[scope("editor-api")]
|
||||||
#[node_macro::node(category("Network"))]
|
#[node_macro::node(category("Network"))]
|
||||||
fn decode_image(_: impl Ctx, data: Arc<[u8]>) -> ImageFrameTable<Color> {
|
fn decode_image(_: impl Ctx, data: Arc<[u8]>) -> ImageFrameTable<Color> {
|
||||||
let Some(image) = image::load_from_memory(data.as_ref()).ok() else {
|
let Some(image) = image::load_from_memory(data.as_ref()).ok() else {
|
||||||
return ImageFrameTable::empty();
|
return ImageFrameTable::one_empty_image();
|
||||||
};
|
};
|
||||||
let image = image.to_rgba32f();
|
let image = image.to_rgba32f();
|
||||||
let image = Image {
|
let image = Image {
|
||||||
|
@ -216,7 +216,7 @@ async fn render<'a: 'n, T: 'n + GraphicElementRendered + WasmNotSend>(
|
||||||
Context -> ImageFrameTable<Color>,
|
Context -> ImageFrameTable<Color>,
|
||||||
Context -> GraphicGroupTable,
|
Context -> GraphicGroupTable,
|
||||||
Context -> graphene_core::Artboard,
|
Context -> graphene_core::Artboard,
|
||||||
Context -> graphene_core::ArtboardGroup,
|
Context -> graphene_core::ArtboardGroupTable,
|
||||||
Context -> Option<Color>,
|
Context -> Option<Color>,
|
||||||
Context -> Vec<Color>,
|
Context -> Vec<Color>,
|
||||||
Context -> bool,
|
Context -> bool,
|
||||||
|
|
|
@ -114,7 +114,10 @@ impl DynamicExecutor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: StaticType + 'static + Send + Sync + std::panic::UnwindSafe> Executor<I, TaggedValue> for &DynamicExecutor {
|
impl<I> Executor<I, TaggedValue> for &DynamicExecutor
|
||||||
|
where
|
||||||
|
I: StaticType + 'static + Send + Sync + std::panic::UnwindSafe,
|
||||||
|
{
|
||||||
fn execute(&self, input: I) -> LocalFuture<Result<TaggedValue, Box<dyn Error>>> {
|
fn execute(&self, input: I) -> LocalFuture<Result<TaggedValue, Box<dyn Error>>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
|
@ -225,14 +228,21 @@ impl BorrowTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate the output node of the [`BorrowTree`].
|
/// Evaluate the output node of the [`BorrowTree`].
|
||||||
pub async fn eval<'i, I: StaticType + 'i + Send + Sync, O: StaticType + 'i>(&'i self, id: NodeId, input: I) -> Option<O> {
|
pub async fn eval<'i, I, O>(&'i self, id: NodeId, input: I) -> Option<O>
|
||||||
|
where
|
||||||
|
I: StaticType + 'i + Send + Sync,
|
||||||
|
O: StaticType + 'i,
|
||||||
|
{
|
||||||
let (node, _path) = self.nodes.get(&id).cloned()?;
|
let (node, _path) = self.nodes.get(&id).cloned()?;
|
||||||
let output = node.eval(Box::new(input));
|
let output = node.eval(Box::new(input));
|
||||||
dyn_any::downcast::<O>(output.await).ok().map(|o| *o)
|
dyn_any::downcast::<O>(output.await).ok().map(|o| *o)
|
||||||
}
|
}
|
||||||
/// Evaluate the output node of the [`BorrowTree`] and cast it to a tagged value.
|
/// Evaluate the output node of the [`BorrowTree`] and cast it to a tagged value.
|
||||||
/// This ensures that no borrowed data can escape the node graph.
|
/// This ensures that no borrowed data can escape the node graph.
|
||||||
pub async fn eval_tagged_value<I: StaticType + 'static + Send + Sync + UnwindSafe>(&self, id: NodeId, input: I) -> Result<TaggedValue, String> {
|
pub async fn eval_tagged_value<I>(&self, id: NodeId, input: I) -> Result<TaggedValue, String>
|
||||||
|
where
|
||||||
|
I: StaticType + 'static + Send + Sync + UnwindSafe,
|
||||||
|
{
|
||||||
let (node, _path) = self.nodes.get(&id).cloned().ok_or("Output node not found in executor")?;
|
let (node, _path) = self.nodes.get(&id).cloned().ok_or("Output node not found in executor")?;
|
||||||
let output = node.eval(Box::new(input));
|
let output = node.eval(Box::new(input));
|
||||||
TaggedValue::try_from_any(output.await)
|
TaggedValue::try_from_any(output.await)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue