Add transform-related nodes to improve transformation abilities (#2893)
* Improve transformation abilities with transform-related nodes * Fix Transform -> Merge and Transform -> Artboard connections
This commit is contained in:
parent
8f26c5c2ad
commit
561b671f8d
|
|
@ -1303,11 +1303,11 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
identifier: "Transform",
|
||||
category: "General",
|
||||
category: "Math: Transform",
|
||||
node_template: NodeTemplate {
|
||||
document_node: DocumentNode {
|
||||
inputs: vec![
|
||||
NodeInput::value(TaggedValue::VectorData(VectorDataTable::default()), true),
|
||||
NodeInput::value(TaggedValue::DAffine2(DAffine2::default()), true),
|
||||
NodeInput::value(TaggedValue::DVec2(DVec2::ZERO), false),
|
||||
NodeInput::value(TaggedValue::F64(0.), false),
|
||||
NodeInput::value(TaggedValue::DVec2(DVec2::ONE), false),
|
||||
|
|
@ -1317,7 +1317,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
exports: vec![NodeInput::node(NodeId(1), 0)],
|
||||
nodes: [
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::network(concrete!(VectorDataTable), 0)],
|
||||
inputs: vec![NodeInput::network(generic!(T), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(memo::monitor::IDENTIFIER),
|
||||
manual_composition: Some(generic!(T)),
|
||||
skip_deduplication: true,
|
||||
|
|
@ -1374,7 +1374,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
..Default::default()
|
||||
}),
|
||||
input_metadata: vec![
|
||||
("Vector Data", "TODO").into(),
|
||||
("Value", "TODO").into(),
|
||||
InputMetadata::with_name_description_override(
|
||||
"Translation",
|
||||
"TODO",
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use graphene_std::raster::{
|
|||
};
|
||||
use graphene_std::raster_types::{CPU, GPU, RasterDataTable};
|
||||
use graphene_std::text::Font;
|
||||
use graphene_std::transform::{Footprint, ReferencePoint};
|
||||
use graphene_std::transform::{Footprint, ReferencePoint, Transform};
|
||||
use graphene_std::vector::VectorDataTable;
|
||||
use graphene_std::vector::misc::GridType;
|
||||
use graphene_std::vector::misc::{ArcType, MergeByDistanceAlgorithm};
|
||||
|
|
@ -176,6 +176,7 @@ pub(crate) fn property_from_type(
|
|||
Some(x) if x == TypeId::of::<bool>() => bool_widget(default_info, CheckboxInput::default()).into(),
|
||||
Some(x) if x == TypeId::of::<String>() => text_widget(default_info).into(),
|
||||
Some(x) if x == TypeId::of::<DVec2>() => coordinate_widget(default_info, "X", "Y", "", None, false),
|
||||
Some(x) if x == TypeId::of::<DAffine2>() => transform_widget(default_info, &mut extra_widgets),
|
||||
// ==========================
|
||||
// PRIMITIVE COLLECTION TYPES
|
||||
// ==========================
|
||||
|
|
@ -504,6 +505,126 @@ pub fn footprint_widget(parameter_widgets_info: ParameterWidgetsInfo, extra_widg
|
|||
last.clone()
|
||||
}
|
||||
|
||||
pub fn transform_widget(parameter_widgets_info: ParameterWidgetsInfo, extra_widgets: &mut Vec<LayoutGroup>) -> LayoutGroup {
|
||||
let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info;
|
||||
|
||||
let mut location_widgets = start_widgets(parameter_widgets_info);
|
||||
location_widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||
|
||||
let mut rotation_widgets = vec![TextLabel::new("").widget_holder()];
|
||||
add_blank_assist(&mut rotation_widgets);
|
||||
rotation_widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||
|
||||
let mut scale_widgets = vec![TextLabel::new("").widget_holder()];
|
||||
add_blank_assist(&mut scale_widgets);
|
||||
scale_widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||
|
||||
let Some(document_node) = document_node else { return LayoutGroup::default() };
|
||||
let Some(input) = document_node.inputs.get(index) else {
|
||||
log::warn!("A widget failed to be built because its node's input index is invalid.");
|
||||
return Vec::new().into();
|
||||
};
|
||||
|
||||
let widgets = if let Some(&TaggedValue::DAffine2(transform)) = input.as_non_exposed_value() {
|
||||
let translation = transform.translation;
|
||||
let rotation = transform.decompose_rotation();
|
||||
let scale = transform.decompose_scale();
|
||||
|
||||
location_widgets.extend_from_slice(&[
|
||||
NumberInput::new(Some(translation.x))
|
||||
.label("X")
|
||||
.unit(" px")
|
||||
.on_update(update_value(
|
||||
move |x: &NumberInput| {
|
||||
let mut transform = transform;
|
||||
transform.translation.x = x.value.unwrap_or(transform.translation.x);
|
||||
TaggedValue::DAffine2(transform)
|
||||
},
|
||||
node_id,
|
||||
index,
|
||||
))
|
||||
.on_commit(commit_value)
|
||||
.widget_holder(),
|
||||
Separator::new(SeparatorType::Related).widget_holder(),
|
||||
NumberInput::new(Some(translation.y))
|
||||
.label("Y")
|
||||
.unit(" px")
|
||||
.on_update(update_value(
|
||||
move |y: &NumberInput| {
|
||||
let mut transform = transform;
|
||||
transform.translation.y = y.value.unwrap_or(transform.translation.y);
|
||||
TaggedValue::DAffine2(transform)
|
||||
},
|
||||
node_id,
|
||||
index,
|
||||
))
|
||||
.on_commit(commit_value)
|
||||
.widget_holder(),
|
||||
]);
|
||||
|
||||
rotation_widgets.extend_from_slice(&[NumberInput::new(Some(rotation.to_degrees()))
|
||||
.unit("°")
|
||||
.mode(NumberInputMode::Range)
|
||||
.range_min(Some(-180.))
|
||||
.range_max(Some(180.))
|
||||
.on_update(update_value(
|
||||
move |r: &NumberInput| {
|
||||
let transform = DAffine2::from_scale_angle_translation(scale, r.value.map(|r| r.to_radians()).unwrap_or(rotation), translation);
|
||||
TaggedValue::DAffine2(transform)
|
||||
},
|
||||
node_id,
|
||||
index,
|
||||
))
|
||||
.on_commit(commit_value)
|
||||
.widget_holder()]);
|
||||
|
||||
scale_widgets.extend_from_slice(&[
|
||||
NumberInput::new(Some(scale.x))
|
||||
.label("W")
|
||||
.unit("x")
|
||||
.on_update(update_value(
|
||||
move |w: &NumberInput| {
|
||||
let transform = DAffine2::from_scale_angle_translation(DVec2::new(w.value.unwrap_or(scale.x), scale.y), rotation, translation);
|
||||
TaggedValue::DAffine2(transform)
|
||||
},
|
||||
node_id,
|
||||
index,
|
||||
))
|
||||
.on_commit(commit_value)
|
||||
.widget_holder(),
|
||||
Separator::new(SeparatorType::Related).widget_holder(),
|
||||
NumberInput::new(Some(scale.y))
|
||||
.label("H")
|
||||
.unit("x")
|
||||
.on_update(update_value(
|
||||
move |h: &NumberInput| {
|
||||
let transform = DAffine2::from_scale_angle_translation(DVec2::new(scale.x, h.value.unwrap_or(scale.y)), rotation, translation);
|
||||
TaggedValue::DAffine2(transform)
|
||||
},
|
||||
node_id,
|
||||
index,
|
||||
))
|
||||
.on_commit(commit_value)
|
||||
.widget_holder(),
|
||||
]);
|
||||
|
||||
vec![
|
||||
LayoutGroup::Row { widgets: location_widgets },
|
||||
LayoutGroup::Row { widgets: rotation_widgets },
|
||||
LayoutGroup::Row { widgets: scale_widgets },
|
||||
]
|
||||
} else {
|
||||
vec![LayoutGroup::Row { widgets: location_widgets }]
|
||||
};
|
||||
|
||||
if let Some((last, rest)) = widgets.split_last() {
|
||||
*extra_widgets = rest.to_vec();
|
||||
last.clone()
|
||||
} else {
|
||||
LayoutGroup::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn coordinate_widget(parameter_widgets_info: ParameterWidgetsInfo, x: &str, y: &str, unit: &str, min: Option<f64>, is_integer: bool) -> LayoutGroup {
|
||||
let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info;
|
||||
|
||||
|
|
@ -1345,9 +1466,9 @@ pub(crate) fn rectangle_properties(node_id: NodeId, context: &mut NodeProperties
|
|||
|
||||
pub(crate) fn node_no_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
||||
let text = if context.network_interface.is_layer(&node_id, context.selection_network_path) {
|
||||
"Layer has no properties"
|
||||
"Layer has no parameters"
|
||||
} else {
|
||||
"Node has no properties"
|
||||
"Node has no parameters"
|
||||
};
|
||||
string_properties(text)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ impl FrontendGraphDataType {
|
|||
| TaggedValue::OptionalDVec2(_)
|
||||
| TaggedValue::F64Array4(_)
|
||||
| TaggedValue::VecF64(_)
|
||||
| TaggedValue::VecDVec2(_) => Self::Number,
|
||||
| TaggedValue::VecDVec2(_)
|
||||
| TaggedValue::DAffine2(_) => Self::Number,
|
||||
TaggedValue::GraphicGroup(_) | TaggedValue::GraphicElement(_) => Self::Group, // TODO: Is GraphicElement supposed to be included here?
|
||||
TaggedValue::ArtboardGroup(_) => Self::Artboard,
|
||||
_ => Self::General,
|
||||
|
|
|
|||
|
|
@ -100,6 +100,11 @@ impl From<RasterDataTable<GPU>> for GraphicGroupTable {
|
|||
Self::new(GraphicElement::RasterDataGPU(raster_data_table))
|
||||
}
|
||||
}
|
||||
impl From<DAffine2> for GraphicGroupTable {
|
||||
fn from(_: DAffine2) -> Self {
|
||||
GraphicGroupTable::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// The possible forms of graphical content held in a Vec by the `elements` field of [`GraphicElement`].
|
||||
#[derive(Clone, Debug, Hash, PartialEq, DynAny, serde::Serialize, serde::Deserialize)]
|
||||
|
|
@ -118,6 +123,12 @@ impl Default for GraphicElement {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<DAffine2> for GraphicElement {
|
||||
fn from(_: DAffine2) -> Self {
|
||||
GraphicElement::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl GraphicElement {
|
||||
pub fn as_group(&self) -> Option<&GraphicGroupTable> {
|
||||
match self {
|
||||
|
|
@ -351,6 +362,7 @@ async fn to_element<Data: Into<GraphicElement> + 'n>(
|
|||
VectorDataTable,
|
||||
RasterDataTable<CPU>,
|
||||
RasterDataTable<GPU>,
|
||||
DAffine2,
|
||||
)]
|
||||
data: Data,
|
||||
) -> GraphicElement {
|
||||
|
|
@ -463,6 +475,7 @@ async fn to_artboard<Data: Into<GraphicGroupTable> + 'n>(
|
|||
Context -> VectorDataTable,
|
||||
Context -> RasterDataTable<CPU>,
|
||||
Context -> RasterDataTable<GPU>,
|
||||
Context -> DAffine2,
|
||||
)]
|
||||
contents: impl Node<Context<'static>, Output = Data>,
|
||||
label: String,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::AlphaBlending;
|
||||
use crate::transform::ApplyTransform;
|
||||
use crate::uuid::NodeId;
|
||||
use dyn_any::StaticType;
|
||||
use glam::DAffine2;
|
||||
|
|
@ -136,6 +137,20 @@ impl<T: Hash> Hash for Instances<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> ApplyTransform for Instances<T> {
|
||||
fn apply_transform(&mut self, modification: &DAffine2) {
|
||||
for transform in &mut self.transform {
|
||||
*transform *= *modification;
|
||||
}
|
||||
}
|
||||
|
||||
fn left_apply_transform(&mut self, modification: &DAffine2) {
|
||||
for transform in &mut self.transform {
|
||||
*transform = *modification * *transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq> PartialEq for Instances<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.instance.len() == other.instance.len() && { self.instance.iter().zip(other.instance.iter()).all(|(a, b)| a == b) }
|
||||
|
|
|
|||
|
|
@ -6,14 +6,20 @@ use glam::{DAffine2, DMat2, DVec2};
|
|||
|
||||
pub trait Transform {
|
||||
fn transform(&self) -> DAffine2;
|
||||
|
||||
fn local_pivot(&self, pivot: DVec2) -> DVec2 {
|
||||
pivot
|
||||
}
|
||||
|
||||
fn decompose_scale(&self) -> DVec2 {
|
||||
DVec2::new(
|
||||
self.transform().transform_vector2((1., 0.).into()).length(),
|
||||
self.transform().transform_vector2((0., 1.).into()).length(),
|
||||
)
|
||||
DVec2::new(self.transform().transform_vector2(DVec2::X).length(), self.transform().transform_vector2(DVec2::Y).length())
|
||||
}
|
||||
|
||||
/// Requires that the transform does not contain any skew.
|
||||
fn decompose_rotation(&self) -> f64 {
|
||||
let rotation_matrix = (self.transform() * DAffine2::from_scale(self.decompose_scale().recip())).matrix2;
|
||||
let rotation = -rotation_matrix.mul_vec2(DVec2::X).angle_to(DVec2::X);
|
||||
if rotation == -0. { 0. } else { rotation }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -141,12 +147,21 @@ impl std::hash::Hash for Footprint {
|
|||
|
||||
pub trait ApplyTransform {
|
||||
fn apply_transform(&mut self, modification: &DAffine2);
|
||||
fn left_apply_transform(&mut self, modification: &DAffine2);
|
||||
}
|
||||
impl<T: TransformMut> ApplyTransform for T {
|
||||
fn apply_transform(&mut self, &modification: &DAffine2) {
|
||||
*self.transform_mut() = self.transform() * modification
|
||||
}
|
||||
fn left_apply_transform(&mut self, &modification: &DAffine2) {
|
||||
*self.transform_mut() = modification * self.transform()
|
||||
}
|
||||
}
|
||||
impl ApplyTransform for () {
|
||||
fn apply_transform(&mut self, &_modification: &DAffine2) {}
|
||||
impl ApplyTransform for DVec2 {
|
||||
fn apply_transform(&mut self, modification: &DAffine2) {
|
||||
*self = modification.transform_point2(*self);
|
||||
}
|
||||
fn left_apply_transform(&mut self, modification: &DAffine2) {
|
||||
*self = modification.inverse().transform_point2(*self);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,20 +7,22 @@ use core::f64;
|
|||
use glam::{DAffine2, DVec2};
|
||||
|
||||
#[node_macro::node(category(""))]
|
||||
async fn transform<T: 'n + 'static>(
|
||||
async fn transform<T: ApplyTransform + 'n + 'static>(
|
||||
ctx: impl Ctx + CloneVarArgs + ExtractAll,
|
||||
#[implementations(
|
||||
Context -> DAffine2,
|
||||
Context -> DVec2,
|
||||
Context -> VectorDataTable,
|
||||
Context -> GraphicGroupTable,
|
||||
Context -> RasterDataTable<CPU>,
|
||||
Context -> RasterDataTable<GPU>,
|
||||
)]
|
||||
transform_target: impl Node<Context<'static>, Output = Instances<T>>,
|
||||
value: impl Node<Context<'static>, Output = T>,
|
||||
translate: DVec2,
|
||||
rotate: f64,
|
||||
scale: DVec2,
|
||||
skew: DVec2,
|
||||
) -> Instances<T> {
|
||||
) -> T {
|
||||
let matrix = DAffine2::from_scale_angle_translation(scale, rotate, translate) * DAffine2::from_cols_array(&[1., skew.y, skew.x, 1., 0., 0.]);
|
||||
|
||||
let footprint = ctx.try_footprint().copied();
|
||||
|
|
@ -31,11 +33,9 @@ async fn transform<T: 'n + 'static>(
|
|||
ctx = ctx.with_footprint(footprint);
|
||||
}
|
||||
|
||||
let mut transform_target = transform_target.eval(ctx.into_context()).await;
|
||||
let mut transform_target = value.eval(ctx.into_context()).await;
|
||||
|
||||
for data_transform in transform_target.instance_mut_iter() {
|
||||
*data_transform.transform = matrix * *data_transform.transform;
|
||||
}
|
||||
transform_target.left_apply_transform(&matrix);
|
||||
|
||||
transform_target
|
||||
}
|
||||
|
|
@ -52,6 +52,40 @@ fn replace_transform<Data, TransformInput: Transform>(
|
|||
data
|
||||
}
|
||||
|
||||
#[node_macro::node(category("Math: Transform"), path(graphene_core::vector))]
|
||||
async fn extract_transform<T>(
|
||||
_: impl Ctx,
|
||||
#[implementations(
|
||||
GraphicGroupTable,
|
||||
VectorDataTable,
|
||||
RasterDataTable<CPU>,
|
||||
RasterDataTable<GPU>,
|
||||
)]
|
||||
vector_data: Instances<T>,
|
||||
) -> DAffine2 {
|
||||
vector_data.instance_ref_iter().next().map(|vector_data| *vector_data.transform).unwrap_or_default()
|
||||
}
|
||||
|
||||
#[node_macro::node(category("Math: Transform"))]
|
||||
fn invert_transform(_: impl Ctx, transform: DAffine2) -> DAffine2 {
|
||||
transform.inverse()
|
||||
}
|
||||
|
||||
#[node_macro::node(category("Math: Transform"))]
|
||||
fn decompose_translation(_: impl Ctx, transform: DAffine2) -> DVec2 {
|
||||
transform.translation
|
||||
}
|
||||
|
||||
#[node_macro::node(category("Math: Transform"))]
|
||||
fn decompose_rotation(_: impl Ctx, transform: DAffine2) -> f64 {
|
||||
transform.decompose_rotation()
|
||||
}
|
||||
|
||||
#[node_macro::node(category("Math: Transform"))]
|
||||
fn decompose_scale(_: impl Ctx, transform: DAffine2) -> DVec2 {
|
||||
transform.decompose_scale()
|
||||
}
|
||||
|
||||
#[node_macro::node(category("Debug"))]
|
||||
async fn boundless_footprint<T: 'n + 'static>(
|
||||
ctx: impl Ctx + CloneVarArgs + ExtractAll,
|
||||
|
|
|
|||
|
|
@ -418,7 +418,7 @@ impl Hash for VectorModification {
|
|||
}
|
||||
}
|
||||
|
||||
/// A node that applies a procedural modification to some [`VectorData`].
|
||||
/// Applies a diff modification to a vector path.
|
||||
#[node_macro::node(category(""))]
|
||||
async fn path_modify(_ctx: impl Ctx, mut vector_data: VectorDataTable, modification: Box<VectorModification>, node_path: Vec<NodeId>) -> VectorDataTable {
|
||||
if vector_data.is_empty() {
|
||||
|
|
@ -437,6 +437,23 @@ async fn path_modify(_ctx: impl Ctx, mut vector_data: VectorDataTable, modificat
|
|||
vector_data
|
||||
}
|
||||
|
||||
/// Applies the vector path's local transformation to its geometry and resets it to the identity.
|
||||
#[node_macro::node(category("Vector"))]
|
||||
async fn apply_transform(_ctx: impl Ctx, mut vector_data: VectorDataTable) -> VectorDataTable {
|
||||
for vector_data_instance in vector_data.instance_mut_iter() {
|
||||
let vector_data = vector_data_instance.instance;
|
||||
let transform = *vector_data_instance.transform;
|
||||
|
||||
for (_, point) in vector_data.point_domain.positions_mut() {
|
||||
*point = transform.transform_point2(*point);
|
||||
}
|
||||
|
||||
*vector_data_instance.transform = DAffine2::IDENTITY;
|
||||
}
|
||||
|
||||
vector_data
|
||||
}
|
||||
|
||||
// Do we want to enforce that all serialized/deserialized hashmaps are a vec of tuples?
|
||||
// TODO: Eventually remove this document upgrade code
|
||||
use serde::de::{SeqAccess, Visitor};
|
||||
|
|
|
|||
|
|
@ -1874,7 +1874,7 @@ fn bevel_algorithm(mut vector_data: VectorData, vector_data_transform: DAffine2,
|
|||
}
|
||||
|
||||
if segment_domain_length != sorted_segments.len() {
|
||||
for i in 0..segment_domain_length as usize {
|
||||
for i in 0..segment_domain_length {
|
||||
if !sorted_segments.contains(&i) {
|
||||
sorted_segments.push(i);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use glam::DVec2;
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphene_core::gradient::GradientStops;
|
||||
use graphene_core::registry::types::{Fraction, Percentage, TextArea};
|
||||
use graphene_core::registry::types::{Fraction, Percentage, PixelSize, TextArea};
|
||||
use graphene_core::transform::Footprint;
|
||||
use graphene_core::{Color, Ctx, num_traits};
|
||||
use log::warn;
|
||||
use math_parser::ast;
|
||||
|
|
@ -107,11 +108,11 @@ fn subtract<U: Sub<T>, T>(
|
|||
fn multiply<U: Mul<T>, T>(
|
||||
_: impl Ctx,
|
||||
/// The left-hand side of the multiplication operation.
|
||||
#[implementations(f64, f32, u32, DVec2, f64, DVec2)]
|
||||
#[implementations(f64, f32, u32, f64, DVec2, DVec2, DAffine2)]
|
||||
multiplier: U,
|
||||
/// The right-hand side of the multiplication operation.
|
||||
#[default(1.)]
|
||||
#[implementations(f64, f32, u32, DVec2, DVec2, f64)]
|
||||
#[implementations(f64, f32, u32, DVec2, f64, DVec2, DAffine2)]
|
||||
multiplicand: T,
|
||||
) -> <U as Mul<T>>::Output {
|
||||
multiplier * multiplicand
|
||||
|
|
@ -681,6 +682,16 @@ fn string_value(_: impl Ctx, _primary: (), string: TextArea) -> String {
|
|||
string
|
||||
}
|
||||
|
||||
/// Constructs a footprint value which may be set to any transformation of a unit square describing a render area, and a render resolution at least 1x1 integer pixels.
|
||||
#[node_macro::node(category("Value"))]
|
||||
fn footprint_value(_: impl Ctx, _primary: (), transform: DAffine2, #[default(100., 100.)] resolution: PixelSize) -> Footprint {
|
||||
Footprint {
|
||||
transform,
|
||||
resolution: resolution.max(DVec2::ONE).as_uvec2(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[node_macro::node(category("Math: Vector"))]
|
||||
fn dot_product(_: impl Ctx, vector_a: DVec2, vector_b: DVec2) -> f64 {
|
||||
vector_a.dot(vector_b)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use dyn_any::StaticType;
|
||||
use glam::{DVec2, IVec2, UVec2};
|
||||
use glam::{DAffine2, DVec2, IVec2, UVec2};
|
||||
use graph_craft::document::value::RenderOutput;
|
||||
use graph_craft::proto::{NodeConstructor, TypeErasedBox};
|
||||
use graphene_core::raster::color::Color;
|
||||
|
|
@ -52,6 +52,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => String]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => IVec2]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => DVec2]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => DAffine2]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => bool]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => f64]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => u32]),
|
||||
|
|
@ -166,7 +167,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||
|
||||
for (id, entry) in graphene_core::registry::NODE_REGISTRY.lock().unwrap().iter() {
|
||||
for (constructor, types) in entry.iter() {
|
||||
map.entry(id.clone().into()).or_default().insert(types.clone(), *constructor);
|
||||
map.entry(id.clone()).or_default().insert(types.clone(), *constructor);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue