This commit is contained in:
Adam
2025-09-04 00:56:43 -07:00
parent efe431fb56
commit 24ceb179b9
5 changed files with 151 additions and 56 deletions

View File

@@ -1,6 +1,9 @@
use std::sync::Arc;
use graphene_core_shaders::Ctx;
use crate::{
Graphic,
node_graph_overlay::{
background::generate_background,
nodes_and_wires::{draw_layers, draw_nodes},
@@ -8,8 +11,8 @@ use crate::{
ui_context::{UIContext, UIRuntimeResponse},
},
table::Table,
text::FontCache,
transform::ApplyTransform,
vector::Vector,
};
pub mod background;
@@ -19,31 +22,31 @@ pub mod types;
pub mod ui_context;
#[node_macro::node(skip_impl)]
pub fn generate_nodes(_: impl Ctx, node_graph_overlay_data: NodeGraphOverlayData) -> Table<Vector> {
pub fn generate_nodes(_: impl Ctx, node_graph_overlay_data: NodeGraphOverlayData, font_cache: Arc<FontCache>) -> Table<Graphic> {
let mut nodes_and_wires = Table::new();
let layers = draw_layers(&node_graph_overlay_data.nodes_to_render);
let layers = draw_layers(&node_graph_overlay_data.nodes_to_render, font_cache.as_ref());
nodes_and_wires.extend(layers);
let nodes = draw_nodes(&node_graph_overlay_data.nodes_to_render);
let nodes = draw_nodes(&node_graph_overlay_data.nodes_to_render, font_cache.as_ref());
nodes_and_wires.extend(nodes);
nodes_and_wires
}
#[node_macro::node(skip_impl)]
pub fn transform_nodes(ui_context: UIContext, mut nodes: Table<Vector>) -> Table<Vector> {
pub fn transform_nodes(ui_context: UIContext, mut nodes: Table<Graphic>) -> Table<Graphic> {
let matrix = ui_context.transform.to_daffine2();
nodes.apply_transform(&matrix);
nodes.left_apply_transform(&matrix);
nodes
}
#[node_macro::node(skip_impl)]
pub fn dot_grid_background(ui_context: UIContext, opacity: f64) -> Table<Vector> {
generate_background(ui_context, opacity)
pub fn dot_grid_background(ui_context: UIContext, opacity: f64) -> Table<Graphic> {
Table::new_from_element(Graphic::Vector(generate_background(ui_context, opacity)))
}
#[node_macro::node(skip_impl)]
pub fn node_graph_ui_extend(_: impl Ctx, new: Table<Vector>, mut base: Table<Vector>) -> Table<Vector> {
pub fn node_graph_ui_extend(_: impl Ctx, new: Table<Graphic>, mut base: Table<Graphic>) -> Table<Graphic> {
base.extend(new);
base
}

View File

@@ -1,17 +1,21 @@
use glam::DVec2;
use glam::{DAffine2, DVec2};
use graphene_core_shaders::color::{AlphaMut, Color};
use kurbo::{BezPath, Rect, RoundedRect, Shape};
use crate::{
Graphic,
bounds::{BoundingBox, RenderBoundingBox},
node_graph_overlay::{
consts::*,
types::{FrontendGraphDataType, FrontendNodeToRender},
},
table::{Table, TableRow},
text::{self, FontCache, TextAlign, TypesettingConfig},
transform::ApplyTransform,
vector::{Vector, style::Fill},
};
pub fn draw_nodes(nodes: &Vec<FrontendNodeToRender>) -> Table<Vector> {
pub fn draw_nodes(nodes: &Vec<FrontendNodeToRender>, _font_cache: &FontCache) -> Table<Graphic> {
let mut node_table = Table::new();
for node_to_render in nodes {
if let Some(frontend_node) = node_to_render.node_or_layer.node.as_ref() {
@@ -22,15 +26,12 @@ pub fn draw_nodes(nodes: &Vec<FrontendNodeToRender>) -> Table<Vector> {
let height = 1 + number_of_exposed_inputs;
let h = height as f64 * GRID_SIZE;
let border_rect = RoundedRect::new(x, y, x + w, y + h, 2.);
let bez_path = border_rect.to_path(BEZ_PATH_TOLERANCE);
let mut border_vector = Vector::from_bezpath(bez_path);
let primary_output_color = frontend_node.outputs[0]
.as_ref()
.map(|primary_output| primary_output.data_type.data_color_dim())
.unwrap_or(FrontendGraphDataType::General.data_color_dim());
let border_color = Color::from_rgba8_no_srgb(primary_output_color).unwrap();
border_vector.style.stroke = Some(crate::vector::style::Stroke::new(Some(border_color), 1.));
let node_rect = RoundedRect::new(x, y, x + w, y + h, 2.);
let node_bez_path = node_rect.to_path(BEZ_PATH_TOLERANCE);
// Background table
let mut bg_table = Table::new();
let mut bg_vector = Vector::from_bezpath(node_bez_path.clone());
let node_color = if node_to_render.metadata.selected {
let mut selection_color = Color::from_rgba8_no_srgb(COLOR_F_WHITE).unwrap();
selection_color.set_alpha(0.15);
@@ -40,37 +41,65 @@ pub fn draw_nodes(nodes: &Vec<FrontendNodeToRender>) -> Table<Vector> {
bg_color.set_alpha(0.33);
bg_color
};
border_vector.style.fill = crate::vector::style::Fill::Solid(node_color);
bg_vector.style.fill = crate::vector::style::Fill::Solid(node_color.clone());
bg_table.push(TableRow::new_from_element(bg_vector));
// Make primary input brighter
if number_of_exposed_inputs == 0 {
// Draw the first row with rounded bottom corners
node_table.push(TableRow::new_from_element(node_first_row(x, y, true)));
bg_table.push(TableRow::new_from_element(node_first_row(x, y, false)));
} else {
// Draw the first row without rounded bottom corners
node_table.push(TableRow::new_from_element(node_first_row(x, y, false)));
// for node_index in 0..(number_of_exposed_inputs - 1) {
// node_table.push(TableRow::new_from_element(node_secondary_row(x, y, node_index + 1, false)));
// }
// // Draw the last row with bottom corners
// node_table.push(TableRow::new_from_element(node_secondary_row(x, y, number_of_exposed_inputs, true)));
bg_table.push(TableRow::new_from_element(node_first_row(x, y, false)));
};
node_table.push(TableRow::new_from_element(Graphic::Vector(bg_table)));
node_table.push(TableRow::new_from_element(border_vector));
// Border table
let mut border_table = Table::new();
let mut border_vector = Vector::from_bezpath(node_bez_path);
let primary_output_color = frontend_node.outputs[0]
.as_ref()
.map(|primary_output| primary_output.data_type.data_color_dim())
.unwrap_or(FrontendGraphDataType::General.data_color_dim());
let border_color = Color::from_rgba8_no_srgb(primary_output_color).unwrap();
border_vector.style.stroke = Some(crate::vector::style::Stroke::new(Some(border_color), 1.));
border_table.push(TableRow::new_from_element(border_vector));
node_table.push(TableRow::new_from_element(Graphic::Vector(border_table)));
// Border mask table
let mut border_mask_table = Table::new();
let mut border_masks = BezPath::new();
if frontend_node.inputs[0].is_some() {
let index = 0;
border_masks.extend(Rect::new(-8., index as f64 * GRID_SIZE + 4., 8., index as f64 * GRID_SIZE + 20.).to_path(BEZ_PATH_TOLERANCE));
}
for index in 1..=frontend_node.inputs.iter().skip(1).filter(|input| input.is_some()).count() {
border_masks.extend(Rect::new(-8., index as f64 * GRID_SIZE + 4., 8., index as f64 * GRID_SIZE + 20.).to_path(BEZ_PATH_TOLERANCE));
}
if frontend_node.outputs[0].is_some() {
let index = 0;
border_masks.extend(Rect::new(-8. + 5. * GRID_SIZE, index as f64 * GRID_SIZE + 4., 8. + 5. * GRID_SIZE, index as f64 * GRID_SIZE + 20.).to_path(BEZ_PATH_TOLERANCE));
}
for index in 1..=frontend_node.outputs.iter().skip(1).filter(|output| output.is_some()).count() {
border_masks.extend(Rect::new(-8. + 5. * GRID_SIZE, index as f64 * GRID_SIZE + 4., 8. + 5. * GRID_SIZE, index as f64 * GRID_SIZE + 20.).to_path(BEZ_PATH_TOLERANCE));
}
let mut border_masks_vector = Vector::from_bezpath(border_masks);
border_masks_vector.style.fill = Fill::Solid(node_color);
let mut border_masks_row = TableRow::new_from_element(border_masks_vector);
border_masks_row.alpha_blending.clip = true;
border_masks_row.transform.left_apply_transform(&DAffine2::from_translation(DVec2::new(x, y)));
border_mask_table.push(border_masks_row);
node_table.push(TableRow::new_from_element(Graphic::Vector(border_mask_table)));
}
}
node_table
}
pub fn draw_layers(nodes: &Vec<FrontendNodeToRender>) -> Table<Vector> {
pub fn draw_layers(nodes: &Vec<FrontendNodeToRender>, font_cache: &FontCache) -> Table<Graphic> {
let mut layer_table = Table::new();
for node_to_render in nodes {
if let Some(frontend_layer) = node_to_render.node_or_layer.layer.as_ref() {
// First render the text too get the layer width
let text_width: f64 = 0.;
// The layer position is the top left of the thumbnail
let layer_position = DVec2::new(frontend_layer.position.x as f64 * GRID_SIZE + 0.5, frontend_layer.position.y as f64 * GRID_SIZE);
let layer_position = DVec2::new(frontend_layer.position.x as f64 * GRID_SIZE + 12., frontend_layer.position.y as f64 * GRID_SIZE);
// Width from the left of the thumbnail to the left border
let chain_width = if frontend_layer.chain_width > 0 {
@@ -78,9 +107,39 @@ pub fn draw_layers(nodes: &Vec<FrontendNodeToRender>) -> Table<Vector> {
} else {
0.
};
// Width from the right of the thumbnail to the right border
let right_layer_width = text_width.max(4.5);
let thumbnail_width = 2. * GRID_SIZE;
// First render the text to get the layer width
// Create typesetting configuration
let typesetting = TypesettingConfig {
font_size: 14.,
line_height_ratio: 1.2,
character_spacing: 0.0,
max_width: None,
max_height: None,
tilt: 0.0,
align: TextAlign::Left,
};
let font_blob = Some(text::load_font(font_cache.source_sans_pro()));
let mut text_table = crate::text::to_path(&node_to_render.metadata.display_name, font_blob, typesetting, false);
let text_width = if let RenderBoundingBox::Rectangle(bbox) = text_table.bounding_box(DAffine2::default(), true) {
bbox[1].x - bbox[0].x
} else {
0.
};
// Text starts at thumbnail + left padding
let text_start = 12. + 8.;
let right_text_edge = text_start + text_width;
let rounded_text_edge = (right_text_edge as f64 / 24.).ceil() * 24.;
let rounded_layer_width_pixels = rounded_text_edge + 24.;
// Subtract the left thumbnail
let layer_right_edge_width = rounded_layer_width_pixels - 12.;
let right_layer_width = layer_right_edge_width.max(4.5 * GRID_SIZE);
let thumbnail_width = 3. * GRID_SIZE;
let full_layer_width = chain_width + thumbnail_width + right_layer_width;
let x0 = layer_position.x - chain_width;
@@ -88,7 +147,8 @@ pub fn draw_layers(nodes: &Vec<FrontendNodeToRender>) -> Table<Vector> {
let h = 2. * GRID_SIZE;
// Background
let bg_rect = RoundedRect::new(x0, y0, x0 + full_layer_width, y0 + full_layer_width, 8.);
let mut background_table = Table::new();
let bg_rect = RoundedRect::new(x0, y0, x0 + full_layer_width, y0 + h, 8.);
let bez_path = bg_rect.to_path(BEZ_PATH_TOLERANCE);
let mut bg_vector = Vector::from_bezpath(bez_path);
let mut background = if node_to_render.metadata.selected {
@@ -97,18 +157,22 @@ pub fn draw_layers(nodes: &Vec<FrontendNodeToRender>) -> Table<Vector> {
Color::from_rgba8_no_srgb(COLOR_0_BLACK).unwrap()
};
background.set_alpha(0.33);
bg_vector.style.fill = crate::vector::style::Fill::Solid(background);
layer_table.push(TableRow::new_from_element(bg_vector));
bg_vector.style.fill = Fill::Solid(background.clone());
background_table.push(TableRow::new_from_element(bg_vector));
layer_table.push(TableRow::new_from_element(Graphic::Vector(background_table)));
// Border
let border_rect = RoundedRect::new(x0, y0, x0 + full_layer_width, y0 + full_layer_width, 8.);
let mut border_table = Table::new();
let border_rect = RoundedRect::new(x0, y0, x0 + full_layer_width, y0 + h, 8.);
let bez_path = border_rect.to_path(BEZ_PATH_TOLERANCE);
let mut border_vector = Vector::from_bezpath(bez_path);
let border_color = Color::from_rgba8_no_srgb(COLOR_5_DULLGRAY).unwrap();
border_vector.style.stroke = Some(crate::vector::style::Stroke::new(Some(border_color), 1.));
layer_table.push(TableRow::new_from_element(border_vector));
border_table.push(TableRow::new_from_element(border_vector));
layer_table.push(TableRow::new_from_element(Graphic::Vector(border_table)));
// Border mask
let mut border_mask_table = Table::new();
let mut border_mask = BezPath::new();
if frontend_layer.layer_has_left_border_gap && chain_width > 0.1 {
let left_input_mask = Rect::new(-8., 16., 8., 32.);
@@ -118,12 +182,24 @@ pub fn draw_layers(nodes: &Vec<FrontendNodeToRender>) -> Table<Vector> {
border_mask.extend(thumbnail_mask.to_path(BEZ_PATH_TOLERANCE));
let right_visibility_mask = Rect::new(full_layer_width - 12., 12., full_layer_width + 12., 36.);
border_mask.extend(right_visibility_mask.to_path(BEZ_PATH_TOLERANCE));
let border_mask_vector = Vector::from_bezpath(border_mask);
let mut border_mask = TableRow::new_from_element(border_mask_vector);
border_mask.alpha_blending.clip = true;
layer_table.push(border_mask);
let mut border_mask_vector = Vector::from_bezpath(border_mask);
border_mask_vector.style.fill = Fill::Solid(background);
let mut border_mask_row = TableRow::new_from_element(border_mask_vector);
border_mask_row.alpha_blending.clip = true;
border_mask_row.transform.left_apply_transform(&DAffine2::from_translation(DVec2::new(x0, y0)));
border_mask_table.push(border_mask_row);
layer_table.push(TableRow::new_from_element(Graphic::Vector(border_mask_table)));
// The top layer contains the ports,thumbnail,text, etc
for text_row in text_table.iter_mut() {
text_row.element.style.fill = Fill::Solid(Color::WHITE);
*text_row.transform = DAffine2::from_translation(layer_position + DVec2::new(thumbnail_width + text_start, 16.));
}
let top_layer = text_table;
layer_table.push(TableRow::new_from_element(Graphic::Vector(top_layer)));
}
}
layer_table
}
@@ -133,6 +209,8 @@ fn node_first_row(x0: f64, y0: f64, rounded_bottom: bool) -> Vector {
let r = 2.;
let bez_path = if rounded_bottom {
RoundedRect::new(x0, y0, x1, y1, r).to_path(BEZ_PATH_TOLERANCE)
} else {
let mut path = BezPath::new();
// Start at bottom-left
path.move_to((x0, y1));
@@ -157,8 +235,6 @@ fn node_first_row(x0: f64, y0: f64, rounded_bottom: bool) -> Vector {
path.close_path();
path
} else {
RoundedRect::new(x0, y0, x1, y1, r).to_path(BEZ_PATH_TOLERANCE)
};
let mut vector = Vector::from_bezpath(bez_path);

View File

@@ -24,6 +24,7 @@ use graphene_std::gradient::GradientStops;
use graphene_std::node_graph_overlay::types::NodeGraphOverlayData;
use graphene_std::node_graph_overlay::ui_context::UIContext;
use graphene_std::table::Table;
use graphene_std::text::FontCache;
use graphene_std::transform::Footprint;
use graphene_std::uuid::NodeId;
use graphene_std::vector::Vector;
@@ -253,11 +254,11 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
node_io
},
),
async_node!(graphene_core::node_graph_overlay::GenerateNodesNode<_>, input: UIContext, fn_params: [UIContext => NodeGraphOverlayData]),
async_node!(graphene_core::node_graph_overlay::TransformNodesNode<_>, input: UIContext, fn_params: [UIContext =>Table<Vector>]),
async_node!(graphene_core::node_graph_overlay::GenerateNodesNode<_, _>, input: UIContext, fn_params: [UIContext => NodeGraphOverlayData, UIContext => Arc<FontCache>]),
async_node!(graphene_core::node_graph_overlay::TransformNodesNode<_>, input: UIContext, fn_params: [UIContext =>Table<Graphic>]),
async_node!(graphene_core::node_graph_overlay::DotGridBackgroundNode<_>, input: UIContext, fn_params: [UIContext =>f64]),
async_node!(graphene_core::node_graph_overlay::NodeGraphUiExtendNode<_, _>, input: UIContext, fn_params: [UIContext =>Table<Vector>, UIContext =>Table<Vector>]),
async_node!(graphene_std::wasm_application_io::RenderNodeGraphUiNode<_>, input: UIContext, fn_params: [UIContext =>Table<Vector>]),
async_node!(graphene_core::node_graph_overlay::NodeGraphUiExtendNode<_, _>, input: UIContext, fn_params: [UIContext =>Table<Graphic>, UIContext =>Table<Graphic>]),
async_node!(graphene_std::wasm_application_io::RenderNodeGraphUiNode<_>, input: UIContext, fn_params: [UIContext =>Table<Graphic>]),
async_node!(graphene_core::node_graph_overlay::SendRenderNode<_>, input: UIContext, fn_params: [UIContext => String]),
];
// =============