Skip to content

Commit 08c2d05

Browse files
committed
Animated thumbnails
1 parent c2815ea commit 08c2d05

File tree

12 files changed

+239
-60
lines changed

12 files changed

+239
-60
lines changed

editor/src/dispatcher.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@ use crate::messages::prelude::*;
66
#[derive(Debug, Default)]
77
pub struct Dispatcher {
88
evaluation_queue: Vec<Message>,
9-
introspection_queue: Vec<Message>,
109
queueing_evaluation_messages: bool,
11-
queueing_introspection_messages: bool,
1210
message_queues: Vec<VecDeque<Message>>,
1311
pub responses: Vec<FrontendMessage>,
1412
pub message_handlers: DispatcherMessageHandlers,

editor/src/messages/portfolio/document/document_message_handler.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use crate::messages::portfolio::document::utility_types::document_metadata::{Doc
1717
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, DocumentMode, FlipAxis, PTZ};
1818
use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, NodeTemplate};
1919
use crate::messages::portfolio::document::utility_types::nodes::RawBuffer;
20-
use crate::messages::portfolio::utility_types::PersistentData;
2120
use crate::messages::prelude::*;
2221
use crate::messages::tool::common_functionality::graph_modification_utils::{self, get_blend_mode, get_fill, get_opacity};
2322
use crate::messages::tool::tool_messages::select_tool::SelectToolPointerKeys;

editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1096,7 +1096,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
10961096
implementation: DocumentNodeImplementation::ProtoNode(text::text::IDENTIFIER),
10971097
manual_composition: Some(concrete!(Context)),
10981098
inputs: vec![
1099-
NodeInput::scope("editor-api"),
1099+
NodeInput::scope("font-cache"),
11001100
NodeInput::value(TaggedValue::String("Lorem ipsum".to_string()), false),
11011101
NodeInput::value(
11021102
TaggedValue::Font(Font::new(graphene_std::consts::DEFAULT_FONT_FAMILY.into(), graphene_std::consts::DEFAULT_FONT_STYLE.into())),

editor/src/messages/portfolio/portfolio_message_handler.rs

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
796796
// Remove all thumbnails
797797
cleared_thumbnails.push(sni);
798798
}
799-
799+
document.node_graph_handler.node_graph_errors = Vec::new();
800800
self.thumbnails_to_clear.extend(cleared_thumbnails);
801801
}
802802
PortfolioMessage::EvaluateActiveDocumentWithThumbnails => {
@@ -869,7 +869,9 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
869869
let evaluated_data = match monitor_result {
870870
MonitorIntrospectResult::Error => continue,
871871
MonitorIntrospectResult::Disabled => continue,
872-
MonitorIntrospectResult::NotEvaluated => continue,
872+
MonitorIntrospectResult::NotEvaluated => {
873+
continue;
874+
}
873875
MonitorIntrospectResult::Evaluated((data, changed)) => {
874876
// If the evaluated value is the same as the previous, then just remap the ID
875877
if !changed {
@@ -1253,30 +1255,30 @@ impl PortfolioMessageHandler {
12531255
.network_interface
12541256
.viewport_loaded_thumbnail_position(&input_connector, graph_wire_style, &document.breadcrumb_network_path)
12551257
{
1256-
let in_view = viewport_position.x > 0.0 && viewport_position.y > 0.0 && viewport_position.x < ipp.viewport_bounds()[1].x && viewport_position.y < ipp.viewport_bounds()[1].y;
1257-
if in_view {
1258-
let Some(protonode) = document.network_interface.protonode_from_input(&input_connector, &document.breadcrumb_network_path) else {
1259-
// The input is not connected to the export, which occurs if inside a disconnected node
1260-
wire_stack = Vec::new();
1261-
nodes_to_render.clear();
1262-
continue;
1263-
};
1264-
nodes_to_render.insert(protonode);
1265-
}
1258+
// let in_view = viewport_position.x > 0.0 && viewport_position.y > 0.0 && viewport_position.x < ipp.viewport_bounds()[1].x && viewport_position.y < ipp.viewport_bounds()[1].y;
1259+
// if in_view {
1260+
let Some(protonode) = document.network_interface.protonode_from_input(&input_connector, &document.breadcrumb_network_path) else {
1261+
// The input is not connected to the export, which occurs if inside a disconnected node
1262+
wire_stack = Vec::new();
1263+
nodes_to_render.clear();
1264+
continue;
1265+
};
1266+
nodes_to_render.insert(protonode);
1267+
// }
12661268
}
12671269
}
12681270
};
12691271

1270-
// Get thumbnails for all visible layer
1271-
for visible_node in &document.node_graph_handler.visible_nodes(&mut document.network_interface, &document.breadcrumb_network_path, ipp) {
1272-
if document.network_interface.is_layer(&visible_node, &document.breadcrumb_network_path) {
1273-
let Some(protonode) = document
1272+
// Get thumbnails for all visible layer ouputs
1273+
// for visible_node in &document.node_graph_handler.visible_nodes(&mut document.network_interface, &document.breadcrumb_network_path, ipp) {
1274+
for visible_node in document.network_interface.nested_network(&document.breadcrumb_network_path).unwrap().nodes.keys() {
1275+
if document.network_interface.is_layer(visible_node, &document.breadcrumb_network_path) {
1276+
if let Some(protonode) = document
12741277
.network_interface
12751278
.protonode_from_output(&OutputConnector::node(*visible_node, 0), &document.breadcrumb_network_path)
1276-
else {
1277-
continue;
1279+
{
1280+
nodes_to_render.insert(protonode);
12781281
};
1279-
nodes_to_render.insert(protonode);
12801282
}
12811283
}
12821284

node-graph/gcore/src/bounds.rs

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::Color;
2-
use glam::{DAffine2, DVec2};
2+
use glam::{DAffine2, DVec2, IVec2, UVec2};
33

44
pub trait BoundingBox {
55
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> Option<[DVec2; 2]>;
@@ -15,10 +15,80 @@ macro_rules! none_impl {
1515
};
1616
}
1717

18-
none_impl!(String);
19-
none_impl!(bool);
20-
none_impl!(f32);
21-
none_impl!(f64);
22-
none_impl!(DVec2);
23-
none_impl!(Option<Color>);
2418
none_impl!(Vec<Color>);
19+
20+
impl BoundingBox for u32 {
21+
fn bounding_box(&self, _transform: DAffine2, _include_stroke: bool) -> Option<[DVec2; 2]> {
22+
text_bbox(i32_width(*self as i32))
23+
}
24+
}
25+
26+
impl BoundingBox for f64 {
27+
fn bounding_box(&self, _transform: DAffine2, _include_stroke: bool) -> Option<[DVec2; 2]> {
28+
text_bbox(f64_width(*self))
29+
}
30+
}
31+
32+
impl BoundingBox for DVec2 {
33+
fn bounding_box(&self, _transform: DAffine2, _include_stroke: bool) -> Option<[DVec2; 2]> {
34+
let width_x = f64_width(self.x);
35+
let width_y = f64_width(self.y);
36+
let total_width = width_x + width_y + 50.;
37+
text_bbox(total_width)
38+
}
39+
}
40+
41+
impl BoundingBox for IVec2 {
42+
fn bounding_box(&self, _transform: DAffine2, _include_stroke: bool) -> Option<[DVec2; 2]> {
43+
let width_x = i32_width(self.x);
44+
let width_y = i32_width(self.y);
45+
let total_width = width_x + width_y + 50.;
46+
text_bbox(total_width)
47+
}
48+
}
49+
50+
impl BoundingBox for UVec2 {
51+
fn bounding_box(&self, _transform: DAffine2, _include_stroke: bool) -> Option<[DVec2; 2]> {
52+
let width_x = i32_width(self.x as i32);
53+
let width_y = i32_width(self.y as i32);
54+
let total_width = width_x + width_y + 50.;
55+
text_bbox(total_width)
56+
}
57+
}
58+
59+
impl BoundingBox for bool {
60+
fn bounding_box(&self, _transform: DAffine2, _include_stroke: bool) -> Option<[DVec2; 2]> {
61+
text_bbox(60.)
62+
}
63+
}
64+
65+
impl BoundingBox for String {
66+
fn bounding_box(&self, _transform: DAffine2, _include_stroke: bool) -> Option<[DVec2; 2]> {
67+
let width = self.len() * 16;
68+
text_bbox(width as f64)
69+
}
70+
}
71+
72+
impl BoundingBox for Option<Color> {
73+
fn bounding_box(&self, _transform: DAffine2, _include_stroke: bool) -> Option<[DVec2; 2]> {
74+
Some([(0., -5.).into(), (150., 110.).into()])
75+
}
76+
}
77+
78+
fn f64_width(f64: f64) -> f64 {
79+
let left_of_decimal_width = i32_width(f64 as i32);
80+
left_of_decimal_width + 5. + 2. * 16.
81+
}
82+
83+
fn i32_width(i32: i32) -> f64 {
84+
let number_of_digits = (i32.abs()).checked_ilog10().unwrap_or(0) + 1;
85+
let mut width = number_of_digits * 16;
86+
if i32 < 0 {
87+
width += 20;
88+
}
89+
width.into()
90+
}
91+
92+
fn text_bbox(width: f64) -> Option<[DVec2; 2]> {
93+
Some([(-width / 2., 0.).into(), (width / 2., 30.).into()])
94+
}

node-graph/gcore/src/context.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -630,8 +630,8 @@ fn get_animation_time(ctx: impl Ctx + ExtractAnimationTime) -> Option<f64> {
630630
}
631631

632632
#[node_macro::node(category("Context Getter"))]
633-
fn get_index(ctx: impl Ctx + ExtractIndex) -> Option<usize> {
634-
ctx.try_index()
633+
fn get_index(ctx: impl Ctx + ExtractIndex) -> Option<u32> {
634+
ctx.try_index().map(|index| index as u32)
635635
}
636636

637637
// #[node_macro::node(category("Loop"))]

node-graph/gcore/src/gradient.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::Color;
1+
use crate::{Color, bounds::BoundingBox, vector::VectorDataTable};
22
use dyn_any::DynAny;
33
use glam::{DAffine2, DVec2};
44

@@ -32,6 +32,12 @@ impl Default for GradientStops {
3232
}
3333
}
3434

35+
impl BoundingBox for GradientStops {
36+
fn bounding_box(&self, _transform: DAffine2, _include_stroke: bool) -> Option<[DVec2; 2]> {
37+
Into::<VectorDataTable>::into(Into::<Gradient>::into(self.clone())).bounding_box(DAffine2::default(), false)
38+
}
39+
}
40+
3541
impl IntoIterator for GradientStops {
3642
type Item = (f64, Color);
3743
type IntoIter = std::vec::IntoIter<(f64, Color)>;
@@ -169,6 +175,24 @@ impl std::fmt::Display for Gradient {
169175
}
170176
}
171177

178+
impl From<GradientStops> for Gradient {
179+
fn from(gradient_stops: GradientStops) -> Gradient {
180+
Gradient {
181+
stops: gradient_stops.clone(),
182+
gradient_type: GradientType::Linear,
183+
start: (0., 0.).into(),
184+
end: (1., 0.).into(),
185+
transform: DAffine2::IDENTITY,
186+
}
187+
}
188+
}
189+
190+
impl BoundingBox for Gradient {
191+
fn bounding_box(&self, _transform: DAffine2, _include_stroke: bool) -> Option<[DVec2; 2]> {
192+
Into::<VectorDataTable>::into(self.clone()).bounding_box(DAffine2::default(), false)
193+
}
194+
}
195+
172196
impl Gradient {
173197
/// Constructs a new gradient with the colors at 0 and 1 specified.
174198
pub fn new(start: DVec2, start_color: Color, end: DVec2, end_color: Color, transform: DAffine2, gradient_type: GradientType) -> Self {

node-graph/gcore/src/render_complexity.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::gradient::{Gradient, GradientStops};
12
use crate::instances::Instances;
23
use crate::raster_types::{CPU, GPU, Raster};
34
use crate::vector::VectorData;
@@ -54,8 +55,10 @@ impl RenderComplexity for Raster<GPU> {
5455

5556
impl RenderComplexity for String {}
5657
impl RenderComplexity for bool {}
57-
impl RenderComplexity for f32 {}
58+
impl RenderComplexity for u32 {}
5859
impl RenderComplexity for f64 {}
5960
impl RenderComplexity for DVec2 {}
6061
impl RenderComplexity for Option<Color> {}
6162
impl RenderComplexity for Vec<Color> {}
63+
impl RenderComplexity for GradientStops {}
64+
impl RenderComplexity for Gradient {}

node-graph/gcore/src/vector/vector_data.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ mod modification;
55
use super::misc::{dvec2_to_point, point_to_dvec2};
66
use super::style::{PathStyle, Stroke};
77
use crate::bounds::BoundingBox;
8+
use crate::gradient::{Gradient, GradientType};
89
use crate::instances::Instances;
910
use crate::math::quad::Quad;
1011
use crate::transform::Transform;
1112
use crate::vector::click_target::{ClickTargetType, FreePoint};
13+
use crate::vector::style::Fill;
1214
use crate::{AlphaBlending, Color, GraphicGroupTable};
1315
pub use attributes::*;
14-
use bezier_rs::{BezierHandles, ManipulatorGroup};
16+
use bezier_rs::{BezierHandles, ManipulatorGroup, Subpath};
1517
use core::borrow::Borrow;
1618
use core::hash::Hash;
1719
use dyn_any::DynAny;
@@ -511,6 +513,36 @@ impl BoundingBox for VectorDataTable {
511513
}
512514
}
513515

516+
/// Convert a Gradient/GradientStops into VectorDataTable for rendering thumbnails
517+
impl From<Gradient> for VectorDataTable {
518+
fn from(mut gradient: Gradient) -> VectorDataTable {
519+
match gradient.gradient_type {
520+
GradientType::Linear => {
521+
let mut rectangle = VectorData::from_subpath(Subpath::new_rect((0., 0.).into(), (150., 100.).into()));
522+
// Handle vertical gradients
523+
let intersection = if gradient.start.x == gradient.end.x {
524+
DVec2::new(0., 100.)
525+
} else {
526+
let slope = (gradient.start.y - gradient.end.y) / (gradient.start.x - gradient.end.x);
527+
if slope > 100. / 150. { DVec2::new(100. / slope, 100.) } else { DVec2::new(150., slope * 150.) }
528+
};
529+
gradient.start = (0., 0.).into();
530+
gradient.end = intersection;
531+
rectangle.style.fill = Fill::Gradient(gradient);
532+
Instances::new(rectangle)
533+
}
534+
GradientType::Radial => {
535+
let mut circle = VectorData::from_subpath(Subpath::new_ellipse((-100., -100.).into(), (100., 100.).into()));
536+
gradient.start = (0., 0.).into();
537+
gradient.end = (100., 0.).into();
538+
gradient.transform = DAffine2::IDENTITY;
539+
circle.style.fill = Fill::Gradient(gradient);
540+
Instances::new(circle)
541+
}
542+
}
543+
}
544+
}
545+
514546
/// A selectable part of a curve, either an anchor (start or end of a bézier) or a handle (doesn't necessarily go through the bézier but influences curvature).
515547
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, DynAny, serde::Serialize, serde::Deserialize)]
516548
pub enum ManipulatorPointId {

node-graph/graph-craft/src/document/value.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pub use glam::{DAffine2, DVec2, IVec2, UVec2};
77
use graphene_application_io::SurfaceFrame;
88
use graphene_brush::brush_cache::BrushCache;
99
use graphene_brush::brush_stroke::BrushStroke;
10+
use graphene_core::gradient::GradientStops;
1011
use graphene_core::raster_types::{CPU, GPU};
1112
use graphene_core::transform::ReferencePoint;
1213
use graphene_core::uuid::NodeId;
@@ -562,8 +563,13 @@ thumbnail_render! {
562563
graphene_core::raster_types::RasterDataTable<GPU>,
563564
graphene_core::GraphicElement,
564565
Option<Color>,
566+
GradientStops,
565567
Vec<Color>,
568+
u32,
566569
f64,
570+
DVec2,
571+
bool,
572+
String,
567573
}
568574

569575
pub enum ThumbnailRenderResult {

0 commit comments

Comments
 (0)