New node: Pointer Position (#3535)
* New node: Pointer Position * Fix test
This commit is contained in:
parent
4ab75c9c1c
commit
fa45efa9e2
|
|
@ -383,6 +383,16 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||||
for document_id in self.document_ids.iter() {
|
for document_id in self.document_ids.iter() {
|
||||||
let node_to_inspect = self.node_to_inspect();
|
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();
|
let scale = viewport.scale();
|
||||||
// Use exact physical dimensions from browser (via ResizeObserver's devicePixelContentBoxSize)
|
// Use exact physical dimensions from browser (via ResizeObserver's devicePixelContentBoxSize)
|
||||||
let physical_resolution = viewport.size().to_physical().into_dvec2().round().as_uvec2();
|
let physical_resolution = viewport.size().to_physical().into_dvec2().round().as_uvec2();
|
||||||
|
|
@ -395,6 +405,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||||
timing_information,
|
timing_information,
|
||||||
node_to_inspect,
|
node_to_inspect,
|
||||||
true,
|
true,
|
||||||
|
pointer_position,
|
||||||
) {
|
) {
|
||||||
responses.add_front(message);
|
responses.add_front(message);
|
||||||
}
|
}
|
||||||
|
|
@ -1054,13 +1065,18 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||||
return;
|
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();
|
let scale = viewport.scale();
|
||||||
// Use exact physical dimensions from browser (via ResizeObserver's devicePixelContentBoxSize)
|
// Use exact physical dimensions from browser (via ResizeObserver's devicePixelContentBoxSize)
|
||||||
let physical_resolution = viewport.size().to_physical().into_dvec2().round().as_uvec2();
|
let physical_resolution = viewport.size().to_physical().into_dvec2().round().as_uvec2();
|
||||||
|
|
||||||
let result = self
|
let result = self
|
||||||
.executor
|
.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 {
|
match result {
|
||||||
Err(description) => {
|
Err(description) => {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::messages::frontend::utility_types::{ExportBounds, FileType};
|
use crate::messages::frontend::utility_types::{ExportBounds, FileType};
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use glam::{DAffine2, UVec2};
|
use glam::{DAffine2, DVec2, UVec2};
|
||||||
use graph_craft::document::value::{RenderOutput, TaggedValue};
|
use graph_craft::document::value::{RenderOutput, TaggedValue};
|
||||||
use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeInput};
|
use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeInput};
|
||||||
use graph_craft::proto::GraphErrors;
|
use graph_craft::proto::GraphErrors;
|
||||||
|
|
@ -81,6 +81,7 @@ impl NodeGraphExecutor {
|
||||||
};
|
};
|
||||||
(node_runtime, node_executor)
|
(node_runtime, node_executor)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute the network by flattening it and creating a borrow stack.
|
/// Execute the network by flattening it and creating a borrow stack.
|
||||||
fn queue_execution(&mut self, render_config: RenderConfig) -> u64 {
|
fn queue_execution(&mut self, render_config: RenderConfig) -> u64 {
|
||||||
let execution_id = self.current_execution_id;
|
let execution_id = self.current_execution_id;
|
||||||
|
|
@ -140,6 +141,7 @@ impl NodeGraphExecutor {
|
||||||
viewport_resolution: UVec2,
|
viewport_resolution: UVec2,
|
||||||
viewport_scale: f64,
|
viewport_scale: f64,
|
||||||
time: TimingInformation,
|
time: TimingInformation,
|
||||||
|
pointer: DVec2,
|
||||||
) -> Result<Message, String> {
|
) -> Result<Message, String> {
|
||||||
let viewport = Footprint {
|
let viewport = Footprint {
|
||||||
transform: document.metadata().document_to_viewport,
|
transform: document.metadata().document_to_viewport,
|
||||||
|
|
@ -150,6 +152,7 @@ impl NodeGraphExecutor {
|
||||||
viewport,
|
viewport,
|
||||||
scale: viewport_scale,
|
scale: viewport_scale,
|
||||||
time,
|
time,
|
||||||
|
pointer,
|
||||||
export_format: graphene_std::application_io::ExportFormat::Raster,
|
export_format: graphene_std::application_io::ExportFormat::Raster,
|
||||||
render_mode: document.render_mode,
|
render_mode: document.render_mode,
|
||||||
hide_artboards: false,
|
hide_artboards: false,
|
||||||
|
|
@ -175,9 +178,10 @@ impl NodeGraphExecutor {
|
||||||
time: TimingInformation,
|
time: TimingInformation,
|
||||||
node_to_inspect: Option<NodeId>,
|
node_to_inspect: Option<NodeId>,
|
||||||
ignore_hash: bool,
|
ignore_hash: bool,
|
||||||
|
pointer: DVec2,
|
||||||
) -> Result<Message, String> {
|
) -> Result<Message, String> {
|
||||||
self.update_node_graph(document, node_to_inspect, ignore_hash)?;
|
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
|
/// Evaluates a node graph for export
|
||||||
|
|
@ -208,6 +212,7 @@ impl NodeGraphExecutor {
|
||||||
},
|
},
|
||||||
scale: export_config.scale_factor,
|
scale: export_config.scale_factor,
|
||||||
time: Default::default(),
|
time: Default::default(),
|
||||||
|
pointer: DVec2::ZERO,
|
||||||
export_format,
|
export_format,
|
||||||
render_mode: document.render_mode,
|
render_mode: document.render_mode,
|
||||||
hide_artboards: export_config.transparent_background,
|
hide_artboards: export_config.transparent_background,
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ impl EditorTestUtils {
|
||||||
Err(e) => return Err(format!("update_node_graph_instrumented failed\n\n{e}")),
|
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}"));
|
return Err(format!("submit_current_node_graph_evaluation failed\n\n{e}"));
|
||||||
}
|
}
|
||||||
runtime.run().await;
|
runtime.run().await;
|
||||||
|
|
|
||||||
|
|
@ -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),
|
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_node::create_context::IDENTIFIER),
|
||||||
context_features: graphene_std::ContextDependencies {
|
context_features: graphene_std::ContextDependencies {
|
||||||
extract: ContextFeatures::empty(),
|
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()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -239,6 +239,7 @@ pub struct RenderConfig {
|
||||||
pub scale: f64,
|
pub scale: f64,
|
||||||
pub export_format: ExportFormat,
|
pub export_format: ExportFormat,
|
||||||
pub time: TimingInformation,
|
pub time: TimingInformation,
|
||||||
|
pub pointer: DVec2,
|
||||||
#[serde(alias = "view_mode")]
|
#[serde(alias = "view_mode")]
|
||||||
pub render_mode: RenderMode,
|
pub render_mode: RenderMode,
|
||||||
pub hide_artboards: bool,
|
pub hide_artboards: bool,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::transform::Footprint;
|
use crate::transform::Footprint;
|
||||||
|
use glam::DVec2;
|
||||||
pub use no_std_types::context::{ArcCtx, Ctx};
|
pub use no_std_types::context::{ArcCtx, Ctx};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
|
|
@ -26,6 +27,10 @@ pub trait ExtractAnimationTime {
|
||||||
fn try_animation_time(&self) -> Option<f64>;
|
fn try_animation_time(&self) -> Option<f64>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait ExtractPointer {
|
||||||
|
fn try_pointer(&self) -> Option<DVec2>;
|
||||||
|
}
|
||||||
|
|
||||||
pub trait ExtractIndex {
|
pub trait ExtractIndex {
|
||||||
fn try_index(&self) -> Option<impl Iterator<Item = usize>>;
|
fn try_index(&self) -> Option<impl Iterator<Item = usize>>;
|
||||||
}
|
}
|
||||||
|
|
@ -47,6 +52,7 @@ pub trait CloneVarArgs: ExtractVarArgs {
|
||||||
pub trait InjectFootprint {}
|
pub trait InjectFootprint {}
|
||||||
pub trait InjectRealTime {}
|
pub trait InjectRealTime {}
|
||||||
pub trait InjectAnimationTime {}
|
pub trait InjectAnimationTime {}
|
||||||
|
pub trait InjectPointer {}
|
||||||
pub trait InjectIndex {}
|
pub trait InjectIndex {}
|
||||||
pub trait InjectVarArgs {}
|
pub trait InjectVarArgs {}
|
||||||
|
|
||||||
|
|
@ -54,23 +60,26 @@ pub trait InjectVarArgs {}
|
||||||
pub trait ModifyFootprint: ExtractFootprint + InjectFootprint {}
|
pub trait ModifyFootprint: ExtractFootprint + InjectFootprint {}
|
||||||
pub trait ModifyRealTime: ExtractRealTime + InjectRealTime {}
|
pub trait ModifyRealTime: ExtractRealTime + InjectRealTime {}
|
||||||
pub trait ModifyAnimationTime: ExtractAnimationTime + InjectAnimationTime {}
|
pub trait ModifyAnimationTime: ExtractAnimationTime + InjectAnimationTime {}
|
||||||
|
pub trait ModifyPointer: ExtractPointer + InjectPointer {}
|
||||||
pub trait ModifyIndex: ExtractIndex + InjectIndex {}
|
pub trait ModifyIndex: ExtractIndex + InjectIndex {}
|
||||||
pub trait ModifyVarArgs: ExtractVarArgs + InjectVarArgs {}
|
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> InjectFootprint for T {}
|
||||||
impl<T: Ctx> InjectRealTime for T {}
|
impl<T: Ctx> InjectRealTime for T {}
|
||||||
impl<T: Ctx> InjectIndex for T {}
|
impl<T: Ctx> InjectIndex for T {}
|
||||||
impl<T: Ctx> InjectAnimationTime for T {}
|
impl<T: Ctx> InjectAnimationTime for T {}
|
||||||
|
impl<T: Ctx> InjectPointer for T {}
|
||||||
impl<T: Ctx> InjectVarArgs for T {}
|
impl<T: Ctx> InjectVarArgs for T {}
|
||||||
|
|
||||||
impl<T: Ctx + InjectFootprint + ExtractFootprint> ModifyFootprint for T {}
|
impl<T: Ctx + InjectFootprint + ExtractFootprint> ModifyFootprint for T {}
|
||||||
impl<T: Ctx + InjectRealTime + ExtractRealTime> ModifyRealTime for T {}
|
impl<T: Ctx + InjectRealTime + ExtractRealTime> ModifyRealTime for T {}
|
||||||
impl<T: Ctx + InjectIndex + ExtractIndex> ModifyIndex for T {}
|
impl<T: Ctx + InjectIndex + ExtractIndex> ModifyIndex for T {}
|
||||||
impl<T: Ctx + InjectAnimationTime + ExtractAnimationTime> ModifyAnimationTime 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 {}
|
impl<T: Ctx + InjectVarArgs + ExtractVarArgs> ModifyVarArgs for T {}
|
||||||
|
|
||||||
// Public enum for flexible node macro codegen
|
// Public enum for flexible node macro codegen
|
||||||
|
|
@ -79,11 +88,13 @@ pub enum ContextFeature {
|
||||||
ExtractFootprint,
|
ExtractFootprint,
|
||||||
ExtractRealTime,
|
ExtractRealTime,
|
||||||
ExtractAnimationTime,
|
ExtractAnimationTime,
|
||||||
|
ExtractPointer,
|
||||||
ExtractIndex,
|
ExtractIndex,
|
||||||
ExtractVarArgs,
|
ExtractVarArgs,
|
||||||
InjectFootprint,
|
InjectFootprint,
|
||||||
InjectRealTime,
|
InjectRealTime,
|
||||||
InjectAnimationTime,
|
InjectAnimationTime,
|
||||||
|
InjectPointer,
|
||||||
InjectIndex,
|
InjectIndex,
|
||||||
InjectVarArgs,
|
InjectVarArgs,
|
||||||
}
|
}
|
||||||
|
|
@ -96,8 +107,9 @@ bitflags! {
|
||||||
const FOOTPRINT = 1 << 0;
|
const FOOTPRINT = 1 << 0;
|
||||||
const REAL_TIME = 1 << 1;
|
const REAL_TIME = 1 << 1;
|
||||||
const ANIMATION_TIME = 1 << 2;
|
const ANIMATION_TIME = 1 << 2;
|
||||||
const INDEX = 1 << 3;
|
const POINTER = 1 << 3;
|
||||||
const VARARGS = 1 << 4;
|
const INDEX = 1 << 4;
|
||||||
|
const VARARGS = 1 << 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,6 +128,7 @@ impl From<&[ContextFeature]> for ContextDependencies {
|
||||||
ContextFeature::ExtractFootprint => ContextFeatures::FOOTPRINT,
|
ContextFeature::ExtractFootprint => ContextFeatures::FOOTPRINT,
|
||||||
ContextFeature::ExtractRealTime => ContextFeatures::REAL_TIME,
|
ContextFeature::ExtractRealTime => ContextFeatures::REAL_TIME,
|
||||||
ContextFeature::ExtractAnimationTime => ContextFeatures::ANIMATION_TIME,
|
ContextFeature::ExtractAnimationTime => ContextFeatures::ANIMATION_TIME,
|
||||||
|
ContextFeature::ExtractPointer => ContextFeatures::POINTER,
|
||||||
ContextFeature::ExtractIndex => ContextFeatures::INDEX,
|
ContextFeature::ExtractIndex => ContextFeatures::INDEX,
|
||||||
ContextFeature::ExtractVarArgs => ContextFeatures::VARARGS,
|
ContextFeature::ExtractVarArgs => ContextFeatures::VARARGS,
|
||||||
_ => ContextFeatures::empty(),
|
_ => ContextFeatures::empty(),
|
||||||
|
|
@ -124,6 +137,7 @@ impl From<&[ContextFeature]> for ContextDependencies {
|
||||||
ContextFeature::InjectFootprint => ContextFeatures::FOOTPRINT,
|
ContextFeature::InjectFootprint => ContextFeatures::FOOTPRINT,
|
||||||
ContextFeature::InjectRealTime => ContextFeatures::REAL_TIME,
|
ContextFeature::InjectRealTime => ContextFeatures::REAL_TIME,
|
||||||
ContextFeature::InjectAnimationTime => ContextFeatures::ANIMATION_TIME,
|
ContextFeature::InjectAnimationTime => ContextFeatures::ANIMATION_TIME,
|
||||||
|
ContextFeature::InjectPointer => ContextFeatures::POINTER,
|
||||||
ContextFeature::InjectIndex => ContextFeatures::INDEX,
|
ContextFeature::InjectIndex => ContextFeatures::INDEX,
|
||||||
ContextFeature::InjectVarArgs => ContextFeatures::VARARGS,
|
ContextFeature::InjectVarArgs => ContextFeatures::VARARGS,
|
||||||
_ => ContextFeatures::empty(),
|
_ => ContextFeatures::empty(),
|
||||||
|
|
@ -174,6 +188,11 @@ impl<T: ExtractAnimationTime + Sync> ExtractAnimationTime for Option<T> {
|
||||||
self.as_ref().and_then(|x| x.try_animation_time())
|
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> {
|
impl<T: ExtractIndex> ExtractIndex for Option<T> {
|
||||||
fn try_index(&self) -> Option<impl Iterator<Item = usize>> {
|
fn try_index(&self) -> Option<impl Iterator<Item = usize>> {
|
||||||
self.as_ref().and_then(|x| x.try_index())
|
self.as_ref().and_then(|x| x.try_index())
|
||||||
|
|
@ -211,6 +230,11 @@ impl<T: ExtractAnimationTime + Sync> ExtractAnimationTime for Arc<T> {
|
||||||
(**self).try_animation_time()
|
(**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> {
|
impl<T: ExtractIndex> ExtractIndex for Arc<T> {
|
||||||
fn try_index(&self) -> Option<impl Iterator<Item = usize>> {
|
fn try_index(&self) -> Option<impl Iterator<Item = usize>> {
|
||||||
(**self).try_index()
|
(**self).try_index()
|
||||||
|
|
@ -303,6 +327,11 @@ impl ExtractAnimationTime for OwnedContextImpl {
|
||||||
self.animation_time
|
self.animation_time
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl ExtractPointer for OwnedContextImpl {
|
||||||
|
fn try_pointer(&self) -> Option<DVec2> {
|
||||||
|
self.pointer
|
||||||
|
}
|
||||||
|
}
|
||||||
impl ExtractIndex for OwnedContextImpl {
|
impl ExtractIndex for OwnedContextImpl {
|
||||||
fn try_index(&self) -> Option<impl Iterator<Item = usize>> {
|
fn try_index(&self) -> Option<impl Iterator<Item = usize>> {
|
||||||
self.index.clone().map(|x| x.into_iter().rev())
|
self.index.clone().map(|x| x.into_iter().rev())
|
||||||
|
|
@ -363,6 +392,7 @@ pub struct OwnedContextImpl {
|
||||||
index: Option<Vec<usize>>,
|
index: Option<Vec<usize>>,
|
||||||
real_time: Option<f64>,
|
real_time: Option<f64>,
|
||||||
animation_time: Option<f64>,
|
animation_time: Option<f64>,
|
||||||
|
pointer: Option<DVec2>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for OwnedContextImpl {
|
impl std::fmt::Debug for OwnedContextImpl {
|
||||||
|
|
@ -374,6 +404,7 @@ impl std::fmt::Debug for OwnedContextImpl {
|
||||||
.field("index", &self.index)
|
.field("index", &self.index)
|
||||||
.field("real_time", &self.real_time)
|
.field("real_time", &self.real_time)
|
||||||
.field("animation_time", &self.animation_time)
|
.field("animation_time", &self.animation_time)
|
||||||
|
.field("pointer", &self.pointer)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -392,6 +423,7 @@ impl Hash for OwnedContextImpl {
|
||||||
self.index.hash(state);
|
self.index.hash(state);
|
||||||
self.real_time.map(|x| x.to_bits()).hash(state);
|
self.real_time.map(|x| x.to_bits()).hash(state);
|
||||||
self.animation_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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -400,12 +432,14 @@ impl OwnedContextImpl {
|
||||||
pub fn from<T: ExtractAll + CloneVarArgs>(value: T) -> Self {
|
pub fn from<T: ExtractAll + CloneVarArgs>(value: T) -> Self {
|
||||||
OwnedContextImpl::from_flags(value, ContextFeatures::all())
|
OwnedContextImpl::from_flags(value, ContextFeatures::all())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn from_flags<T: ExtractAll + CloneVarArgs>(value: T, bitflags: ContextFeatures) -> Self {
|
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 footprint = bitflags.contains(ContextFeatures::FOOTPRINT).then(|| value.try_footprint().copied()).flatten();
|
||||||
let index = bitflags.contains(ContextFeatures::INDEX).then(|| value.try_index()).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 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 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
|
let parent = bitflags
|
||||||
.contains(ContextFeatures::VARARGS)
|
.contains(ContextFeatures::VARARGS)
|
||||||
.then(|| match value.varargs_len() {
|
.then(|| match value.varargs_len() {
|
||||||
|
|
@ -421,8 +455,10 @@ impl OwnedContextImpl {
|
||||||
index: index.map(|x| x.collect()),
|
index: index.map(|x| x.collect()),
|
||||||
real_time,
|
real_time,
|
||||||
animation_time,
|
animation_time,
|
||||||
|
pointer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn empty() -> Self {
|
pub const fn empty() -> Self {
|
||||||
OwnedContextImpl {
|
OwnedContextImpl {
|
||||||
footprint: None,
|
footprint: None,
|
||||||
|
|
@ -431,6 +467,7 @@ impl OwnedContextImpl {
|
||||||
index: None,
|
index: None,
|
||||||
real_time: None,
|
real_time: None,
|
||||||
animation_time: None,
|
animation_time: None,
|
||||||
|
pointer: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -475,6 +512,10 @@ impl OwnedContextImpl {
|
||||||
self.animation_time = Some(animation_time);
|
self.animation_time = Some(animation_time);
|
||||||
self
|
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 {
|
pub fn with_vararg(mut self, value: Box<dyn AnyHash + Send + Sync>) -> Self {
|
||||||
assert!(self.varargs.is_none_or(|value| value.is_empty()));
|
assert!(self.varargs.is_none_or(|value| value.is_empty()));
|
||||||
self.varargs = Some(Arc::new([value]));
|
self.varargs = Some(Arc::new([value]));
|
||||||
|
|
|
||||||
|
|
@ -1112,11 +1112,11 @@ impl<Upstream> Vector<Upstream> {
|
||||||
for neighbors in &mut adjacency {
|
for neighbors in &mut adjacency {
|
||||||
neighbors.sort_by(|a, b| {
|
neighbors.sort_by(|a, b| {
|
||||||
let angle = [a, b].map(|side| {
|
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.start_point[side.segment_index],
|
||||||
self.segment_domain.end_point[side.segment_index],
|
self.segment_domain.end_point[side.segment_index],
|
||||||
self.segment_domain.handles[side.segment_index],
|
self.segment_domain.handles[side.segment_index],
|
||||||
));
|
);
|
||||||
let curve = if side.reversed { curve.reverse() } else { curve };
|
let curve = if side.reversed { curve.reverse() } else { curve };
|
||||||
let tangent = curve.tangent_at_start();
|
let tangent = curve.tangent_at_start();
|
||||||
tangent.y.atan2(tangent.x)
|
tangent.y.atan2(tangent.x)
|
||||||
|
|
@ -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();
|
faces.start_new_face();
|
||||||
let max_iterations = self.segment_domain.id.len() * 2;
|
let max_iterations = self.segment_domain.id.len() * 2;
|
||||||
let mut side = first;
|
let mut side = first;
|
||||||
for _iteration in 1..max_iterations {
|
for _iteration in 1..max_iterations {
|
||||||
if seen.contains(side) {
|
if seen.contains(side) {
|
||||||
log::debug!("Encountered seen side {:?}, aborting face construction", side);
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
seen.insert(side);
|
seen.insert(side);
|
||||||
faces.add_side(side.clone());
|
faces.add_side(side);
|
||||||
let next_vertex = if side.reversed {
|
let next_vertex = if side.reversed {
|
||||||
self.segment_domain.start_point[side.segment_index]
|
self.segment_domain.start_point[side.segment_index]
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -414,11 +414,13 @@ fn parse_context_feature_idents(ty: &Type) -> Vec<Ident> {
|
||||||
"ExtractFootprint"
|
"ExtractFootprint"
|
||||||
| "ExtractRealTime"
|
| "ExtractRealTime"
|
||||||
| "ExtractAnimationTime"
|
| "ExtractAnimationTime"
|
||||||
|
| "ExtractPointer"
|
||||||
| "ExtractIndex"
|
| "ExtractIndex"
|
||||||
| "ExtractVarArgs"
|
| "ExtractVarArgs"
|
||||||
| "InjectFootprint"
|
| "InjectFootprint"
|
||||||
| "InjectRealTime"
|
| "InjectRealTime"
|
||||||
| "InjectAnimationTime"
|
| "InjectAnimationTime"
|
||||||
|
| "InjectPointer"
|
||||||
| "InjectIndex"
|
| "InjectIndex"
|
||||||
| "InjectVarArgs" => {
|
| "InjectVarArgs" => {
|
||||||
features.push(segment.ident.clone());
|
features.push(segment.ident.clone());
|
||||||
|
|
|
||||||
|
|
@ -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.;
|
const DAY: f64 = 1000. * 3600. * 24.;
|
||||||
|
|
||||||
|
|
@ -47,6 +48,12 @@ fn animation_time(ctx: impl Ctx + ExtractAnimationTime) -> f64 {
|
||||||
ctx.try_animation_time().unwrap_or_default()
|
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
|
// TODO: These nodes require more sophisticated algorithms for giving the correct result
|
||||||
// #[node_macro::node(category("Animation"))]
|
// #[node_macro::node(category("Animation"))]
|
||||||
// fn month(ctx: impl Ctx + ExtractRealTime) -> f64 {
|
// fn month(ctx: impl Ctx + ExtractRealTime) -> f64 {
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,7 @@ async fn create_context<'a: 'n>(
|
||||||
.with_footprint(footprint)
|
.with_footprint(footprint)
|
||||||
.with_real_time(render_config.time.time)
|
.with_real_time(render_config.time.time)
|
||||||
.with_animation_time(render_config.time.animation_time.as_secs_f64())
|
.with_animation_time(render_config.time.animation_time.as_secs_f64())
|
||||||
|
.with_pointer(render_config.pointer)
|
||||||
.with_vararg(Box::new(render_params))
|
.with_vararg(Box::new(render_params))
|
||||||
.into_context();
|
.into_context();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -471,12 +471,41 @@ fn ceiling<T: num_traits::float::Float>(
|
||||||
value.ceil()
|
value.ceil()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait AbsoluteValue {
|
||||||
|
fn abs(self) -> Self;
|
||||||
|
}
|
||||||
|
impl AbsoluteValue for DVec2 {
|
||||||
|
fn abs(self) -> Self {
|
||||||
|
DVec2::new(self.x.abs(), self.y.abs())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl AbsoluteValue for f32 {
|
||||||
|
fn abs(self) -> Self {
|
||||||
|
self.abs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl AbsoluteValue for f64 {
|
||||||
|
fn abs(self) -> Self {
|
||||||
|
self.abs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl AbsoluteValue for i32 {
|
||||||
|
fn abs(self) -> Self {
|
||||||
|
self.abs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl AbsoluteValue for i64 {
|
||||||
|
fn abs(self) -> Self {
|
||||||
|
self.abs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The absolute value function (`abs`) removes the negative sign from an input value, if present.
|
/// The absolute value function (`abs`) removes the negative sign from an input value, if present.
|
||||||
#[node_macro::node(category("Math: Numeric"))]
|
#[node_macro::node(category("Math: Numeric"))]
|
||||||
fn absolute_value<T: num_traits::sign::Signed>(
|
fn absolute_value<T: AbsoluteValue>(
|
||||||
_: impl Ctx,
|
_: impl Ctx,
|
||||||
/// The number to be made positive.
|
/// The number to be made positive.
|
||||||
#[implementations(f64, f32, i32, i64)]
|
#[implementations(f64, f32, i32, i64, DVec2)]
|
||||||
value: T,
|
value: T,
|
||||||
) -> T {
|
) -> T {
|
||||||
value.abs()
|
value.abs()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue