mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-07-08 00:05:00 +00:00
refactor tables to calculate the index of the the row in the vec of instances
This commit is contained in:
parent
db141046a3
commit
b1ee9cf412
7 changed files with 184 additions and 165 deletions
|
@ -1481,7 +1481,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::network(concrete!(graphene_std::vector::VectorDataInstancesModification), 1)],
|
inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::network(concrete!(graphene_std::vector::VectorDataModification), 1)],
|
||||||
manual_composition: Some(generic!(T)),
|
manual_composition: Some(generic!(T)),
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::vector_data::modification::PathModifyNode")),
|
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::vector_data::modification::PathModifyNode")),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -1495,7 +1495,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
}),
|
}),
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
NodeInput::value(TaggedValue::VectorData(VectorDataTable::default()), true),
|
NodeInput::value(TaggedValue::VectorData(VectorDataTable::default()), true),
|
||||||
NodeInput::value(TaggedValue::VectorDataInstancesModification(Default::default()), false),
|
NodeInput::value(TaggedValue::VectorDataModification(Default::default()), false),
|
||||||
],
|
],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,7 +5,7 @@ use glam::{DAffine2, DVec2};
|
||||||
use graph_craft::document::NodeId;
|
use graph_craft::document::NodeId;
|
||||||
use graphene_std::renderer::{ClickTarget, ClickTargetType, Quad};
|
use graphene_std::renderer::{ClickTarget, ClickTargetType, Quad};
|
||||||
use graphene_std::transform::Footprint;
|
use graphene_std::transform::Footprint;
|
||||||
use graphene_std::vector::{PointId, VectorData};
|
use graphene_std::vector::{PointId, VectorData, VectorDataTable};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::num::NonZeroU64;
|
use std::num::NonZeroU64;
|
||||||
|
|
||||||
|
@ -20,9 +20,9 @@ pub struct DocumentMetadata {
|
||||||
pub upstream_footprints: HashMap<NodeId, Footprint>,
|
pub upstream_footprints: HashMap<NodeId, Footprint>,
|
||||||
pub local_transforms: HashMap<NodeId, DAffine2>,
|
pub local_transforms: HashMap<NodeId, DAffine2>,
|
||||||
pub structure: HashMap<LayerNodeIdentifier, NodeRelations>,
|
pub structure: HashMap<LayerNodeIdentifier, NodeRelations>,
|
||||||
pub click_targets: HashMap<LayerNodeIdentifier, Vec<ClickTarget>>,
|
pub click_targets: HashMap<LayerNodeIdentifier, HashMap<usize, Vec<ClickTarget>>>,
|
||||||
pub clip_targets: HashSet<NodeId>,
|
pub clip_targets: HashSet<NodeId>,
|
||||||
pub vector_modify: HashMap<NodeId, VectorData>,
|
pub vector_modify: HashMap<NodeId, VectorDataTable>,
|
||||||
/// Transform from document space to viewport space.
|
/// Transform from document space to viewport space.
|
||||||
pub document_to_viewport: DAffine2,
|
pub document_to_viewport: DAffine2,
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, No
|
||||||
use graph_craft::{Type, concrete};
|
use graph_craft::{Type, concrete};
|
||||||
use graphene_std::renderer::{ClickTarget, ClickTargetType, Quad};
|
use graphene_std::renderer::{ClickTarget, ClickTargetType, Quad};
|
||||||
use graphene_std::transform::Footprint;
|
use graphene_std::transform::Footprint;
|
||||||
use graphene_std::vector::{PointId, VectorData, VectorModificationType};
|
use graphene_std::vector::{PointId, VectorData, VectorDataTable, VectorModificationType};
|
||||||
use interpreted_executor::dynamic_executor::ResolvedDocumentNodeTypes;
|
use interpreted_executor::dynamic_executor::ResolvedDocumentNodeTypes;
|
||||||
use interpreted_executor::node_registry::NODE_REGISTRY;
|
use interpreted_executor::node_registry::NODE_REGISTRY;
|
||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
|
@ -3178,15 +3178,27 @@ impl NodeNetworkInterface {
|
||||||
(layer_widths, chain_widths, has_left_input_wire)
|
(layer_widths, chain_widths, has_left_input_wire)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn compute_modified_vector_table(&self, layer: LayerNodeIdentifier) -> Option<VectorDataTable> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn compute_modified_vector(&self, layer: LayerNodeIdentifier) -> Option<VectorData> {
|
pub fn compute_modified_vector(&self, layer: LayerNodeIdentifier) -> Option<VectorData> {
|
||||||
let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, self);
|
let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, self);
|
||||||
|
|
||||||
if let Some(vector_data) = graph_layer.upstream_node_id_from_name("Path").and_then(|node| self.document_metadata.vector_modify.get(&node)) {
|
let vector_data = graph_layer.upstream_node_id_from_name("Path").and_then(|node| self.document_metadata.vector_modify.get(&node));
|
||||||
let mut modified = vector_data.clone();
|
let modification = graph_layer.find_input("Path", 1);
|
||||||
if let Some(TaggedValue::VectorModification(modification)) = graph_layer.find_input("Path", 1) {
|
|
||||||
modification.apply(&mut modified);
|
match (vector_data, modification) {
|
||||||
|
(Some(vector_data), Some(TaggedValue::VectorDataModification(modification))) => {
|
||||||
|
let mut vector_data = vector_data.clone();
|
||||||
|
for (index, vector_data_instance) in vector_data.instance_mut_iter().enumerate() {
|
||||||
|
if let Some(vector_modification) = modification.get(&index) {
|
||||||
|
vector_modification.apply(vector_data_instance.instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Some(vector_data);
|
||||||
}
|
}
|
||||||
return Some(modified);
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.document_metadata
|
self.document_metadata
|
||||||
|
@ -3361,7 +3373,7 @@ impl NodeNetworkInterface {
|
||||||
};
|
};
|
||||||
{
|
{
|
||||||
let mut value = node.inputs.get_mut(1).and_then(|input| input.as_value_mut());
|
let mut value = node.inputs.get_mut(1).and_then(|input| input.as_value_mut());
|
||||||
let Some(TaggedValue::VectorModification(modification)) = value.as_deref_mut() else {
|
let Some(TaggedValue::VectorDataModification(modification)) = value.as_deref_mut() else {
|
||||||
panic!("Path node does not have modification input");
|
panic!("Path node does not have modification input");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -745,7 +745,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
|
||||||
let path_node_type = resolve_document_node_type("Path").expect("Path node does not exist.");
|
let path_node_type = resolve_document_node_type("Path").expect("Path node does not exist.");
|
||||||
let path_node = path_node_type.node_template_input_override([
|
let path_node = path_node_type.node_template_input_override([
|
||||||
Some(NodeInput::value(TaggedValue::VectorData(VectorDataTable::new(vector_data)), true)),
|
Some(NodeInput::value(TaggedValue::VectorData(VectorDataTable::new(vector_data)), true)),
|
||||||
Some(NodeInput::value(TaggedValue::VectorModification(Default::default()), false)),
|
Some(NodeInput::value(TaggedValue::VectorDataModification(Default::default()), false)),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Get the "Spline" node definition and wire it up with the "Path" node as input
|
// Get the "Spline" node definition and wire it up with the "Path" node as input
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::transform::{Footprint, Transform};
|
||||||
use crate::uuid::{NodeId, generate_uuid};
|
use crate::uuid::{NodeId, generate_uuid};
|
||||||
use crate::vector::style::{Fill, Stroke, StrokeAlign, ViewMode};
|
use crate::vector::style::{Fill, Stroke, StrokeAlign, ViewMode};
|
||||||
use crate::vector::{PointId, VectorDataTable};
|
use crate::vector::{PointId, VectorDataTable};
|
||||||
use crate::{Artboard, ArtboardGroupTable, Color, GraphicElement, GraphicGroupTable};
|
use crate::{ArtboardGroupTable, Color, GraphicElement, GraphicGroupTable};
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use bezier_rs::Subpath;
|
use bezier_rs::Subpath;
|
||||||
use dyn_any::DynAny;
|
use dyn_any::DynAny;
|
||||||
|
@ -354,7 +354,7 @@ pub fn to_transform(transform: DAffine2) -> usvg::Transform {
|
||||||
pub struct RenderMetadata {
|
pub struct RenderMetadata {
|
||||||
pub upstream_footprints: HashMap<NodeId, Footprint>,
|
pub upstream_footprints: HashMap<NodeId, Footprint>,
|
||||||
pub local_transforms: HashMap<NodeId, DAffine2>,
|
pub local_transforms: HashMap<NodeId, DAffine2>,
|
||||||
pub click_targets: HashMap<NodeId, Vec<ClickTarget>>,
|
pub click_targets: HashMap<NodeId, HashMap<usize, Vec<ClickTarget>>>,
|
||||||
pub clip_targets: HashSet<NodeId>,
|
pub clip_targets: HashSet<NodeId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,7 +367,7 @@ pub trait GraphicElementRendered {
|
||||||
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> Option<[DVec2; 2]>;
|
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> Option<[DVec2; 2]>;
|
||||||
|
|
||||||
/// The upstream click targets for each layer are collected during the render so that they do not have to be calculated for each click detection.
|
/// The upstream click targets for each layer are collected during the render so that they do not have to be calculated for each click detection.
|
||||||
fn add_upstream_click_targets(&self, _click_targets: &mut Vec<ClickTarget>) {}
|
fn add_upstream_click_targets(&self, _click_targets: &mut HashMap<usize, Vec<ClickTarget>>) {}
|
||||||
|
|
||||||
// TODO: Store all click targets in a vec which contains the AABB, click target, and path
|
// TODO: Store all click targets in a vec which contains the AABB, click target, and path
|
||||||
// fn add_click_targets(&self, click_targets: &mut Vec<([DVec2; 2], ClickTarget, Vec<NodeId>)>, current_path: Option<NodeId>) {}
|
// fn add_click_targets(&self, click_targets: &mut Vec<([DVec2; 2], ClickTarget, Vec<NodeId>)>, current_path: Option<NodeId>) {}
|
||||||
|
@ -524,14 +524,16 @@ impl GraphicElementRendered for GraphicGroupTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(graphic_group_id) = element_id {
|
if let Some(graphic_group_id) = element_id {
|
||||||
let mut all_upstream_click_targets = Vec::new();
|
let mut all_upstream_click_targets = HashMap::new();
|
||||||
|
|
||||||
for instance in self.instance_ref_iter() {
|
for (index, instance) in self.instance_ref_iter().enumerate() {
|
||||||
let mut new_click_targets = Vec::new();
|
let mut new_click_targets = HashMap::new();
|
||||||
instance.instance.add_upstream_click_targets(&mut new_click_targets);
|
instance.instance.add_upstream_click_targets(&mut new_click_targets);
|
||||||
|
|
||||||
for click_target in new_click_targets.iter_mut() {
|
for (_, click_targets) in new_click_targets.iter_mut() {
|
||||||
click_target.apply_transform(*instance.transform)
|
for click_target in click_targets {
|
||||||
|
click_target.apply_transform(*instance.transform)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
all_upstream_click_targets.extend(new_click_targets);
|
all_upstream_click_targets.extend(new_click_targets);
|
||||||
|
@ -541,14 +543,16 @@ impl GraphicElementRendered for GraphicGroupTable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_upstream_click_targets(&self, click_targets: &mut Vec<ClickTarget>) {
|
fn add_upstream_click_targets(&self, click_targets: &mut HashMap<usize, Vec<ClickTarget>>) {
|
||||||
for instance in self.instance_ref_iter() {
|
for instance in self.instance_ref_iter() {
|
||||||
let mut new_click_targets = Vec::new();
|
let mut new_click_targets = HashMap::new();
|
||||||
|
|
||||||
instance.instance.add_upstream_click_targets(&mut new_click_targets);
|
instance.instance.add_upstream_click_targets(&mut new_click_targets);
|
||||||
|
|
||||||
for click_target in new_click_targets.iter_mut() {
|
for (_, click_targets) in new_click_targets.iter_mut() {
|
||||||
click_target.apply_transform(*instance.transform)
|
for click_target in click_targets {
|
||||||
|
click_target.apply_transform(*instance.transform)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
click_targets.extend(new_click_targets);
|
click_targets.extend(new_click_targets);
|
||||||
|
@ -905,7 +909,7 @@ impl GraphicElementRendered for VectorDataTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_metadata(&self, metadata: &mut RenderMetadata, mut footprint: Footprint, element_id: Option<NodeId>) {
|
fn collect_metadata(&self, metadata: &mut RenderMetadata, mut footprint: Footprint, element_id: Option<NodeId>) {
|
||||||
for instance in self.instance_ref_iter() {
|
for (index, instance) in self.instance_ref_iter().enumerate() {
|
||||||
let instance_transform = *instance.transform;
|
let instance_transform = *instance.transform;
|
||||||
let instance = instance.instance;
|
let instance = instance.instance;
|
||||||
|
|
||||||
|
@ -938,7 +942,10 @@ impl GraphicElementRendered for VectorDataTable {
|
||||||
.chain(single_anchors_targets.into_iter())
|
.chain(single_anchors_targets.into_iter())
|
||||||
.collect::<Vec<ClickTarget>>();
|
.collect::<Vec<ClickTarget>>();
|
||||||
|
|
||||||
metadata.click_targets.insert(element_id, click_targets);
|
// metadata.click_targets.insert(element_id, );
|
||||||
|
metadata.click_targets.entry(element_id).and_modify(|click_target_map| {
|
||||||
|
click_target_map.insert(index, click_targets);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(upstream_graphic_group) = &instance.upstream_graphic_group {
|
if let Some(upstream_graphic_group) = &instance.upstream_graphic_group {
|
||||||
|
@ -948,8 +955,8 @@ impl GraphicElementRendered for VectorDataTable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_upstream_click_targets(&self, click_targets: &mut Vec<ClickTarget>) {
|
fn add_upstream_click_targets(&self, click_targets: &mut HashMap<usize, Vec<ClickTarget>>) {
|
||||||
for instance in self.instance_ref_iter() {
|
for (index, instance) in self.instance_ref_iter().enumerate() {
|
||||||
let stroke_width = instance.instance.style.stroke().as_ref().map_or(0., Stroke::weight);
|
let stroke_width = instance.instance.style.stroke().as_ref().map_or(0., Stroke::weight);
|
||||||
let filled = instance.instance.style.fill() != &Fill::None;
|
let filled = instance.instance.style.fill() != &Fill::None;
|
||||||
let fill = |mut subpath: Subpath<_>| {
|
let fill = |mut subpath: Subpath<_>| {
|
||||||
|
@ -958,11 +965,15 @@ impl GraphicElementRendered for VectorDataTable {
|
||||||
}
|
}
|
||||||
subpath
|
subpath
|
||||||
};
|
};
|
||||||
click_targets.extend(instance.instance.stroke_bezier_paths().map(fill).map(|subpath| {
|
|
||||||
let mut click_target = ClickTarget::new_with_subpath(subpath, stroke_width);
|
click_targets
|
||||||
click_target.apply_transform(*instance.transform);
|
.entry(index)
|
||||||
click_target
|
.or_insert(Vec::new())
|
||||||
}));
|
.extend(instance.instance.stroke_bezier_paths().map(fill).map(|subpath| {
|
||||||
|
let mut click_target = ClickTarget::new_with_subpath(subpath, stroke_width);
|
||||||
|
click_target.apply_transform(*instance.transform);
|
||||||
|
click_target
|
||||||
|
}));
|
||||||
|
|
||||||
// For free-floating anchors, we need to add a click target for each
|
// For free-floating anchors, we need to add a click target for each
|
||||||
let single_anchors_targets = instance.instance.point_domain.ids().iter().filter_map(|&point_id| {
|
let single_anchors_targets = instance.instance.point_domain.ids().iter().filter_map(|&point_id| {
|
||||||
|
@ -977,7 +988,8 @@ impl GraphicElementRendered for VectorDataTable {
|
||||||
click_target.apply_transform(*instance.transform);
|
click_target.apply_transform(*instance.transform);
|
||||||
Some(click_target)
|
Some(click_target)
|
||||||
});
|
});
|
||||||
click_targets.extend(single_anchors_targets);
|
|
||||||
|
click_targets.entry(index).or_insert(Vec::new()).extend(single_anchors_targets);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -992,143 +1004,133 @@ impl GraphicElementRendered for VectorDataTable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GraphicElementRendered for Artboard {
|
impl GraphicElementRendered for ArtboardGroupTable {
|
||||||
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
|
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
|
||||||
if !render_params.hide_artboards {
|
for artboard in self.instance_ref_iter() {
|
||||||
// Background
|
let artboard = artboard.instance;
|
||||||
render.leaf_tag("rect", |attributes| {
|
|
||||||
attributes.push("fill", format!("#{}", self.background.to_rgb_hex_srgb_from_gamma()));
|
if !render_params.hide_artboards {
|
||||||
if self.background.a() < 1. {
|
// Background
|
||||||
attributes.push("fill-opacity", ((self.background.a() * 1000.).round() / 1000.).to_string());
|
render.leaf_tag("rect", |attributes| {
|
||||||
}
|
attributes.push("fill", format!("#{}", artboard.background.to_rgb_hex_srgb_from_gamma()));
|
||||||
attributes.push("x", self.location.x.min(self.location.x + self.dimensions.x).to_string());
|
if artboard.background.a() < 1. {
|
||||||
attributes.push("y", self.location.y.min(self.location.y + self.dimensions.y).to_string());
|
attributes.push("fill-opacity", ((artboard.background.a() * 1000.).round() / 1000.).to_string());
|
||||||
attributes.push("width", self.dimensions.x.abs().to_string());
|
}
|
||||||
attributes.push("height", self.dimensions.y.abs().to_string());
|
attributes.push("x", artboard.location.x.min(artboard.location.x + artboard.dimensions.x).to_string());
|
||||||
});
|
attributes.push("y", artboard.location.y.min(artboard.location.y + artboard.dimensions.y).to_string());
|
||||||
|
attributes.push("width", artboard.dimensions.x.abs().to_string());
|
||||||
|
attributes.push("height", artboard.dimensions.y.abs().to_string());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contents group (includes the artwork but not the background)
|
||||||
|
render.parent_tag(
|
||||||
|
// SVG group tag
|
||||||
|
"g",
|
||||||
|
// Group tag attributes
|
||||||
|
|attributes| {
|
||||||
|
let matrix = format_transform_matrix(artboard.transform());
|
||||||
|
if !matrix.is_empty() {
|
||||||
|
attributes.push("transform", matrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
if artboard.clip {
|
||||||
|
let id = format!("artboard-{}", generate_uuid());
|
||||||
|
let selector = format!("url(#{id})");
|
||||||
|
|
||||||
|
write!(
|
||||||
|
&mut attributes.0.svg_defs,
|
||||||
|
r##"<clipPath id="{id}"><rect x="0" y="0" width="{}" height="{}"/></clipPath>"##,
|
||||||
|
artboard.dimensions.x, artboard.dimensions.y,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
attributes.push("clip-path", selector);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Artboard contents
|
||||||
|
|render| {
|
||||||
|
artboard.graphic_group.render_svg(render, render_params);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Contents group (includes the artwork but not the background)
|
|
||||||
render.parent_tag(
|
|
||||||
// SVG group tag
|
|
||||||
"g",
|
|
||||||
// Group tag attributes
|
|
||||||
|attributes| {
|
|
||||||
let matrix = format_transform_matrix(self.transform());
|
|
||||||
if !matrix.is_empty() {
|
|
||||||
attributes.push("transform", matrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.clip {
|
|
||||||
let id = format!("artboard-{}", generate_uuid());
|
|
||||||
let selector = format!("url(#{id})");
|
|
||||||
|
|
||||||
write!(
|
|
||||||
&mut attributes.0.svg_defs,
|
|
||||||
r##"<clipPath id="{id}"><rect x="0" y="0" width="{}" height="{}"/></clipPath>"##,
|
|
||||||
self.dimensions.x, self.dimensions.y,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
attributes.push("clip-path", selector);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Artboard contents
|
|
||||||
|render| {
|
|
||||||
self.graphic_group.render_svg(render, render_params);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "vello")]
|
#[cfg(feature = "vello")]
|
||||||
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) {
|
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) {
|
||||||
use vello::peniko;
|
use vello::peniko;
|
||||||
|
|
||||||
// Render background
|
|
||||||
let color = peniko::Color::new([self.background.r(), self.background.g(), self.background.b(), self.background.a()]);
|
|
||||||
let [a, b] = [self.location.as_dvec2(), self.location.as_dvec2() + self.dimensions.as_dvec2()];
|
|
||||||
let rect = kurbo::Rect::new(a.x.min(b.x), a.y.min(b.y), a.x.max(b.x), a.y.max(b.y));
|
|
||||||
|
|
||||||
scene.push_layer(peniko::Mix::Normal, 1., kurbo::Affine::new(transform.to_cols_array()), &rect);
|
|
||||||
scene.fill(peniko::Fill::NonZero, kurbo::Affine::new(transform.to_cols_array()), color, None, &rect);
|
|
||||||
scene.pop_layer();
|
|
||||||
|
|
||||||
if self.clip {
|
|
||||||
let blend_mode = peniko::BlendMode::new(peniko::Mix::Clip, peniko::Compose::SrcOver);
|
|
||||||
scene.push_layer(blend_mode, 1., kurbo::Affine::new(transform.to_cols_array()), &rect);
|
|
||||||
}
|
|
||||||
// Since the graphic group's transform is right multiplied in when rendering the graphic group, we just need to right multiply by the offset here.
|
|
||||||
let child_transform = transform * DAffine2::from_translation(self.location.as_dvec2());
|
|
||||||
self.graphic_group.render_to_vello(scene, child_transform, context, render_params);
|
|
||||||
if self.clip {
|
|
||||||
scene.pop_layer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> Option<[DVec2; 2]> {
|
|
||||||
let artboard_bounds = (transform * Quad::from_box([self.location.as_dvec2(), self.location.as_dvec2() + self.dimensions.as_dvec2()])).bounding_box();
|
|
||||||
if self.clip {
|
|
||||||
Some(artboard_bounds)
|
|
||||||
} else {
|
|
||||||
[self.graphic_group.bounding_box(transform, include_stroke), Some(artboard_bounds)]
|
|
||||||
.into_iter()
|
|
||||||
.flatten()
|
|
||||||
.reduce(Quad::combine_bounds)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn collect_metadata(&self, metadata: &mut RenderMetadata, mut footprint: Footprint, element_id: Option<NodeId>) {
|
|
||||||
if let Some(element_id) = element_id {
|
|
||||||
let subpath = Subpath::new_rect(DVec2::ZERO, self.dimensions.as_dvec2());
|
|
||||||
metadata.click_targets.insert(element_id, vec![ClickTarget::new_with_subpath(subpath, 0.)]);
|
|
||||||
metadata.upstream_footprints.insert(element_id, footprint);
|
|
||||||
metadata.local_transforms.insert(element_id, DAffine2::from_translation(self.location.as_dvec2()));
|
|
||||||
if self.clip {
|
|
||||||
metadata.clip_targets.insert(element_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
footprint.transform *= self.transform();
|
|
||||||
self.graphic_group.collect_metadata(metadata, footprint, None);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_upstream_click_targets(&self, click_targets: &mut Vec<ClickTarget>) {
|
|
||||||
let subpath_rectangle = Subpath::new_rect(DVec2::ZERO, self.dimensions.as_dvec2());
|
|
||||||
click_targets.push(ClickTarget::new_with_subpath(subpath_rectangle, 0.));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn contains_artboard(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GraphicElementRendered for ArtboardGroupTable {
|
|
||||||
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
|
|
||||||
for artboard in self.instance_ref_iter() {
|
|
||||||
artboard.instance.render_svg(render, render_params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "vello")]
|
|
||||||
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) {
|
|
||||||
for instance in self.instance_ref_iter() {
|
for instance in self.instance_ref_iter() {
|
||||||
instance.instance.render_to_vello(scene, transform, context, render_params);
|
let instance = instance.instance;
|
||||||
|
|
||||||
|
// Render background
|
||||||
|
let color = peniko::Color::new([instance.background.r(), instance.background.g(), instance.background.b(), instance.background.a()]);
|
||||||
|
let [a, b] = [instance.location.as_dvec2(), instance.location.as_dvec2() + instance.dimensions.as_dvec2()];
|
||||||
|
let rect = kurbo::Rect::new(a.x.min(b.x), a.y.min(b.y), a.x.max(b.x), a.y.max(b.y));
|
||||||
|
|
||||||
|
scene.push_layer(peniko::Mix::Normal, 1., kurbo::Affine::new(transform.to_cols_array()), &rect);
|
||||||
|
scene.fill(peniko::Fill::NonZero, kurbo::Affine::new(transform.to_cols_array()), color, None, &rect);
|
||||||
|
scene.pop_layer();
|
||||||
|
|
||||||
|
if instance.clip {
|
||||||
|
let blend_mode = peniko::BlendMode::new(peniko::Mix::Clip, peniko::Compose::SrcOver);
|
||||||
|
scene.push_layer(blend_mode, 1., kurbo::Affine::new(transform.to_cols_array()), &rect);
|
||||||
|
}
|
||||||
|
// Since the graphic group's transform is right multiplied in when rendering the graphic group, we just need to right multiply by the offset here.
|
||||||
|
let child_transform = transform * DAffine2::from_translation(instance.location.as_dvec2());
|
||||||
|
instance.graphic_group.render_to_vello(scene, child_transform, context, render_params);
|
||||||
|
if instance.clip {
|
||||||
|
scene.pop_layer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> Option<[DVec2; 2]> {
|
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> Option<[DVec2; 2]> {
|
||||||
self.instance_ref_iter()
|
self.instance_ref_iter()
|
||||||
.filter_map(|instance| instance.instance.bounding_box(transform, include_stroke))
|
.filter_map(|instance| {
|
||||||
|
let instance = instance.instance;
|
||||||
|
let artboard_bounds = (transform * Quad::from_box([instance.location.as_dvec2(), instance.location.as_dvec2() + instance.dimensions.as_dvec2()])).bounding_box();
|
||||||
|
if instance.clip {
|
||||||
|
Some(artboard_bounds)
|
||||||
|
} else {
|
||||||
|
[instance.graphic_group.bounding_box(transform, include_stroke), Some(artboard_bounds)]
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.reduce(Quad::combine_bounds)
|
||||||
|
}
|
||||||
|
})
|
||||||
.reduce(Quad::combine_bounds)
|
.reduce(Quad::combine_bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_metadata(&self, metadata: &mut RenderMetadata, footprint: Footprint, _element_id: Option<NodeId>) {
|
fn collect_metadata(&self, metadata: &mut RenderMetadata, mut footprint: Footprint, element_id: Option<NodeId>) {
|
||||||
for instance in self.instance_ref_iter() {
|
for (index, instance) in self.instance_ref_iter().enumerate() {
|
||||||
instance.instance.collect_metadata(metadata, footprint, *instance.source_node_id);
|
let instance = instance.instance;
|
||||||
|
|
||||||
|
if let Some(element_id) = element_id {
|
||||||
|
let subpath = Subpath::new_rect(DVec2::ZERO, instance.dimensions.as_dvec2());
|
||||||
|
|
||||||
|
metadata
|
||||||
|
.click_targets
|
||||||
|
.entry(element_id)
|
||||||
|
.or_insert(HashMap::new())
|
||||||
|
.entry(index)
|
||||||
|
.or_insert(Vec::new())
|
||||||
|
.push(ClickTarget::new_with_subpath(subpath, 0.));
|
||||||
|
|
||||||
|
metadata.upstream_footprints.insert(element_id, footprint);
|
||||||
|
metadata.local_transforms.insert(element_id, DAffine2::from_translation(instance.location.as_dvec2()));
|
||||||
|
if instance.clip {
|
||||||
|
metadata.clip_targets.insert(element_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
footprint.transform *= instance.transform();
|
||||||
|
instance.graphic_group.collect_metadata(metadata, footprint, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_upstream_click_targets(&self, click_targets: &mut Vec<ClickTarget>) {
|
fn add_upstream_click_targets(&self, click_targets: &mut HashMap<usize, Vec<ClickTarget>>) {
|
||||||
for instance in self.instance_ref_iter() {
|
for (index, instance) in self.instance_ref_iter().enumerate() {
|
||||||
instance.instance.add_upstream_click_targets(click_targets);
|
let subpath_rectangle = Subpath::new_rect(DVec2::ZERO, instance.instance.dimensions.as_dvec2());
|
||||||
|
|
||||||
|
click_targets.entry(index).or_insert(Vec::new()).push(ClickTarget::new_with_subpath(subpath_rectangle, 0.));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1205,7 +1207,9 @@ impl GraphicElementRendered for RasterDataTable<CPU> {
|
||||||
let Some(element_id) = element_id else { return };
|
let Some(element_id) = element_id else { return };
|
||||||
let subpath = Subpath::new_rect(DVec2::ZERO, DVec2::ONE);
|
let subpath = Subpath::new_rect(DVec2::ZERO, DVec2::ONE);
|
||||||
|
|
||||||
metadata.click_targets.insert(element_id, vec![ClickTarget::new_with_subpath(subpath, 0.)]);
|
let mut click_targets = HashMap::new();
|
||||||
|
click_targets.insert(0, vec![ClickTarget::new_with_subpath(subpath, 0.)]);
|
||||||
|
metadata.click_targets.insert(element_id, click_targets);
|
||||||
metadata.upstream_footprints.insert(element_id, footprint);
|
metadata.upstream_footprints.insert(element_id, footprint);
|
||||||
// TODO: Find a way to handle more than one row of the graphical data table
|
// TODO: Find a way to handle more than one row of the graphical data table
|
||||||
if let Some(image) = self.instance_ref_iter().next() {
|
if let Some(image) = self.instance_ref_iter().next() {
|
||||||
|
@ -1213,9 +1217,9 @@ impl GraphicElementRendered for RasterDataTable<CPU> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_upstream_click_targets(&self, click_targets: &mut Vec<ClickTarget>) {
|
fn add_upstream_click_targets(&self, click_targets: &mut HashMap<usize, Vec<ClickTarget>>) {
|
||||||
let subpath = Subpath::new_rect(DVec2::ZERO, DVec2::ONE);
|
let subpath = Subpath::new_rect(DVec2::ZERO, DVec2::ONE);
|
||||||
click_targets.push(ClickTarget::new_with_subpath(subpath, 0.));
|
click_targets.entry(0).or_insert(Vec::new()).push(ClickTarget::new_with_subpath(subpath, 0.));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_graphic_element(&self) -> GraphicElement {
|
fn to_graphic_element(&self) -> GraphicElement {
|
||||||
|
@ -1272,7 +1276,10 @@ impl GraphicElementRendered for RasterDataTable<GPU> {
|
||||||
let Some(element_id) = element_id else { return };
|
let Some(element_id) = element_id else { return };
|
||||||
let subpath = Subpath::new_rect(DVec2::ZERO, DVec2::ONE);
|
let subpath = Subpath::new_rect(DVec2::ZERO, DVec2::ONE);
|
||||||
|
|
||||||
metadata.click_targets.insert(element_id, vec![ClickTarget::new_with_subpath(subpath, 0.)]);
|
let mut click_targets = HashMap::new();
|
||||||
|
click_targets.insert(0, vec![ClickTarget::new_with_subpath(subpath, 0.)]);
|
||||||
|
|
||||||
|
metadata.click_targets.insert(element_id, click_targets);
|
||||||
metadata.upstream_footprints.insert(element_id, footprint);
|
metadata.upstream_footprints.insert(element_id, footprint);
|
||||||
// TODO: Find a way to handle more than one row of the graphical data table
|
// TODO: Find a way to handle more than one row of the graphical data table
|
||||||
if let Some(image) = self.instance_ref_iter().next() {
|
if let Some(image) = self.instance_ref_iter().next() {
|
||||||
|
@ -1280,9 +1287,9 @@ impl GraphicElementRendered for RasterDataTable<GPU> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_upstream_click_targets(&self, click_targets: &mut Vec<ClickTarget>) {
|
fn add_upstream_click_targets(&self, click_targets: &mut HashMap<usize, Vec<ClickTarget>>) {
|
||||||
let subpath = Subpath::new_rect(DVec2::ZERO, DVec2::ONE);
|
let subpath = Subpath::new_rect(DVec2::ZERO, DVec2::ONE);
|
||||||
click_targets.push(ClickTarget::new_with_subpath(subpath, 0.));
|
click_targets.entry(0).or_insert(Vec::new()).push(ClickTarget::new_with_subpath(subpath, 0.));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1355,7 +1362,7 @@ impl GraphicElementRendered for GraphicElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_upstream_click_targets(&self, click_targets: &mut Vec<ClickTarget>) {
|
fn add_upstream_click_targets(&self, click_targets: &mut HashMap<usize, Vec<ClickTarget>>) {
|
||||||
match self {
|
match self {
|
||||||
GraphicElement::VectorData(vector_data) => vector_data.add_upstream_click_targets(click_targets),
|
GraphicElement::VectorData(vector_data) => vector_data.add_upstream_click_targets(click_targets),
|
||||||
GraphicElement::RasterDataCPU(raster) => raster.add_upstream_click_targets(click_targets),
|
GraphicElement::RasterDataCPU(raster) => raster.add_upstream_click_targets(click_targets),
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::uuid::generate_uuid;
|
||||||
use bezier_rs::BezierHandles;
|
use bezier_rs::BezierHandles;
|
||||||
use dyn_any::DynAny;
|
use dyn_any::DynAny;
|
||||||
use kurbo::{BezPath, PathEl, Point};
|
use kurbo::{BezPath, PathEl, Point};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||||
use std::hash::BuildHasher;
|
use std::hash::BuildHasher;
|
||||||
|
|
||||||
/// Represents a procedural change to the [`PointDomain`] in [`VectorData`].
|
/// Represents a procedural change to the [`PointDomain`] in [`VectorData`].
|
||||||
|
@ -418,11 +418,11 @@ impl Hash for VectorModification {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type VectorDataInstancesModification = HashMap<usize, VectorModification>;
|
pub type VectorDataModification = BTreeMap<usize, VectorModification>;
|
||||||
|
|
||||||
/// A node that applies a procedural modification to some [`VectorData`].
|
/// A node that applies a procedural modification to some [`VectorData`].
|
||||||
#[node_macro::node(category(""))]
|
#[node_macro::node(category(""))]
|
||||||
async fn path_modify(_ctx: impl Ctx, mut vector_data: VectorDataTable, modification: VectorDataInstancesModification) -> VectorDataTable {
|
async fn path_modify(_ctx: impl Ctx, mut vector_data: VectorDataTable, modification: VectorDataModification) -> VectorDataTable {
|
||||||
for (index, vector_data_instance) in vector_data.instance_mut_iter().enumerate() {
|
for (index, vector_data_instance) in vector_data.instance_mut_iter().enumerate() {
|
||||||
if let Some(vector_modification) = modification.get(&index) {
|
if let Some(vector_modification) = modification.get(&index) {
|
||||||
vector_modification.apply(vector_data_instance.instance);
|
vector_modification.apply(vector_data_instance.instance);
|
||||||
|
|
|
@ -11,7 +11,7 @@ use graphene_core::raster_types::CPU;
|
||||||
use graphene_core::renderer::RenderMetadata;
|
use graphene_core::renderer::RenderMetadata;
|
||||||
use graphene_core::transform::ReferencePoint;
|
use graphene_core::transform::ReferencePoint;
|
||||||
use graphene_core::uuid::NodeId;
|
use graphene_core::uuid::NodeId;
|
||||||
use graphene_core::vector::VectorDataInstancesModification;
|
use graphene_core::vector::VectorDataModification;
|
||||||
use graphene_core::vector::style::Fill;
|
use graphene_core::vector::style::Fill;
|
||||||
use graphene_core::{Color, MemoHash, Node, Type};
|
use graphene_core::{Color, MemoHash, Node, Type};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
@ -215,7 +215,7 @@ tagged_value! {
|
||||||
DocumentNode(DocumentNode),
|
DocumentNode(DocumentNode),
|
||||||
Curve(graphene_core::raster::curve::Curve),
|
Curve(graphene_core::raster::curve::Curve),
|
||||||
Footprint(graphene_core::transform::Footprint),
|
Footprint(graphene_core::transform::Footprint),
|
||||||
VectorDataInstancesModification(VectorDataInstancesModification),
|
VectorDataModification(VectorDataModification),
|
||||||
FontCache(Arc<graphene_core::text::FontCache>),
|
FontCache(Arc<graphene_core::text::FontCache>),
|
||||||
// ==========
|
// ==========
|
||||||
// ENUM TYPES
|
// ENUM TYPES
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue