mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-04 13:30:48 +00:00
Multi Morph WIP
This commit is contained in:
parent
feba87449b
commit
12dd5007c1
1 changed files with 98 additions and 43 deletions
|
@ -951,31 +951,7 @@ async fn jitter_points<F: 'n + Send>(
|
||||||
vector_data
|
vector_data
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
|
fn morph_vector_data(source: VectorData, target: VectorData, time: Fraction, start_index: IntegerCount) -> VectorData {
|
||||||
async fn morph<F: 'n + Send + Copy>(
|
|
||||||
#[implementations(
|
|
||||||
(),
|
|
||||||
Footprint,
|
|
||||||
)]
|
|
||||||
footprint: F,
|
|
||||||
#[implementations(
|
|
||||||
() -> VectorData,
|
|
||||||
Footprint -> VectorData,
|
|
||||||
)]
|
|
||||||
source: impl Node<F, Output = VectorData>,
|
|
||||||
#[expose]
|
|
||||||
#[implementations(
|
|
||||||
() -> VectorData,
|
|
||||||
Footprint -> VectorData,
|
|
||||||
)]
|
|
||||||
target: impl Node<F, Output = VectorData>,
|
|
||||||
#[range((0., 1.))]
|
|
||||||
#[default(0.5)]
|
|
||||||
time: Fraction,
|
|
||||||
#[min(0.)] start_index: IntegerCount,
|
|
||||||
) -> VectorData {
|
|
||||||
let source = source.eval(footprint).await;
|
|
||||||
let target = target.eval(footprint).await;
|
|
||||||
let mut result = VectorData::empty();
|
let mut result = VectorData::empty();
|
||||||
|
|
||||||
// Lerp styles
|
// Lerp styles
|
||||||
|
@ -984,6 +960,7 @@ async fn morph<F: 'n + Send + Copy>(
|
||||||
|
|
||||||
let mut source_paths = source.stroke_bezier_paths();
|
let mut source_paths = source.stroke_bezier_paths();
|
||||||
let mut target_paths = target.stroke_bezier_paths();
|
let mut target_paths = target.stroke_bezier_paths();
|
||||||
|
|
||||||
for (mut source_path, mut target_path) in (&mut source_paths).zip(&mut target_paths) {
|
for (mut source_path, mut target_path) in (&mut source_paths).zip(&mut target_paths) {
|
||||||
// Deal with mismatched transforms
|
// Deal with mismatched transforms
|
||||||
source_path.apply_transform(source.transform);
|
source_path.apply_transform(source.transform);
|
||||||
|
@ -1005,22 +982,14 @@ async fn morph<F: 'n + Send + Copy>(
|
||||||
target_path.push_manipulator_group(target_path.manipulator_groups()[0].flip());
|
target_path.push_manipulator_group(target_path.manipulator_groups()[0].flip());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mismatched subpath items
|
// Equalize number of manipulator groups
|
||||||
'outer: loop {
|
while source_path.len() < target_path.len() {
|
||||||
for segment_index in (0..(source_path.len() - 1)).rev() {
|
let segment_index = (0..(source_path.len() - 1)).rev().next().unwrap_or(0);
|
||||||
if target_path.len() <= source_path.len() {
|
source_path.insert(SubpathTValue::Parametric { segment_index, t: 0.5 });
|
||||||
break 'outer;
|
|
||||||
}
|
|
||||||
source_path.insert(SubpathTValue::Parametric { segment_index, t: 0.5 })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
'outer: loop {
|
while target_path.len() < source_path.len() {
|
||||||
for segment_index in (0..(target_path.len() - 1)).rev() {
|
let segment_index = (0..(target_path.len() - 1)).rev().next().unwrap_or(0);
|
||||||
if source_path.len() <= target_path.len() {
|
target_path.insert(SubpathTValue::Parametric { segment_index, t: 0.5 });
|
||||||
break 'outer;
|
|
||||||
}
|
|
||||||
target_path.insert(SubpathTValue::Parametric { segment_index, t: 0.5 })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lerp points
|
// Lerp points
|
||||||
|
@ -1032,15 +1001,17 @@ async fn morph<F: 'n + Send + Copy>(
|
||||||
|
|
||||||
result.append_subpath(source_path, true);
|
result.append_subpath(source_path, true);
|
||||||
}
|
}
|
||||||
// Mismatched subpath count
|
|
||||||
|
// Handle mismatched subpath counts
|
||||||
for mut source_path in source_paths {
|
for mut source_path in source_paths {
|
||||||
source_path.apply_transform(source.transform);
|
source_path.apply_transform(source.transform);
|
||||||
let end = source_path.manipulator_groups().first().map(|group| group.anchor).unwrap_or_default();
|
let end = source_path.manipulator_groups().first().map(|group| group.anchor).unwrap_or_default();
|
||||||
for group in source_path.manipulator_groups_mut() {
|
for group in source_path.manipulator_groups_mut() {
|
||||||
group.anchor = group.anchor.lerp(end, time);
|
group.anchor = group.anchor.lerp(end, time);
|
||||||
group.in_handle = group.in_handle.map(|handle| handle.lerp(end, time));
|
group.in_handle = group.in_handle.map(|handle| handle.lerp(end, time));
|
||||||
group.out_handle = group.in_handle.map(|handle| handle.lerp(end, time));
|
group.out_handle = group.out_handle.map(|handle| handle.lerp(end, time));
|
||||||
}
|
}
|
||||||
|
result.append_subpath(source_path, true);
|
||||||
}
|
}
|
||||||
for mut target_path in target_paths {
|
for mut target_path in target_paths {
|
||||||
target_path.apply_transform(target.transform);
|
target_path.apply_transform(target.transform);
|
||||||
|
@ -1048,13 +1019,97 @@ async fn morph<F: 'n + Send + Copy>(
|
||||||
for group in target_path.manipulator_groups_mut() {
|
for group in target_path.manipulator_groups_mut() {
|
||||||
group.anchor = start.lerp(group.anchor, time);
|
group.anchor = start.lerp(group.anchor, time);
|
||||||
group.in_handle = group.in_handle.map(|handle| start.lerp(handle, time));
|
group.in_handle = group.in_handle.map(|handle| start.lerp(handle, time));
|
||||||
group.out_handle = group.in_handle.map(|handle| start.lerp(handle, time));
|
group.out_handle = group.out_handle.map(|handle| start.lerp(handle, time));
|
||||||
}
|
}
|
||||||
|
result.append_subpath(target_path, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
|
||||||
|
async fn morph<F: 'n + Send + Copy>(
|
||||||
|
#[implementations(
|
||||||
|
(),
|
||||||
|
Footprint,
|
||||||
|
)]
|
||||||
|
footprint: F,
|
||||||
|
#[implementations(
|
||||||
|
() -> VectorData,
|
||||||
|
Footprint -> VectorData,
|
||||||
|
)]
|
||||||
|
source: impl Node<F, Output = VectorData>,
|
||||||
|
#[expose]
|
||||||
|
#[implementations(
|
||||||
|
() -> VectorData,
|
||||||
|
Footprint -> VectorData,
|
||||||
|
)]
|
||||||
|
target: impl Node<F, Output = VectorData>,
|
||||||
|
// TODO: Rename to "progress"
|
||||||
|
#[range((0., 1.))]
|
||||||
|
#[default(0.5)]
|
||||||
|
time: Fraction,
|
||||||
|
#[min(0.)] start_index: IntegerCount,
|
||||||
|
) -> VectorData {
|
||||||
|
let source = source.eval(footprint).await;
|
||||||
|
let target = target.eval(footprint).await;
|
||||||
|
morph_vector_data(source, target, time, start_index)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
|
||||||
|
async fn multi_morph<F: 'n + Send + Copy>(
|
||||||
|
#[implementations(
|
||||||
|
(),
|
||||||
|
Footprint,
|
||||||
|
)]
|
||||||
|
footprint: F,
|
||||||
|
#[implementations(
|
||||||
|
() -> VectorData,
|
||||||
|
Footprint -> VectorData,
|
||||||
|
)]
|
||||||
|
source0: impl Node<F, Output = VectorData>,
|
||||||
|
#[implementations(
|
||||||
|
() -> VectorData,
|
||||||
|
Footprint -> VectorData,
|
||||||
|
)]
|
||||||
|
source1: impl Node<F, Output = VectorData>,
|
||||||
|
#[implementations(
|
||||||
|
() -> VectorData,
|
||||||
|
Footprint -> VectorData,
|
||||||
|
)]
|
||||||
|
source2: impl Node<F, Output = VectorData>,
|
||||||
|
#[implementations(
|
||||||
|
() -> VectorData,
|
||||||
|
Footprint -> VectorData,
|
||||||
|
)]
|
||||||
|
source3: impl Node<F, Output = VectorData>,
|
||||||
|
#[implementations(
|
||||||
|
() -> VectorData,
|
||||||
|
Footprint -> VectorData,
|
||||||
|
)]
|
||||||
|
source4: impl Node<F, Output = VectorData>,
|
||||||
|
// TODO: Rename to "progress"
|
||||||
|
#[range((0., 1.))]
|
||||||
|
#[default(0.5)]
|
||||||
|
time: Fraction,
|
||||||
|
#[min(0.)] start_index: IntegerCount,
|
||||||
|
) -> VectorData {
|
||||||
|
let sources = [
|
||||||
|
source0.eval(footprint).await,
|
||||||
|
source1.eval(footprint).await,
|
||||||
|
source2.eval(footprint).await,
|
||||||
|
source3.eval(footprint).await,
|
||||||
|
source4.eval(footprint).await,
|
||||||
|
];
|
||||||
|
let num_segments = sources.len() - 1;
|
||||||
|
let segment_time = time * num_segments as f64;
|
||||||
|
let index = segment_time.floor() as usize;
|
||||||
|
let local_time = segment_time - index as f64;
|
||||||
|
let source = sources[index].clone();
|
||||||
|
let target = sources[(index + 1).min(num_segments)].clone();
|
||||||
|
morph_vector_data(source, target, local_time, start_index)
|
||||||
|
}
|
||||||
|
|
||||||
fn bevel_algorithm(mut vector_data: VectorData, distance: f64) -> VectorData {
|
fn bevel_algorithm(mut vector_data: VectorData, distance: f64) -> VectorData {
|
||||||
// Splits a bézier curve based on a distance measurement
|
// Splits a bézier curve based on a distance measurement
|
||||||
fn split_distance(bezier: bezier_rs::Bezier, distance: f64, length: f64) -> bezier_rs::Bezier {
|
fn split_distance(bezier: bezier_rs::Bezier, distance: f64, length: f64) -> bezier_rs::Bezier {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue