Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion editor/src/messages/portfolio/portfolio_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,16 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
for document_id in self.document_ids.iter() {
let node_to_inspect = self.node_to_inspect();

let Some(document) = self.documents.get_mut(document_id) else {
log::error!("Tried to render non-existent document");
continue;
};

let document_to_viewport = document
.navigation_handler
.calculate_offset_transform(viewport.center_in_viewport_space().into(), &document.document_ptz);
let pointer_position = document_to_viewport.inverse().transform_point2(ipp.mouse.position);

let scale = viewport.scale();
// Use exact physical dimensions from browser (via ResizeObserver's devicePixelContentBoxSize)
let physical_resolution = viewport.size().to_physical().into_dvec2().round().as_uvec2();
Expand All @@ -395,6 +405,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
timing_information,
node_to_inspect,
true,
pointer_position,
) {
responses.add_front(message);
}
Expand Down Expand Up @@ -1054,13 +1065,18 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
return;
};

let document_to_viewport = document
.navigation_handler
.calculate_offset_transform(viewport.center_in_viewport_space().into(), &document.document_ptz);
let pointer_position = document_to_viewport.inverse().transform_point2(ipp.mouse.position);

let scale = viewport.scale();
// Use exact physical dimensions from browser (via ResizeObserver's devicePixelContentBoxSize)
let physical_resolution = viewport.size().to_physical().into_dvec2().round().as_uvec2();

let result = self
.executor
.submit_node_graph_evaluation(document, document_id, physical_resolution, scale, timing_information, node_to_inspect, ignore_hash);
.submit_node_graph_evaluation(document, document_id, physical_resolution, scale, timing_information, node_to_inspect, ignore_hash, pointer_position);

match result {
Err(description) => {
Expand Down
9 changes: 7 additions & 2 deletions editor/src/node_graph_executor.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::messages::frontend::utility_types::{ExportBounds, FileType};
use crate::messages::prelude::*;
use glam::{DAffine2, UVec2};
use glam::{DAffine2, DVec2, UVec2};
use graph_craft::document::value::{RenderOutput, TaggedValue};
use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeInput};
use graph_craft::proto::GraphErrors;
Expand Down Expand Up @@ -81,6 +81,7 @@ impl NodeGraphExecutor {
};
(node_runtime, node_executor)
}

/// Execute the network by flattening it and creating a borrow stack.
fn queue_execution(&mut self, render_config: RenderConfig) -> u64 {
let execution_id = self.current_execution_id;
Expand Down Expand Up @@ -140,6 +141,7 @@ impl NodeGraphExecutor {
viewport_resolution: UVec2,
viewport_scale: f64,
time: TimingInformation,
pointer: DVec2,
) -> Result<Message, String> {
let viewport = Footprint {
transform: document.metadata().document_to_viewport,
Expand All @@ -150,6 +152,7 @@ impl NodeGraphExecutor {
viewport,
scale: viewport_scale,
time,
pointer,
export_format: graphene_std::application_io::ExportFormat::Raster,
render_mode: document.render_mode,
hide_artboards: false,
Expand All @@ -175,9 +178,10 @@ impl NodeGraphExecutor {
time: TimingInformation,
node_to_inspect: Option<NodeId>,
ignore_hash: bool,
pointer: DVec2,
) -> Result<Message, String> {
self.update_node_graph(document, node_to_inspect, ignore_hash)?;
self.submit_current_node_graph_evaluation(document, document_id, viewport_resolution, viewport_scale, time)
self.submit_current_node_graph_evaluation(document, document_id, viewport_resolution, viewport_scale, time, pointer)
}

/// Evaluates a node graph for export
Expand Down Expand Up @@ -208,6 +212,7 @@ impl NodeGraphExecutor {
},
scale: export_config.scale_factor,
time: Default::default(),
pointer: DVec2::ZERO,
export_format,
render_mode: document.render_mode,
hide_artboards: export_config.transparent_background,
Expand Down
2 changes: 1 addition & 1 deletion editor/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl EditorTestUtils {
Err(e) => return Err(format!("update_node_graph_instrumented failed\n\n{e}")),
};

if let Err(e) = exector.submit_current_node_graph_evaluation(document, DocumentId(0), UVec2::ONE, 1., Default::default()) {
if let Err(e) = exector.submit_current_node_graph_evaluation(document, DocumentId(0), UVec2::ONE, 1., Default::default(), DVec2::ZERO) {
return Err(format!("submit_current_node_graph_evaluation failed\n\n{e}"));
}
runtime.run().await;
Expand Down
2 changes: 1 addition & 1 deletion node-graph/interpreted-executor/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ pub fn wrap_network_in_scope(mut network: NodeNetwork, editor_api: Arc<WasmEdito
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_node::create_context::IDENTIFIER),
context_features: graphene_std::ContextDependencies {
extract: ContextFeatures::empty(),
inject: ContextFeatures::REAL_TIME | ContextFeatures::ANIMATION_TIME | ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS,
inject: ContextFeatures::REAL_TIME | ContextFeatures::ANIMATION_TIME | ContextFeatures::POINTER | ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS,
},
..Default::default()
},
Expand Down
1 change: 1 addition & 0 deletions node-graph/libraries/application-io/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ pub struct RenderConfig {
pub scale: f64,
pub export_format: ExportFormat,
pub time: TimingInformation,
pub pointer: DVec2,
#[serde(alias = "view_mode")]
pub render_mode: RenderMode,
pub hide_artboards: bool,
Expand Down
49 changes: 45 additions & 4 deletions node-graph/libraries/core-types/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::transform::Footprint;
use glam::DVec2;
pub use no_std_types::context::{ArcCtx, Ctx};
use std::any::Any;
use std::borrow::Borrow;
Expand Down Expand Up @@ -26,6 +27,10 @@ pub trait ExtractAnimationTime {
fn try_animation_time(&self) -> Option<f64>;
}

pub trait ExtractPointer {
fn try_pointer(&self) -> Option<DVec2>;
}

pub trait ExtractIndex {
fn try_index(&self) -> Option<impl Iterator<Item = usize>>;
}
Expand All @@ -47,30 +52,34 @@ pub trait CloneVarArgs: ExtractVarArgs {
pub trait InjectFootprint {}
pub trait InjectRealTime {}
pub trait InjectAnimationTime {}
pub trait InjectPointer {}
pub trait InjectIndex {}
pub trait InjectVarArgs {}

// Modify* marker traits for context-transparent nodes
pub trait ModifyFootprint: ExtractFootprint + InjectFootprint {}
pub trait ModifyRealTime: ExtractRealTime + InjectRealTime {}
pub trait ModifyAnimationTime: ExtractAnimationTime + InjectAnimationTime {}
pub trait ModifyPointer: ExtractPointer + InjectPointer {}
pub trait ModifyIndex: ExtractIndex + InjectIndex {}
pub trait ModifyVarArgs: ExtractVarArgs + InjectVarArgs {}

pub trait ExtractAll: ExtractFootprint + ExtractIndex + ExtractRealTime + ExtractAnimationTime + ExtractVarArgs {}
pub trait ExtractAll: ExtractFootprint + ExtractIndex + ExtractRealTime + ExtractAnimationTime + ExtractPointer + ExtractVarArgs {}

impl<T: ?Sized + ExtractFootprint + ExtractIndex + ExtractRealTime + ExtractAnimationTime + ExtractVarArgs> ExtractAll for T {}
impl<T: ?Sized + ExtractFootprint + ExtractIndex + ExtractRealTime + ExtractAnimationTime + ExtractPointer + ExtractVarArgs> ExtractAll for T {}

impl<T: Ctx> InjectFootprint for T {}
impl<T: Ctx> InjectRealTime for T {}
impl<T: Ctx> InjectIndex for T {}
impl<T: Ctx> InjectAnimationTime for T {}
impl<T: Ctx> InjectPointer for T {}
impl<T: Ctx> InjectVarArgs for T {}

impl<T: Ctx + InjectFootprint + ExtractFootprint> ModifyFootprint for T {}
impl<T: Ctx + InjectRealTime + ExtractRealTime> ModifyRealTime for T {}
impl<T: Ctx + InjectIndex + ExtractIndex> ModifyIndex for T {}
impl<T: Ctx + InjectAnimationTime + ExtractAnimationTime> ModifyAnimationTime for T {}
impl<T: Ctx + InjectPointer + ExtractPointer> ModifyPointer for T {}
impl<T: Ctx + InjectVarArgs + ExtractVarArgs> ModifyVarArgs for T {}

// Public enum for flexible node macro codegen
Expand All @@ -79,11 +88,13 @@ pub enum ContextFeature {
ExtractFootprint,
ExtractRealTime,
ExtractAnimationTime,
ExtractPointer,
ExtractIndex,
ExtractVarArgs,
InjectFootprint,
InjectRealTime,
InjectAnimationTime,
InjectPointer,
InjectIndex,
InjectVarArgs,
}
Expand All @@ -96,8 +107,9 @@ bitflags! {
const FOOTPRINT = 1 << 0;
const REAL_TIME = 1 << 1;
const ANIMATION_TIME = 1 << 2;
const INDEX = 1 << 3;
const VARARGS = 1 << 4;
const POINTER = 1 << 3;
const INDEX = 1 << 4;
const VARARGS = 1 << 5;
}
}

Expand All @@ -116,6 +128,7 @@ impl From<&[ContextFeature]> for ContextDependencies {
ContextFeature::ExtractFootprint => ContextFeatures::FOOTPRINT,
ContextFeature::ExtractRealTime => ContextFeatures::REAL_TIME,
ContextFeature::ExtractAnimationTime => ContextFeatures::ANIMATION_TIME,
ContextFeature::ExtractPointer => ContextFeatures::POINTER,
ContextFeature::ExtractIndex => ContextFeatures::INDEX,
ContextFeature::ExtractVarArgs => ContextFeatures::VARARGS,
_ => ContextFeatures::empty(),
Expand All @@ -124,6 +137,7 @@ impl From<&[ContextFeature]> for ContextDependencies {
ContextFeature::InjectFootprint => ContextFeatures::FOOTPRINT,
ContextFeature::InjectRealTime => ContextFeatures::REAL_TIME,
ContextFeature::InjectAnimationTime => ContextFeatures::ANIMATION_TIME,
ContextFeature::InjectPointer => ContextFeatures::POINTER,
ContextFeature::InjectIndex => ContextFeatures::INDEX,
ContextFeature::InjectVarArgs => ContextFeatures::VARARGS,
_ => ContextFeatures::empty(),
Expand Down Expand Up @@ -174,6 +188,11 @@ impl<T: ExtractAnimationTime + Sync> ExtractAnimationTime for Option<T> {
self.as_ref().and_then(|x| x.try_animation_time())
}
}
impl<T: ExtractPointer + Sync> ExtractPointer for Option<T> {
fn try_pointer(&self) -> Option<DVec2> {
self.as_ref().and_then(|x| x.try_pointer())
}
}
impl<T: ExtractIndex> ExtractIndex for Option<T> {
fn try_index(&self) -> Option<impl Iterator<Item = usize>> {
self.as_ref().and_then(|x| x.try_index())
Expand Down Expand Up @@ -211,6 +230,11 @@ impl<T: ExtractAnimationTime + Sync> ExtractAnimationTime for Arc<T> {
(**self).try_animation_time()
}
}
impl<T: ExtractPointer + Sync> ExtractPointer for Arc<T> {
fn try_pointer(&self) -> Option<DVec2> {
(**self).try_pointer()
}
}
impl<T: ExtractIndex> ExtractIndex for Arc<T> {
fn try_index(&self) -> Option<impl Iterator<Item = usize>> {
(**self).try_index()
Expand Down Expand Up @@ -303,6 +327,11 @@ impl ExtractAnimationTime for OwnedContextImpl {
self.animation_time
}
}
impl ExtractPointer for OwnedContextImpl {
fn try_pointer(&self) -> Option<DVec2> {
self.pointer
}
}
impl ExtractIndex for OwnedContextImpl {
fn try_index(&self) -> Option<impl Iterator<Item = usize>> {
self.index.clone().map(|x| x.into_iter().rev())
Expand Down Expand Up @@ -363,6 +392,7 @@ pub struct OwnedContextImpl {
index: Option<Vec<usize>>,
real_time: Option<f64>,
animation_time: Option<f64>,
pointer: Option<DVec2>,
}

impl std::fmt::Debug for OwnedContextImpl {
Expand All @@ -374,6 +404,7 @@ impl std::fmt::Debug for OwnedContextImpl {
.field("index", &self.index)
.field("real_time", &self.real_time)
.field("animation_time", &self.animation_time)
.field("pointer", &self.pointer)
.finish()
}
}
Expand All @@ -392,6 +423,7 @@ impl Hash for OwnedContextImpl {
self.index.hash(state);
self.real_time.map(|x| x.to_bits()).hash(state);
self.animation_time.map(|x| x.to_bits()).hash(state);
self.pointer.map(|v| (v.x.to_bits(), v.y.to_bits())).hash(state);
}
}

Expand All @@ -400,12 +432,14 @@ impl OwnedContextImpl {
pub fn from<T: ExtractAll + CloneVarArgs>(value: T) -> Self {
OwnedContextImpl::from_flags(value, ContextFeatures::all())
}

#[track_caller]
pub fn from_flags<T: ExtractAll + CloneVarArgs>(value: T, bitflags: ContextFeatures) -> Self {
let footprint = bitflags.contains(ContextFeatures::FOOTPRINT).then(|| value.try_footprint().copied()).flatten();
let index = bitflags.contains(ContextFeatures::INDEX).then(|| value.try_index()).flatten();
let real_time = bitflags.contains(ContextFeatures::REAL_TIME).then(|| value.try_real_time()).flatten();
let animation_time = bitflags.contains(ContextFeatures::ANIMATION_TIME).then(|| value.try_animation_time()).flatten();
let pointer = bitflags.contains(ContextFeatures::POINTER).then(|| value.try_pointer()).flatten();
let parent = bitflags
.contains(ContextFeatures::VARARGS)
.then(|| match value.varargs_len() {
Expand All @@ -421,8 +455,10 @@ impl OwnedContextImpl {
index: index.map(|x| x.collect()),
real_time,
animation_time,
pointer,
}
}

pub const fn empty() -> Self {
OwnedContextImpl {
footprint: None,
Expand All @@ -431,6 +467,7 @@ impl OwnedContextImpl {
index: None,
real_time: None,
animation_time: None,
pointer: None,
}
}
}
Expand Down Expand Up @@ -475,6 +512,10 @@ impl OwnedContextImpl {
self.animation_time = Some(animation_time);
self
}
pub fn with_pointer(mut self, pointer: DVec2) -> Self {
self.pointer = Some(pointer);
self
}
pub fn with_vararg(mut self, value: Box<dyn AnyHash + Send + Sync>) -> Self {
assert!(self.varargs.is_none_or(|value| value.is_empty()));
self.varargs = Some(Arc::new([value]));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1112,11 +1112,11 @@ impl<Upstream> Vector<Upstream> {
for neighbors in &mut adjacency {
neighbors.sort_by(|a, b| {
let angle = [a, b].map(|side| {
let curve = PathSeg::from(self.path_segment_from_index(
let curve = self.path_segment_from_index(
self.segment_domain.start_point[side.segment_index],
self.segment_domain.end_point[side.segment_index],
self.segment_domain.handles[side.segment_index],
));
);
let curve = if side.reversed { curve.reverse() } else { curve };
let tangent = curve.tangent_at_start();
tangent.y.atan2(tangent.x)
Expand All @@ -1140,20 +1140,19 @@ impl<Upstream> Vector<Upstream> {
}
}

return FaceIterator::new(faces, self);
FaceIterator::new(faces, self)
}

fn construct_face(&self, adjacency: &Vec<Vec<FaceSide>>, first: FaceSide, faces: &mut Faces, seen: &mut FaceSideSet) -> Option<()> {
fn construct_face(&self, adjacency: &[Vec<FaceSide>], first: FaceSide, faces: &mut Faces, seen: &mut FaceSideSet) -> Option<()> {
faces.start_new_face();
let max_iterations = self.segment_domain.id.len() * 2;
let mut side = first;
for _iteration in 1..max_iterations {
if seen.contains(side) {
log::debug!("Encountered seen side {:?}, aborting face construction", side);
return None;
}
seen.insert(side);
faces.add_side(side.clone());
faces.add_side(side);
let next_vertex = if side.reversed {
self.segment_domain.start_point[side.segment_index]
} else {
Expand Down
2 changes: 2 additions & 0 deletions node-graph/node-macro/src/parsing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,11 +414,13 @@ fn parse_context_feature_idents(ty: &Type) -> Vec<Ident> {
"ExtractFootprint"
| "ExtractRealTime"
| "ExtractAnimationTime"
| "ExtractPointer"
| "ExtractIndex"
| "ExtractVarArgs"
| "InjectFootprint"
| "InjectRealTime"
| "InjectAnimationTime"
| "InjectPointer"
| "InjectIndex"
| "InjectVarArgs" => {
features.push(segment.ident.clone());
Expand Down
9 changes: 8 additions & 1 deletion node-graph/nodes/gcore/src/animation.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use core_types::{Ctx, ExtractAnimationTime, ExtractRealTime};
use core_types::{Ctx, ExtractAnimationTime, ExtractPointer, ExtractRealTime};
use glam::DVec2;

const DAY: f64 = 1000. * 3600. * 24.;

Expand Down Expand Up @@ -47,6 +48,12 @@ fn animation_time(ctx: impl Ctx + ExtractAnimationTime) -> f64 {
ctx.try_animation_time().unwrap_or_default()
}

/// Produces the current position of the user's pointer within the document canvas.
#[node_macro::node(category("Animation"))]
fn pointer_position(ctx: impl Ctx + ExtractPointer) -> DVec2 {
ctx.try_pointer().unwrap_or_default()
}

// TODO: These nodes require more sophisticated algorithms for giving the correct result
// #[node_macro::node(category("Animation"))]
// fn month(ctx: impl Ctx + ExtractRealTime) -> f64 {
Expand Down
Loading