mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-01 01:58:11 +08:00
Improve backwards compatability robustness of serde-based document format
This commit is contained in:
@@ -42,6 +42,7 @@ pub struct DocumentMessageData<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
pub struct DocumentMessageHandler {
|
pub struct DocumentMessageHandler {
|
||||||
// ======================
|
// ======================
|
||||||
// Child message handlers
|
// Child message handlers
|
||||||
@@ -62,44 +63,32 @@ pub struct DocumentMessageHandler {
|
|||||||
//
|
//
|
||||||
/// The node graph that generates this document's artwork.
|
/// The node graph that generates this document's artwork.
|
||||||
/// It recursively stores its sub-graphs, so this root graph is the whole snapshot of the document content.
|
/// It recursively stores its sub-graphs, so this root graph is the whole snapshot of the document content.
|
||||||
#[serde(default = "default_network")]
|
|
||||||
pub network: NodeNetwork,
|
pub network: NodeNetwork,
|
||||||
/// List of the [`NodeId`]s that are currently selected by the user.
|
/// List of the [`NodeId`]s that are currently selected by the user.
|
||||||
#[serde(default = "default_selected_nodes")]
|
|
||||||
pub selected_nodes: SelectedNodes,
|
pub selected_nodes: SelectedNodes,
|
||||||
/// List of the [`LayerNodeIdentifier`]s that are currently collapsed by the user in the Layers panel.
|
/// List of the [`LayerNodeIdentifier`]s that are currently collapsed by the user in the Layers panel.
|
||||||
/// Collapsed means that the expansion arrow isn't set to show the children of these layers.
|
/// Collapsed means that the expansion arrow isn't set to show the children of these layers.
|
||||||
#[serde(default = "default_collapsed")]
|
|
||||||
pub collapsed: CollapsedLayers,
|
pub collapsed: CollapsedLayers,
|
||||||
/// The name of the document, which is displayed in the tab and title bar of the editor.
|
/// The name of the document, which is displayed in the tab and title bar of the editor.
|
||||||
#[serde(default = "default_name")]
|
|
||||||
pub name: String,
|
pub name: String,
|
||||||
/// The full Git commit hash of the Graphite repository that was used to build the editor.
|
/// The full Git commit hash of the Graphite repository that was used to build the editor.
|
||||||
/// We save this to provide a hint about which version of the editor was used to create the document.
|
/// We save this to provide a hint about which version of the editor was used to create the document.
|
||||||
#[serde(default = "default_commit_hash")]
|
|
||||||
commit_hash: String,
|
commit_hash: String,
|
||||||
/// The current pan, tilt, and zoom state of the viewport's view of the document canvas.
|
/// The current pan, tilt, and zoom state of the viewport's view of the document canvas.
|
||||||
#[serde(default = "default_pan_tilt_zoom")]
|
|
||||||
pub navigation: PTZ,
|
pub navigation: PTZ,
|
||||||
/// The current mode that the document is in, which starts out as Design Mode. This choice affects the editing behavior of the tools.
|
/// The current mode that the document is in, which starts out as Design Mode. This choice affects the editing behavior of the tools.
|
||||||
#[serde(default = "default_document_mode")]
|
|
||||||
document_mode: DocumentMode,
|
document_mode: DocumentMode,
|
||||||
/// The current view mode that the user has set for rendering the document within the viewport.
|
/// The current view mode that the user has set for rendering the document within the viewport.
|
||||||
/// This is usually "Normal" but can be set to "Outline" or "Pixels" to see the canvas differently.
|
/// This is usually "Normal" but can be set to "Outline" or "Pixels" to see the canvas differently.
|
||||||
#[serde(default = "default_view_mode")]
|
|
||||||
pub view_mode: ViewMode,
|
pub view_mode: ViewMode,
|
||||||
/// Sets whether or not all the viewport overlays should be drawn on top of the artwork.
|
/// Sets whether or not all the viewport overlays should be drawn on top of the artwork.
|
||||||
/// This includes tool interaction visualizations (like the transform cage and path anchors/handles), the grid, and more.
|
/// This includes tool interaction visualizations (like the transform cage and path anchors/handles), the grid, and more.
|
||||||
#[serde(default = "default_overlays_visible")]
|
|
||||||
overlays_visible: bool,
|
overlays_visible: bool,
|
||||||
/// Sets whether or not the rulers should be drawn along the top and left edges of the viewport area.
|
/// Sets whether or not the rulers should be drawn along the top and left edges of the viewport area.
|
||||||
#[serde(default = "default_rulers_visible")]
|
|
||||||
pub rulers_visible: bool,
|
pub rulers_visible: bool,
|
||||||
/// Sets whether or not the node graph is drawn (as an overlay) on top of the viewport area, or otherwise if it's hidden.
|
/// Sets whether or not the node graph is drawn (as an overlay) on top of the viewport area, or otherwise if it's hidden.
|
||||||
#[serde(default = "default_graph_view_overlay_open")]
|
|
||||||
graph_view_overlay_open: bool,
|
graph_view_overlay_open: bool,
|
||||||
/// The current user choices for snapping behavior, including whether snapping is enabled at all.
|
/// The current user choices for snapping behavior, including whether snapping is enabled at all.
|
||||||
#[serde(default = "default_snapping_state")]
|
|
||||||
pub snapping_state: SnappingState,
|
pub snapping_state: SnappingState,
|
||||||
|
|
||||||
// =============================================
|
// =============================================
|
||||||
@@ -131,6 +120,45 @@ pub struct DocumentMessageHandler {
|
|||||||
pub metadata: DocumentMetadata,
|
pub metadata: DocumentMetadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for DocumentMessageHandler {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
// ======================
|
||||||
|
// Child message handlers
|
||||||
|
// ======================
|
||||||
|
navigation_handler: NavigationMessageHandler::default(),
|
||||||
|
node_graph_handler: NodeGraphMessageHandler::default(),
|
||||||
|
overlays_message_handler: OverlaysMessageHandler::default(),
|
||||||
|
properties_panel_message_handler: PropertiesPanelMessageHandler::default(),
|
||||||
|
// ============================================
|
||||||
|
// Fields that are saved in the document format
|
||||||
|
// ============================================
|
||||||
|
network: root_network(),
|
||||||
|
selected_nodes: SelectedNodes::default(),
|
||||||
|
collapsed: CollapsedLayers::default(),
|
||||||
|
name: DEFAULT_DOCUMENT_NAME.to_string(),
|
||||||
|
commit_hash: GRAPHITE_GIT_COMMIT_HASH.to_string(),
|
||||||
|
navigation: PTZ::default(),
|
||||||
|
document_mode: DocumentMode::DesignMode,
|
||||||
|
view_mode: ViewMode::default(),
|
||||||
|
overlays_visible: true,
|
||||||
|
rulers_visible: true,
|
||||||
|
graph_view_overlay_open: false,
|
||||||
|
snapping_state: SnappingState::default(),
|
||||||
|
// =============================================
|
||||||
|
// Fields omitted from the saved document format
|
||||||
|
// =============================================
|
||||||
|
document_undo_history: VecDeque::new(),
|
||||||
|
document_redo_history: VecDeque::new(),
|
||||||
|
saved_hash: None,
|
||||||
|
auto_saved_hash: None,
|
||||||
|
undo_in_progress: false,
|
||||||
|
layer_range_selection_reference: None,
|
||||||
|
metadata: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessageHandler {
|
impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessageHandler {
|
||||||
fn process_message(&mut self, message: DocumentMessage, responses: &mut VecDeque<Message>, data: DocumentMessageData) {
|
fn process_message(&mut self, message: DocumentMessage, responses: &mut VecDeque<Message>, data: DocumentMessageData) {
|
||||||
let DocumentMessageData {
|
let DocumentMessageData {
|
||||||
@@ -1913,94 +1941,6 @@ impl DocumentMessageHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for DocumentMessageHandler {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
// ======================
|
|
||||||
// Child message handlers
|
|
||||||
// ======================
|
|
||||||
navigation_handler: NavigationMessageHandler::default(),
|
|
||||||
node_graph_handler: NodeGraphMessageHandler::default(),
|
|
||||||
overlays_message_handler: OverlaysMessageHandler::default(),
|
|
||||||
properties_panel_message_handler: PropertiesPanelMessageHandler::default(),
|
|
||||||
// ============================================
|
|
||||||
// Fields that are saved in the document format
|
|
||||||
// ============================================
|
|
||||||
network: root_network(),
|
|
||||||
selected_nodes: SelectedNodes::default(),
|
|
||||||
collapsed: CollapsedLayers::default(),
|
|
||||||
name: DEFAULT_DOCUMENT_NAME.to_string(),
|
|
||||||
commit_hash: GRAPHITE_GIT_COMMIT_HASH.to_string(),
|
|
||||||
navigation: PTZ::default(),
|
|
||||||
document_mode: DocumentMode::DesignMode,
|
|
||||||
view_mode: ViewMode::default(),
|
|
||||||
overlays_visible: true,
|
|
||||||
rulers_visible: true,
|
|
||||||
// =============================================
|
|
||||||
// Fields omitted from the saved document format
|
|
||||||
// =============================================
|
|
||||||
document_undo_history: VecDeque::new(),
|
|
||||||
document_redo_history: VecDeque::new(),
|
|
||||||
saved_hash: None,
|
|
||||||
auto_saved_hash: None,
|
|
||||||
undo_in_progress: false,
|
|
||||||
graph_view_overlay_open: false,
|
|
||||||
snapping_state: SnappingState::default(),
|
|
||||||
layer_range_selection_reference: None,
|
|
||||||
metadata: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn default_network() -> NodeNetwork {
|
|
||||||
DocumentMessageHandler::default().network
|
|
||||||
}
|
|
||||||
#[inline(always)]
|
|
||||||
fn default_selected_nodes() -> SelectedNodes {
|
|
||||||
DocumentMessageHandler::default().selected_nodes
|
|
||||||
}
|
|
||||||
#[inline(always)]
|
|
||||||
fn default_collapsed() -> CollapsedLayers {
|
|
||||||
DocumentMessageHandler::default().collapsed
|
|
||||||
}
|
|
||||||
#[inline(always)]
|
|
||||||
fn default_name() -> String {
|
|
||||||
DocumentMessageHandler::default().name
|
|
||||||
}
|
|
||||||
#[inline(always)]
|
|
||||||
fn default_commit_hash() -> String {
|
|
||||||
DocumentMessageHandler::default().commit_hash
|
|
||||||
}
|
|
||||||
#[inline(always)]
|
|
||||||
fn default_pan_tilt_zoom() -> PTZ {
|
|
||||||
DocumentMessageHandler::default().navigation
|
|
||||||
}
|
|
||||||
#[inline(always)]
|
|
||||||
fn default_document_mode() -> DocumentMode {
|
|
||||||
DocumentMessageHandler::default().document_mode
|
|
||||||
}
|
|
||||||
#[inline(always)]
|
|
||||||
fn default_view_mode() -> ViewMode {
|
|
||||||
DocumentMessageHandler::default().view_mode
|
|
||||||
}
|
|
||||||
#[inline(always)]
|
|
||||||
fn default_overlays_visible() -> bool {
|
|
||||||
DocumentMessageHandler::default().overlays_visible
|
|
||||||
}
|
|
||||||
#[inline(always)]
|
|
||||||
fn default_rulers_visible() -> bool {
|
|
||||||
DocumentMessageHandler::default().rulers_visible
|
|
||||||
}
|
|
||||||
#[inline(always)]
|
|
||||||
fn default_graph_view_overlay_open() -> bool {
|
|
||||||
DocumentMessageHandler::default().graph_view_overlay_open
|
|
||||||
}
|
|
||||||
#[inline(always)]
|
|
||||||
fn default_snapping_state() -> SnappingState {
|
|
||||||
DocumentMessageHandler::default().snapping_state
|
|
||||||
}
|
|
||||||
|
|
||||||
fn root_network() -> NodeNetwork {
|
fn root_network() -> NodeNetwork {
|
||||||
{
|
{
|
||||||
let mut network = NodeNetwork::default();
|
let mut network = NodeNetwork::default();
|
||||||
|
|||||||
@@ -356,19 +356,6 @@ fn number_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, na
|
|||||||
.on_commit(commit_value)
|
.on_commit(commit_value)
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
])
|
])
|
||||||
} else if let NodeInput::Value {
|
|
||||||
tagged_value: TaggedValue::F32(x),
|
|
||||||
exposed: false,
|
|
||||||
} = document_node.inputs[index]
|
|
||||||
{
|
|
||||||
widgets.extend_from_slice(&[
|
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
|
||||||
number_props
|
|
||||||
.value(Some(x as f64))
|
|
||||||
.on_update(update_value(move |x: &NumberInput| TaggedValue::F32((x.value.unwrap()) as f32), node_id, index))
|
|
||||||
.on_commit(commit_value)
|
|
||||||
.widget_holder(),
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
widgets
|
widgets
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ impl FrontendGraphDataType {
|
|||||||
pub const fn with_tagged_value(value: &TaggedValue) -> Self {
|
pub const fn with_tagged_value(value: &TaggedValue) -> Self {
|
||||||
match value {
|
match value {
|
||||||
TaggedValue::String(_) => Self::Text,
|
TaggedValue::String(_) => Self::Text,
|
||||||
TaggedValue::F32(_) | TaggedValue::F64(_) | TaggedValue::U32(_) | TaggedValue::DAffine2(_) => Self::Number,
|
TaggedValue::F64(_) | TaggedValue::U32(_) | TaggedValue::DAffine2(_) => Self::Number,
|
||||||
TaggedValue::Bool(_) => Self::Boolean,
|
TaggedValue::Bool(_) => Self::Boolean,
|
||||||
TaggedValue::DVec2(_) | TaggedValue::IVec2(_) => Self::Vector,
|
TaggedValue::DVec2(_) | TaggedValue::IVec2(_) => Self::Vector,
|
||||||
TaggedValue::Image(_) => Self::Raster,
|
TaggedValue::Image(_) => Self::Raster,
|
||||||
|
|||||||
@@ -56,8 +56,9 @@ impl DocumentMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
|
||||||
/// SnappingState determines the current individual snapping states
|
/// SnappingState determines the current individual snapping states
|
||||||
|
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
pub struct SnappingState {
|
pub struct SnappingState {
|
||||||
pub snapping_enabled: bool,
|
pub snapping_enabled: bool,
|
||||||
pub grid_snapping: bool,
|
pub grid_snapping: bool,
|
||||||
@@ -67,39 +68,21 @@ pub struct SnappingState {
|
|||||||
pub tolerance: f64,
|
pub tolerance: f64,
|
||||||
pub artboards: bool,
|
pub artboards: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SnappingState {
|
impl Default for SnappingState {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
snapping_enabled: true,
|
snapping_enabled: true,
|
||||||
grid_snapping: false,
|
grid_snapping: false,
|
||||||
bounds: BoundsSnapping {
|
bounds: Default::default(),
|
||||||
edges: true,
|
nodes: Default::default(),
|
||||||
corners: true,
|
grid: Default::default(),
|
||||||
edge_midpoints: false,
|
|
||||||
centers: true,
|
|
||||||
},
|
|
||||||
nodes: PointSnapping {
|
|
||||||
paths: true,
|
|
||||||
path_intersections: true,
|
|
||||||
anchors: true,
|
|
||||||
line_midpoints: true,
|
|
||||||
normals: true,
|
|
||||||
tangents: true,
|
|
||||||
},
|
|
||||||
grid: GridSnapping {
|
|
||||||
origin: DVec2::ZERO,
|
|
||||||
grid_type: GridType::RECTANGLE,
|
|
||||||
grid_color: COLOR_OVERLAY_GRAY
|
|
||||||
.strip_prefix("#")
|
|
||||||
.and_then(|value| Color::from_rgb_str(value))
|
|
||||||
.expect("Should create Color from prefixed hex string"),
|
|
||||||
dot_display: false,
|
|
||||||
},
|
|
||||||
tolerance: 8.,
|
tolerance: 8.,
|
||||||
artboards: true,
|
artboards: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SnappingState {
|
impl SnappingState {
|
||||||
pub const fn target_enabled(&self, target: SnapTarget) -> bool {
|
pub const fn target_enabled(&self, target: SnapTarget) -> bool {
|
||||||
if !self.snapping_enabled {
|
if !self.snapping_enabled {
|
||||||
@@ -127,13 +110,27 @@ impl SnappingState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
pub struct BoundsSnapping {
|
pub struct BoundsSnapping {
|
||||||
pub edges: bool,
|
pub edges: bool,
|
||||||
pub corners: bool,
|
pub corners: bool,
|
||||||
pub edge_midpoints: bool,
|
pub edge_midpoints: bool,
|
||||||
pub centers: bool,
|
pub centers: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for BoundsSnapping {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
edges: true,
|
||||||
|
corners: true,
|
||||||
|
edge_midpoints: false,
|
||||||
|
centers: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct OptionBoundsSnapping {
|
pub struct OptionBoundsSnapping {
|
||||||
pub edges: Option<bool>,
|
pub edges: Option<bool>,
|
||||||
@@ -141,7 +138,9 @@ pub struct OptionBoundsSnapping {
|
|||||||
pub edge_midpoints: Option<bool>,
|
pub edge_midpoints: Option<bool>,
|
||||||
pub centers: Option<bool>,
|
pub centers: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
pub struct PointSnapping {
|
pub struct PointSnapping {
|
||||||
pub paths: bool,
|
pub paths: bool,
|
||||||
pub path_intersections: bool,
|
pub path_intersections: bool,
|
||||||
@@ -150,6 +149,20 @@ pub struct PointSnapping {
|
|||||||
pub normals: bool,
|
pub normals: bool,
|
||||||
pub tangents: bool,
|
pub tangents: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for PointSnapping {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
paths: true,
|
||||||
|
path_intersections: true,
|
||||||
|
anchors: true,
|
||||||
|
line_midpoints: true,
|
||||||
|
normals: true,
|
||||||
|
tangents: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
|
#[derive(PartialEq, Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct OptionPointSnapping {
|
pub struct OptionPointSnapping {
|
||||||
pub paths: Option<bool>,
|
pub paths: Option<bool>,
|
||||||
@@ -159,11 +172,19 @@ pub struct OptionPointSnapping {
|
|||||||
pub normals: Option<bool>,
|
pub normals: Option<bool>,
|
||||||
pub tangents: Option<bool>,
|
pub tangents: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize, PartialEq)]
|
#[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize, PartialEq)]
|
||||||
pub enum GridType {
|
pub enum GridType {
|
||||||
Rectangle { spacing: DVec2 },
|
Rectangle { spacing: DVec2 },
|
||||||
Isometric { y_axis_spacing: f64, angle_a: f64, angle_b: f64 },
|
Isometric { y_axis_spacing: f64, angle_a: f64, angle_b: f64 },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for GridType {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::RECTANGLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl GridType {
|
impl GridType {
|
||||||
pub const RECTANGLE: Self = GridType::Rectangle { spacing: DVec2::ONE };
|
pub const RECTANGLE: Self = GridType::Rectangle { spacing: DVec2::ONE };
|
||||||
pub const ISOMETRIC: Self = GridType::Isometric {
|
pub const ISOMETRIC: Self = GridType::Isometric {
|
||||||
@@ -196,13 +217,30 @@ impl GridType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq)]
|
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq)]
|
||||||
|
#[serde(default)]
|
||||||
pub struct GridSnapping {
|
pub struct GridSnapping {
|
||||||
pub origin: DVec2,
|
pub origin: DVec2,
|
||||||
pub grid_type: GridType,
|
pub grid_type: GridType,
|
||||||
pub grid_color: Color,
|
pub grid_color: Color,
|
||||||
pub dot_display: bool,
|
pub dot_display: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for GridSnapping {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
origin: DVec2::ZERO,
|
||||||
|
grid_type: Default::default(),
|
||||||
|
grid_color: COLOR_OVERLAY_GRAY
|
||||||
|
.strip_prefix("#")
|
||||||
|
.and_then(|value| Color::from_rgb_str(value))
|
||||||
|
.expect("Should create Color from prefixed hex string"),
|
||||||
|
dot_display: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl GridSnapping {
|
impl GridSnapping {
|
||||||
// Double grid size until it takes up at least 10px.
|
// Double grid size until it takes up at least 10px.
|
||||||
pub fn compute_rectangle_spacing(mut size: DVec2, navigation: &PTZ) -> Option<DVec2> {
|
pub fn compute_rectangle_spacing(mut size: DVec2, navigation: &PTZ) -> Option<DVec2> {
|
||||||
@@ -240,11 +278,13 @@ pub enum BoundingBoxSnapSource {
|
|||||||
Corner,
|
Corner,
|
||||||
EdgeMidpoint,
|
EdgeMidpoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum BoardSnapSource {
|
pub enum BoardSnapSource {
|
||||||
Center,
|
Center,
|
||||||
Corner,
|
Corner,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum GeometrySnapSource {
|
pub enum GeometrySnapSource {
|
||||||
AnchorWithColinearHandles,
|
AnchorWithColinearHandles,
|
||||||
@@ -253,6 +293,7 @@ pub enum GeometrySnapSource {
|
|||||||
LineMidpoint,
|
LineMidpoint,
|
||||||
Intersection,
|
Intersection,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum SnapSource {
|
pub enum SnapSource {
|
||||||
#[default]
|
#[default]
|
||||||
@@ -261,6 +302,7 @@ pub enum SnapSource {
|
|||||||
Board(BoardSnapSource),
|
Board(BoardSnapSource),
|
||||||
Geometry(GeometrySnapSource),
|
Geometry(GeometrySnapSource),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SnapSource {
|
impl SnapSource {
|
||||||
pub fn is_some(&self) -> bool {
|
pub fn is_some(&self) -> bool {
|
||||||
self != &Self::None
|
self != &Self::None
|
||||||
@@ -269,6 +311,7 @@ impl SnapSource {
|
|||||||
matches!(self, Self::BoundingBox(_) | Self::Board(_))
|
matches!(self, Self::BoundingBox(_) | Self::Board(_))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum BoundingBoxSnapTarget {
|
pub enum BoundingBoxSnapTarget {
|
||||||
Center,
|
Center,
|
||||||
@@ -319,12 +362,14 @@ pub enum BoardSnapTarget {
|
|||||||
Corner,
|
Corner,
|
||||||
Center,
|
Center,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum GridSnapTarget {
|
pub enum GridSnapTarget {
|
||||||
Line,
|
Line,
|
||||||
LineNormal,
|
LineNormal,
|
||||||
Intersection,
|
Intersection,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum SnapTarget {
|
pub enum SnapTarget {
|
||||||
#[default]
|
#[default]
|
||||||
@@ -334,6 +379,7 @@ pub enum SnapTarget {
|
|||||||
Board(BoardSnapTarget),
|
Board(BoardSnapTarget),
|
||||||
Grid(GridSnapTarget),
|
Grid(GridSnapTarget),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SnapTarget {
|
impl SnapTarget {
|
||||||
pub fn is_some(&self) -> bool {
|
pub fn is_some(&self) -> bool {
|
||||||
self != &Self::None
|
self != &Self::None
|
||||||
@@ -342,6 +388,7 @@ impl SnapTarget {
|
|||||||
matches!(self, Self::BoundingBox(_) | Self::Board(_))
|
matches!(self, Self::BoundingBox(_) | Self::Board(_))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement icons for SnappingOptions eventually
|
// TODO: implement icons for SnappingOptions eventually
|
||||||
pub enum SnappingOptions {
|
pub enum SnappingOptions {
|
||||||
BoundingBoxes,
|
BoundingBoxes,
|
||||||
@@ -358,9 +405,11 @@ impl fmt::Display for SnappingOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
pub struct PTZ {
|
pub struct PTZ {
|
||||||
pub pan: DVec2,
|
pub pan: DVec2,
|
||||||
pub tilt: f64,
|
pub tilt: f64,
|
||||||
|
// TODO: Make this private and add getter/setter methods which ensure zoom is always positive and greater than the smallest zoom level in `VIEWPORT_ZOOM_LEVELS`.
|
||||||
pub zoom: f64,
|
pub zoom: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -637,7 +637,6 @@ impl NodeGraphExecutor {
|
|||||||
}
|
}
|
||||||
TaggedValue::Bool(render_object) => Self::debug_render(render_object, transform, responses),
|
TaggedValue::Bool(render_object) => Self::debug_render(render_object, transform, responses),
|
||||||
TaggedValue::String(render_object) => Self::debug_render(render_object, transform, responses),
|
TaggedValue::String(render_object) => Self::debug_render(render_object, transform, responses),
|
||||||
TaggedValue::F32(render_object) => Self::debug_render(render_object, transform, responses),
|
|
||||||
TaggedValue::F64(render_object) => Self::debug_render(render_object, transform, responses),
|
TaggedValue::F64(render_object) => Self::debug_render(render_object, transform, responses),
|
||||||
TaggedValue::OptionalColor(render_object) => Self::debug_render(render_object, transform, responses),
|
TaggedValue::OptionalColor(render_object) => Self::debug_render(render_object, transform, responses),
|
||||||
TaggedValue::VectorData(render_object) => Self::debug_render(render_object, transform, responses),
|
TaggedValue::VectorData(render_object) => Self::debug_render(render_object, transform, responses),
|
||||||
|
|||||||
@@ -100,7 +100,11 @@
|
|||||||
const categories = new Map<string, NodeCategoryDetails>();
|
const categories = new Map<string, NodeCategoryDetails>();
|
||||||
|
|
||||||
nodeTypes.forEach((node) => {
|
nodeTypes.forEach((node) => {
|
||||||
const nameIncludesSearchTerm = node.name.toLowerCase().includes(searchTerm.toLowerCase());
|
let nameIncludesSearchTerm = node.name.toLowerCase().includes(searchTerm.toLowerCase());
|
||||||
|
// Quick and dirty hack to alias "Layer" to "Merge" in the search
|
||||||
|
if (node.name === "Merge") {
|
||||||
|
nameIncludesSearchTerm = nameIncludesSearchTerm || "Layer".toLowerCase().includes(searchTerm.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
if (searchTerm.length > 0 && !nameIncludesSearchTerm && !node.category.toLowerCase().includes(searchTerm.toLowerCase())) {
|
if (searchTerm.length > 0 && !nameIncludesSearchTerm && !node.category.toLowerCase().includes(searchTerm.toLowerCase())) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ fn add_network() -> NodeNetwork {
|
|||||||
}},
|
}},
|
||||||
))"#,
|
))"#,
|
||||||
TaggedValue::BlendMode(BlendMode::Normal).to_primitive_string(),
|
TaggedValue::BlendMode(BlendMode::Normal).to_primitive_string(),
|
||||||
TaggedValue::F32(1.0).to_primitive_string(),
|
TaggedValue::F64(1.).to_primitive_string(),
|
||||||
),
|
),
|
||||||
concrete![Color],
|
concrete![Color],
|
||||||
))],
|
))],
|
||||||
|
|||||||
@@ -80,12 +80,25 @@ pub struct ProtoNodeIdentifier {
|
|||||||
pub name: Cow<'static, str>,
|
pub name: Cow<'static, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn migrate_type_descriptor_names<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<Cow<'static, str>, D::Error> {
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
// Rename "f32" to "f64"
|
||||||
|
let name = String::deserialize(deserializer)?;
|
||||||
|
let name = match name.as_str() {
|
||||||
|
"f32" => "f64".to_string(),
|
||||||
|
_ => name,
|
||||||
|
};
|
||||||
|
Ok(Cow::Owned(name))
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, specta::Type)]
|
#[derive(Clone, Debug, Eq, specta::Type)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct TypeDescriptor {
|
pub struct TypeDescriptor {
|
||||||
#[cfg_attr(feature = "serde", serde(skip))]
|
#[cfg_attr(feature = "serde", serde(skip))]
|
||||||
#[specta(skip)]
|
#[specta(skip)]
|
||||||
pub id: Option<TypeId>,
|
pub id: Option<TypeId>,
|
||||||
|
#[serde(deserialize_with = "migrate_type_descriptor_names")]
|
||||||
pub name: Cow<'static, str>,
|
pub name: Cow<'static, str>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub size: usize,
|
pub size: usize,
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ use crate::proto::{ConstructionArgs, ProtoNetwork, ProtoNode, ProtoNodeInput};
|
|||||||
|
|
||||||
use dyn_any::{DynAny, StaticType};
|
use dyn_any::{DynAny, StaticType};
|
||||||
pub use graphene_core::uuid::generate_uuid;
|
pub use graphene_core::uuid::generate_uuid;
|
||||||
use graphene_core::vector::VectorData;
|
use graphene_core::{ProtoNodeIdentifier, Type};
|
||||||
use graphene_core::{ArtboardGroup, GraphicGroup, ProtoNodeIdentifier, Type};
|
|
||||||
|
|
||||||
use glam::IVec2;
|
use glam::IVec2;
|
||||||
use std::collections::hash_map::DefaultHasher;
|
use std::collections::hash_map::DefaultHasher;
|
||||||
@@ -51,6 +50,15 @@ fn return_true() -> bool {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Eventually remove this (probably starting late 2024)
|
||||||
|
fn migrate_layer_to_merge<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<String, D::Error> {
|
||||||
|
let mut s: String = serde::Deserialize::deserialize(deserializer)?;
|
||||||
|
if s == "Layer" {
|
||||||
|
s = "Merge".to_string();
|
||||||
|
}
|
||||||
|
Ok(s)
|
||||||
|
}
|
||||||
|
|
||||||
/// An instance of a [`DocumentNodeDefinition`] that has been instantiated in a [`NodeNetwork`].
|
/// An instance of a [`DocumentNodeDefinition`] that has been instantiated in a [`NodeNetwork`].
|
||||||
/// Currently, when an instance is made, it lives all on its own without any lasting connection to the definition.
|
/// Currently, when an instance is made, it lives all on its own without any lasting connection to the definition.
|
||||||
/// But we will want to change it in the future so it merely references its definition.
|
/// But we will want to change it in the future so it merely references its definition.
|
||||||
@@ -62,6 +70,7 @@ pub struct DocumentNode {
|
|||||||
pub alias: String,
|
pub alias: String,
|
||||||
// TODO: Replace this name with a reference to the [`DocumentNodeDefinition`] node definition to use the name from there instead.
|
// TODO: Replace this name with a reference to the [`DocumentNodeDefinition`] node definition to use the name from there instead.
|
||||||
/// The name of the node definition, as originally set by [`DocumentNodeDefinition`], used to display in the UI and to display the appropriate properties.
|
/// The name of the node definition, as originally set by [`DocumentNodeDefinition`], used to display in the UI and to display the appropriate properties.
|
||||||
|
#[serde(deserialize_with = "migrate_layer_to_merge")]
|
||||||
pub name: String,
|
pub name: String,
|
||||||
/// The inputs to a node, which are either:
|
/// The inputs to a node, which are either:
|
||||||
/// - From other nodes within this graph [`NodeInput::Node`],
|
/// - From other nodes within this graph [`NodeInput::Node`],
|
||||||
@@ -467,6 +476,7 @@ pub enum DocumentNodeImplementation {
|
|||||||
/// This describes a (document) node implemented as a proto node.
|
/// This describes a (document) node implemented as a proto node.
|
||||||
///
|
///
|
||||||
/// A proto node identifier which can be found in `node_registry.rs`.
|
/// A proto node identifier which can be found in `node_registry.rs`.
|
||||||
|
#[serde(alias = "Unresolved")] // TODO: Eventually remove this alias (probably starting late 2024)
|
||||||
ProtoNode(ProtoNodeIdentifier),
|
ProtoNode(ProtoNodeIdentifier),
|
||||||
/// The Extract variant is a tag which tells the compilation process to do something special. It invokes language-level functionality built for use by the ExtractNode to enable metaprogramming.
|
/// The Extract variant is a tag which tells the compilation process to do something special. It invokes language-level functionality built for use by the ExtractNode to enable metaprogramming.
|
||||||
/// When the ExtractNode is compiled, it gets replaced by a value node containing a representation of the source code for the function/lambda of the document node that's fed into the ExtractNode
|
/// When the ExtractNode is compiled, it gets replaced by a value node containing a representation of the source code for the function/lambda of the document node that's fed into the ExtractNode
|
||||||
@@ -536,12 +546,15 @@ pub struct NodeNetwork {
|
|||||||
/// The list of nodes that are imported into this network from the parent network.
|
/// The list of nodes that are imported into this network from the parent network.
|
||||||
/// Each import is a reference to which node within this network that the input is connected to.
|
/// Each import is a reference to which node within this network that the input is connected to.
|
||||||
/// Presently, only one is supported— use an Identity node to split an input to multiple user nodes (although this could, and should, be changed in the future).
|
/// Presently, only one is supported— use an Identity node to split an input to multiple user nodes (although this could, and should, be changed in the future).
|
||||||
|
#[serde(alias = "inputs")] // TODO: Eventually remove this alias (probably starting late 2024)
|
||||||
pub imports: Vec<NodeId>,
|
pub imports: Vec<NodeId>,
|
||||||
/// The list of data outputs that are exported from this network to the parent network.
|
/// The list of data outputs that are exported from this network to the parent network.
|
||||||
/// Each export is a reference to a node within this network, paired with its output index, that is the source of the network's exported data.
|
/// Each export is a reference to a node within this network, paired with its output index, that is the source of the network's exported data.
|
||||||
|
#[serde(alias = "outputs")] // TODO: Eventually remove this alias (probably starting late 2024)
|
||||||
pub exports: Vec<NodeOutput>,
|
pub exports: Vec<NodeOutput>,
|
||||||
/// The list of all nodes in this network.
|
/// The list of all nodes in this network.
|
||||||
pub nodes: HashMap<NodeId, DocumentNode>,
|
pub nodes: HashMap<NodeId, DocumentNode>,
|
||||||
|
#[serde(skip)]
|
||||||
/// In the case when another node is previewed (chosen by the user as a temporary output), this stores what it previously was so it can be restored later.
|
/// In the case when another node is previewed (chosen by the user as a temporary output), this stores what it previously was so it can be restored later.
|
||||||
pub previous_outputs: Option<Vec<NodeOutput>>,
|
pub previous_outputs: Option<Vec<NodeOutput>>,
|
||||||
}
|
}
|
||||||
@@ -1536,7 +1549,7 @@ mod test {
|
|||||||
NodeId(1),
|
NodeId(1),
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
name: "Nested network".into(),
|
name: "Nested network".into(),
|
||||||
inputs: vec![NodeInput::value(TaggedValue::F32(1.), false), NodeInput::value(TaggedValue::F32(2.), false)],
|
inputs: vec![NodeInput::value(TaggedValue::F64(1.), false), NodeInput::value(TaggedValue::F64(2.), false)],
|
||||||
implementation: DocumentNodeImplementation::Network(two_node_identity()),
|
implementation: DocumentNodeImplementation::Network(two_node_identity()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ pub enum TaggedValue {
|
|||||||
String(String),
|
String(String),
|
||||||
U32(u32),
|
U32(u32),
|
||||||
U64(u64),
|
U64(u64),
|
||||||
F32(f32),
|
#[serde(alias = "F32")] // TODO: Eventually remove this alias (probably starting late 2024)
|
||||||
F64(f64),
|
F64(f64),
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
UVec2(UVec2),
|
UVec2(UVec2),
|
||||||
@@ -43,6 +43,7 @@ pub enum TaggedValue {
|
|||||||
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]),
|
||||||
|
#[serde(alias = "VecF32")] // TODO: Eventually remove this alias (probably starting late 2024)
|
||||||
VecF64(Vec<f64>),
|
VecF64(Vec<f64>),
|
||||||
VecDVec2(Vec<DVec2>),
|
VecDVec2(Vec<DVec2>),
|
||||||
RedGreenBlue(graphene_core::raster::RedGreenBlue),
|
RedGreenBlue(graphene_core::raster::RedGreenBlue),
|
||||||
@@ -87,7 +88,6 @@ impl Hash for TaggedValue {
|
|||||||
Self::String(x) => x.hash(state),
|
Self::String(x) => x.hash(state),
|
||||||
Self::U32(x) => x.hash(state),
|
Self::U32(x) => x.hash(state),
|
||||||
Self::U64(x) => x.hash(state),
|
Self::U64(x) => x.hash(state),
|
||||||
Self::F32(x) => x.to_bits().hash(state),
|
|
||||||
Self::F64(x) => x.to_bits().hash(state),
|
Self::F64(x) => x.to_bits().hash(state),
|
||||||
Self::Bool(x) => x.hash(state),
|
Self::Bool(x) => x.hash(state),
|
||||||
Self::UVec2(x) => x.to_array().iter().for_each(|x| x.hash(state)),
|
Self::UVec2(x) => x.to_array().iter().for_each(|x| x.hash(state)),
|
||||||
@@ -168,7 +168,6 @@ impl<'a> TaggedValue {
|
|||||||
TaggedValue::String(x) => Box::new(x),
|
TaggedValue::String(x) => Box::new(x),
|
||||||
TaggedValue::U32(x) => Box::new(x),
|
TaggedValue::U32(x) => Box::new(x),
|
||||||
TaggedValue::U64(x) => Box::new(x),
|
TaggedValue::U64(x) => Box::new(x),
|
||||||
TaggedValue::F32(x) => Box::new(x),
|
|
||||||
TaggedValue::F64(x) => Box::new(x),
|
TaggedValue::F64(x) => Box::new(x),
|
||||||
TaggedValue::Bool(x) => Box::new(x),
|
TaggedValue::Bool(x) => Box::new(x),
|
||||||
TaggedValue::UVec2(x) => Box::new(x),
|
TaggedValue::UVec2(x) => Box::new(x),
|
||||||
@@ -232,7 +231,6 @@ impl<'a> TaggedValue {
|
|||||||
TaggedValue::String(x) => format!("\"{x}\""),
|
TaggedValue::String(x) => format!("\"{x}\""),
|
||||||
TaggedValue::U32(x) => x.to_string() + "_u32",
|
TaggedValue::U32(x) => x.to_string() + "_u32",
|
||||||
TaggedValue::U64(x) => x.to_string() + "_u64",
|
TaggedValue::U64(x) => x.to_string() + "_u64",
|
||||||
TaggedValue::F32(x) => x.to_string() + "_f32",
|
|
||||||
TaggedValue::F64(x) => x.to_string() + "_f64",
|
TaggedValue::F64(x) => x.to_string() + "_f64",
|
||||||
TaggedValue::Bool(x) => x.to_string(),
|
TaggedValue::Bool(x) => x.to_string(),
|
||||||
TaggedValue::BlendMode(x) => "BlendMode::".to_string() + &x.to_string(),
|
TaggedValue::BlendMode(x) => "BlendMode::".to_string() + &x.to_string(),
|
||||||
@@ -247,7 +245,6 @@ impl<'a> TaggedValue {
|
|||||||
TaggedValue::String(_) => concrete!(String),
|
TaggedValue::String(_) => concrete!(String),
|
||||||
TaggedValue::U32(_) => concrete!(u32),
|
TaggedValue::U32(_) => concrete!(u32),
|
||||||
TaggedValue::U64(_) => concrete!(u64),
|
TaggedValue::U64(_) => concrete!(u64),
|
||||||
TaggedValue::F32(_) => concrete!(f32),
|
|
||||||
TaggedValue::F64(_) => concrete!(f64),
|
TaggedValue::F64(_) => concrete!(f64),
|
||||||
TaggedValue::Bool(_) => concrete!(bool),
|
TaggedValue::Bool(_) => concrete!(bool),
|
||||||
TaggedValue::UVec2(_) => concrete!(UVec2),
|
TaggedValue::UVec2(_) => concrete!(UVec2),
|
||||||
@@ -314,7 +311,6 @@ impl<'a> TaggedValue {
|
|||||||
x if x == TypeId::of::<String>() => Ok(TaggedValue::String(*downcast(input).unwrap())),
|
x if x == TypeId::of::<String>() => Ok(TaggedValue::String(*downcast(input).unwrap())),
|
||||||
x if x == TypeId::of::<u32>() => Ok(TaggedValue::U32(*downcast(input).unwrap())),
|
x if x == TypeId::of::<u32>() => Ok(TaggedValue::U32(*downcast(input).unwrap())),
|
||||||
x if x == TypeId::of::<u64>() => Ok(TaggedValue::U64(*downcast(input).unwrap())),
|
x if x == TypeId::of::<u64>() => Ok(TaggedValue::U64(*downcast(input).unwrap())),
|
||||||
x if x == TypeId::of::<f32>() => Ok(TaggedValue::F32(*downcast(input).unwrap())),
|
|
||||||
x if x == TypeId::of::<f64>() => Ok(TaggedValue::F64(*downcast(input).unwrap())),
|
x if x == TypeId::of::<f64>() => Ok(TaggedValue::F64(*downcast(input).unwrap())),
|
||||||
x if x == TypeId::of::<bool>() => Ok(TaggedValue::Bool(*downcast(input).unwrap())),
|
x if x == TypeId::of::<bool>() => Ok(TaggedValue::Bool(*downcast(input).unwrap())),
|
||||||
x if x == TypeId::of::<UVec2>() => Ok(TaggedValue::UVec2(*downcast(input).unwrap())),
|
x if x == TypeId::of::<UVec2>() => Ok(TaggedValue::UVec2(*downcast(input).unwrap())),
|
||||||
|
|||||||
@@ -421,7 +421,7 @@ pub struct BlendGpuImageNode<Background, B, O> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(BlendGpuImageNode)]
|
#[node_macro::node_fn(BlendGpuImageNode)]
|
||||||
async fn blend_gpu_image(foreground: ImageFrame<Color>, background: ImageFrame<Color>, blend_mode: BlendMode, opacity: f32) -> ImageFrame<Color> {
|
async fn blend_gpu_image(foreground: ImageFrame<Color>, background: ImageFrame<Color>, blend_mode: BlendMode, opacity: f64) -> ImageFrame<Color> {
|
||||||
let foreground_size = DVec2::new(foreground.image.width as f64, foreground.image.height as f64);
|
let foreground_size = DVec2::new(foreground.image.width as f64, foreground.image.height as f64);
|
||||||
let background_size = DVec2::new(background.image.width as f64, background.image.height as f64);
|
let background_size = DVec2::new(background.image.width as f64, background.image.height as f64);
|
||||||
// Transforms a point from the background image to the foreground image
|
// Transforms a point from the background image to the foreground image
|
||||||
@@ -457,7 +457,7 @@ async fn blend_gpu_image(foreground: ImageFrame<Color>, background: ImageFrame<C
|
|||||||
i1[(_global_index.y * i0 + _global_index.x) as usize],
|
i1[(_global_index.y * i0 + _global_index.x) as usize],
|
||||||
))"#,
|
))"#,
|
||||||
TaggedValue::BlendMode(blend_mode).to_primitive_string(),
|
TaggedValue::BlendMode(blend_mode).to_primitive_string(),
|
||||||
TaggedValue::F32(opacity).to_primitive_string(),
|
TaggedValue::F64(opacity).to_primitive_string(),
|
||||||
),
|
),
|
||||||
concrete![Color],
|
concrete![Color],
|
||||||
))],
|
))],
|
||||||
|
|||||||
@@ -419,7 +419,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let background: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0].clone());
|
let background: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0].clone());
|
||||||
let blend_mode: DowncastBothNode<(), BlendMode> = DowncastBothNode::new(args[1].clone());
|
let blend_mode: DowncastBothNode<(), BlendMode> = DowncastBothNode::new(args[1].clone());
|
||||||
let opacity: DowncastBothNode<(), f32> = DowncastBothNode::new(args[2].clone());
|
let opacity: DowncastBothNode<(), f64> = DowncastBothNode::new(args[2].clone());
|
||||||
let node = graphene_std::gpu_nodes::BlendGpuImageNode::new(background, blend_mode, opacity);
|
let node = graphene_std::gpu_nodes::BlendGpuImageNode::new(background, blend_mode, opacity);
|
||||||
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(node);
|
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(node);
|
||||||
|
|
||||||
@@ -429,7 +429,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||||||
NodeIOTypes::new(
|
NodeIOTypes::new(
|
||||||
concrete!(ImageFrame<Color>),
|
concrete!(ImageFrame<Color>),
|
||||||
concrete!(ImageFrame<Color>),
|
concrete!(ImageFrame<Color>),
|
||||||
vec![fn_type!(ImageFrame<Color>), fn_type!(BlendMode), fn_type!(f32)],
|
vec![fn_type!(ImageFrame<Color>), fn_type!(BlendMode), fn_type!(f64)],
|
||||||
),
|
),
|
||||||
)],
|
)],
|
||||||
vec![(
|
vec![(
|
||||||
|
|||||||
Reference in New Issue
Block a user