fix animation

This commit is contained in:
Adam
2025-07-16 18:36:22 -07:00
parent 04ff7b75e5
commit c2815ea0e3
30 changed files with 258 additions and 386 deletions

View File

@@ -41,7 +41,7 @@ pub trait ExtractAnimationTime {
}
pub trait ExtractIndex {
fn try_index(&self) -> Option<Vec<usize>>;
fn try_index(&self) -> Option<usize>;
}
// Consider returning a slice or something like that
@@ -231,7 +231,7 @@ impl<T: ExtractAnimationTime + Sync> ExtractAnimationTime for Option<T> {
}
}
impl<T: ExtractIndex> ExtractIndex for Option<T> {
fn try_index(&self) -> Option<Vec<usize>> {
fn try_index(&self) -> Option<usize> {
self.as_ref().and_then(|x| x.try_index())
}
}
@@ -263,7 +263,7 @@ impl<T: ExtractAnimationTime + Sync> ExtractAnimationTime for Arc<T> {
}
}
impl<T: ExtractIndex> ExtractIndex for Arc<T> {
fn try_index(&self) -> Option<Vec<usize>> {
fn try_index(&self) -> Option<usize> {
(**self).try_index()
}
}
@@ -316,7 +316,7 @@ impl ExtractAnimationTime for OwnedContextImpl {
}
}
impl ExtractIndex for OwnedContextImpl {
fn try_index(&self) -> Option<Vec<usize>> {
fn try_index(&self) -> Option<usize> {
self.index.clone()
}
}
@@ -630,8 +630,8 @@ fn get_animation_time(ctx: impl Ctx + ExtractAnimationTime) -> Option<f64> {
}
#[node_macro::node(category("Context Getter"))]
fn get_index(ctx: impl Ctx + ExtractIndex) -> Option<u32> {
ctx.try_index().map(|index| index as u32)
fn get_index(ctx: impl Ctx + ExtractIndex) -> Option<usize> {
ctx.try_index()
}
// #[node_macro::node(category("Loop"))]
@@ -671,21 +671,21 @@ fn get_index(ctx: impl Ctx + ExtractIndex) -> Option<u32> {
// }
// }
#[node_macro::node(category("Loop"))]
async fn set_index<T: 'n + 'static>(
ctx: impl Ctx + ExtractAll + CloneVarArgs + Sync,
#[expose]
#[implementations(
Context -> u32,
Context -> (),
)]
input: impl Node<Context<'static>, Output = T>,
number: u32,
) -> T {
let mut new_context = OwnedContextImpl::from(ctx);
new_context.index = Some(number.try_into().unwrap());
input.eval(new_context.into_context()).await
}
// #[node_macro::node(category("Loop"))]
// async fn set_index<T: 'n + 'static>(
// ctx: impl Ctx + ExtractAll + CloneVarArgs + Sync,
// #[expose]
// #[implementations(
// Context -> u32,
// Context -> (),
// )]
// input: impl Node<Context<'static>, Output = T>,
// number: u32,
// ) -> T {
// let mut new_context = OwnedContextImpl::from(ctx);
// new_context.index = Some(number.try_into().unwrap());
// input.eval(new_context.into_context()).await
// }
// #[node_macro::node(category("Loop"))]
// fn create_arc_mutex(_ctx: impl Ctx) -> Arc<Mutex<Option<OwnedContextImpl>>> {

View File

@@ -86,10 +86,10 @@ async fn instance_position(ctx: impl Ctx + ExtractVarArgs) -> DVec2 {
// TODO: Make this return a u32 instead of an f64, but we ned to improve math-related compatibility with integer types first.
#[node_macro::node(category("Instancing"), path(graphene_core::vector))]
async fn instance_index(ctx: impl Ctx + ExtractIndex, _primary: (), loop_level: u32) -> f64 {
ctx.try_index()
.and_then(|indexes| indexes.get(indexes.len().wrapping_sub(1).wrapping_sub(loop_level as usize)).copied())
.unwrap_or_default() as f64
async fn instance_index(ctx: impl Ctx + ExtractIndex, _primary: (), _loop_level: u32) -> f64 {
ctx.try_index().unwrap_or_default() as f64
// .and_then(|indexes| indexes.get(indexes.len().wrapping_sub(1).wrapping_sub(loop_level as usize)).copied())
// .unwrap_or_default() as f64
}
// #[cfg(test)]

View File

@@ -20,7 +20,8 @@ use glam::{DAffine2, DVec2};
use kurbo::{Affine, BezPath, DEFAULT_ACCURACY, ParamCurve, PathEl, PathSeg, Shape};
use rand::{Rng, SeedableRng};
use std::collections::hash_map::DefaultHasher;
use std::f64::consts::TAU;
use std::f64::consts::{PI, TAU};
use std::hash::{Hash, Hasher};
/// Implemented for types that can be converted to an iterator of vector data.
/// Used for the fill and stroke node so they can be used on VectorData or GraphicGroup
@@ -1732,7 +1733,7 @@ async fn morph(_: impl Ctx, source: VectorDataTable, #[expose] target: VectorDat
fn bevel_algorithm(mut vector_data: VectorData, vector_data_transform: DAffine2, distance: f64) -> VectorData {
// Splits a bézier curve based on a distance measurement
fn split_distance(bezier: PathSeg, distance: f64, length: f64) -> PathSeg {
let parametric = eval_pathseg_euclidean(bezier, (distance / length).clamp(0., 1.), DEFAULT_ACCURACY);
let parametric = bezpath_algorithms::eval_pathseg_euclidean(bezier, (distance / length).clamp(0., 1.), DEFAULT_ACCURACY);
bezier.subsegment(parametric..1.)
}
@@ -1773,7 +1774,7 @@ fn bevel_algorithm(mut vector_data: VectorData, vector_data_transform: DAffine2,
}
fn calculate_distance_to_spilt(bezier1: PathSeg, bezier2: PathSeg, bevel_length: f64) -> f64 {
if is_linear(&bezier1) && is_linear(&bezier2) {
if bezpath_algorithms::is_linear(&bezier1) && bezpath_algorithms::is_linear(&bezier2) {
let v1 = (bezier1.end() - bezier1.start()).normalize();
let v2 = (bezier1.end() - bezier2.end()).normalize();
@@ -1798,8 +1799,8 @@ fn bevel_algorithm(mut vector_data: VectorData, vector_data_transform: DAffine2,
for i in 0..=INITIAL_SAMPLES {
let distance_sample = max_split * (i as f64 / INITIAL_SAMPLES as f64);
let x_point_t = eval_pathseg_euclidean(bezier1, 1. - clamp_and_round(distance_sample / length1), DEFAULT_ACCURACY);
let y_point_t = eval_pathseg_euclidean(bezier2, clamp_and_round(distance_sample / length2), DEFAULT_ACCURACY);
let x_point_t = bezpath_algorithms::eval_pathseg_euclidean(bezier1, 1. - clamp_and_round(distance_sample / length1), DEFAULT_ACCURACY);
let y_point_t = bezpath_algorithms::eval_pathseg_euclidean(bezier2, clamp_and_round(distance_sample / length2), DEFAULT_ACCURACY);
let x_point = bezier1.eval(x_point_t);
let y_point = bezier2.eval(y_point_t);
@@ -1822,8 +1823,8 @@ fn bevel_algorithm(mut vector_data: VectorData, vector_data_transform: DAffine2,
for j in 1..=REFINE_STEPS {
let refined_sample = prev_sample + (distance_sample - prev_sample) * (j as f64 / REFINE_STEPS as f64);
let x_point_t = eval_pathseg_euclidean(bezier1, 1. - (refined_sample / length1).clamp(0., 1.), DEFAULT_ACCURACY);
let y_point_t = eval_pathseg_euclidean(bezier2, (refined_sample / length2).clamp(0., 1.), DEFAULT_ACCURACY);
let x_point_t = bezpath_algorithms::eval_pathseg_euclidean(bezier1, 1. - (refined_sample / length1).clamp(0., 1.), DEFAULT_ACCURACY);
let y_point_t = bezpath_algorithms::eval_pathseg_euclidean(bezier2, (refined_sample / length2).clamp(0., 1.), DEFAULT_ACCURACY);
let x_point = bezier1.eval(x_point_t);
let y_point = bezier2.eval(y_point_t);
@@ -1911,16 +1912,16 @@ fn bevel_algorithm(mut vector_data: VectorData, vector_data_transform: DAffine2,
let spilt_distance = calculate_distance_to_spilt(bezier, next_bezier, distance);
if is_linear(&bezier) {
if bezpath_algorithms::is_linear(&bezier) {
let start = point_to_dvec2(bezier.start());
let end = point_to_dvec2(bezier.end());
bezier = handles_to_segment(start, BezierHandles::Linear, end);
bezier = handles_to_segment(start, bezier_rs::BezierHandles::Linear, end);
}
if is_linear(&next_bezier) {
if bezpath_algorithms::is_linear(&next_bezier) {
let start = point_to_dvec2(next_bezier.start());
let end = point_to_dvec2(next_bezier.end());
next_bezier = handles_to_segment(start, BezierHandles::Linear, end);
next_bezier = handles_to_segment(start, bezier_rs::BezierHandles::Linear, end);
}
let inverse_transform = (vector_data_transform.matrix2.determinant() != 0.).then(|| vector_data_transform.inverse()).unwrap_or_default();

View File

@@ -13,7 +13,6 @@ use graphene_core::uuid::NodeId;
use graphene_core::vector::style::Fill;
use graphene_core::{Color, MemoHash, Node, Type};
use graphene_svg_renderer::{GraphicElementRendered, RenderMetadata};
use std::cell::Cell;
use std::fmt::Display;
use std::hash::Hash;
use std::marker::PhantomData;
@@ -564,6 +563,7 @@ thumbnail_render! {
graphene_core::GraphicElement,
Option<Color>,
Vec<Color>,
f64,
}
pub enum ThumbnailRenderResult {

View File

@@ -3,6 +3,7 @@ pub use graph_craft::proto::{Any, NodeContainer, TypeErasedBox, TypeErasedNode};
use graph_craft::proto::{DynFuture, FutureAny, SharedNodeContainer};
use graphene_core::Context;
use graphene_core::ContextDependencies;
use graphene_core::EditorContext;
use graphene_core::NodeIO;
use graphene_core::OwnedContextImpl;
use graphene_core::WasmNotSend;

View File

@@ -1,4 +1,4 @@
use crate::vector::{VectorData, VectorDataTable};
use crate::vector::{VectorDataTable};
use graphene_core::Ctx;
pub use graphene_core::text::*;

View File

@@ -213,6 +213,7 @@ pub trait GraphicElementRendered: BoundingBox + RenderComplexity {
fn render_thumbnail(&self) -> String {
let Some(bounds) = self.bounding_box(DAffine2::IDENTITY, true) else {
log::debug!("Could not get bounds");
return String::new();
};
@@ -228,7 +229,7 @@ pub trait GraphicElementRendered: BoundingBox + RenderComplexity {
let mut render = SvgRender::new();
self.render_svg(&mut render, &render_params);
// let center = (bounds[0] + bounds[1]) / 2.;
// let size = bounds[1] - bounds[0];
@@ -1193,13 +1194,13 @@ impl Primitive for f64 {}
impl Primitive for DVec2 {}
fn text_attributes(attributes: &mut SvgRenderAttrs) {
attributes.push("fill", "white");
attributes.push("y", "30");
attributes.push("fill", "black");
attributes.push("font-size", "30");
}
impl<P: Primitive> GraphicElementRendered for P {
fn render_svg(&self, render: &mut SvgRender, _render_params: &RenderParams) {
log::debug!("Rendering svg for primative: {}", self);
render.parent_tag("text", text_attributes, |render| render.leaf_node(format!("{self}")));
}