blob: 0adfda9bdf342bc8108e8d51a2ddf3f0ed82beed [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::cell::Cell;
use crate::{
bones::{CubicWeight, Weight},
core::{Core, ObjectRef, OnAdded},
math::{self, Mat},
shapes::{CubicAsymmetricVertex, CubicDetachedVertex, CubicMirroredVertex, PathVertex},
};
#[derive(Debug, Default)]
pub struct CubicVertex {
path_vertex: PathVertex,
in_is_valid: Cell<bool>,
out_is_valid: Cell<bool>,
in_point: Cell<math::Vec>,
out_point: Cell<math::Vec>,
}
impl ObjectRef<'_, CubicVertex> {
pub fn in_point(&self) -> math::Vec {
if !self.in_is_valid.get() {
self.compute_in();
self.in_is_valid.set(true);
}
self.in_point.get()
}
pub fn set_in_point(&self, in_point: math::Vec) {
self.in_point.set(in_point);
self.in_is_valid.set(true);
}
pub fn out_point(&self) -> math::Vec {
if !self.out_is_valid.get() {
self.compute_out();
self.out_is_valid.set(true);
}
self.out_point.get()
}
pub fn set_out_point(&self, out_point: math::Vec) {
self.out_point.set(out_point);
self.out_is_valid.set(true);
}
pub fn render_in(&self) -> math::Vec {
if let Some(weight) = self.cast::<PathVertex>().weight() {
weight.as_ref().cast::<CubicWeight>().in_translation()
} else {
self.in_point()
}
}
pub fn render_out(&self) -> math::Vec {
if let Some(weight) = self.cast::<PathVertex>().weight() {
weight.as_ref().cast::<CubicWeight>().out_translation()
} else {
self.out_point()
}
}
pub fn compute_in(&self) {
if let Some(cubic_asymmetric_vertex) = self.try_cast::<CubicAsymmetricVertex>() {
return cubic_asymmetric_vertex.compute_in();
}
if let Some(cubic_detached_vertex) = self.try_cast::<CubicDetachedVertex>() {
return cubic_detached_vertex.compute_in();
}
if let Some(cubic_mirrored_vertex) = self.try_cast::<CubicMirroredVertex>() {
return cubic_mirrored_vertex.compute_in();
}
unreachable!();
}
pub fn compute_out(&self) {
if let Some(cubic_asymmetric_vertex) = self.try_cast::<CubicAsymmetricVertex>() {
return cubic_asymmetric_vertex.compute_out();
}
if let Some(cubic_detached_vertex) = self.try_cast::<CubicDetachedVertex>() {
return cubic_detached_vertex.compute_out();
}
if let Some(cubic_mirrored_vertex) = self.try_cast::<CubicMirroredVertex>() {
return cubic_mirrored_vertex.compute_out();
}
unreachable!();
}
pub fn deform(&self, world_transform: Mat, bone_transforms: &[Cell<Mat>]) {
let cubic_weight = self
.cast::<PathVertex>()
.weight()
.expect("CubicVertex must have a CubicWeight")
.cast::<CubicWeight>();
let cubic_weight = cubic_weight.as_ref();
let in_point = self.in_point();
cubic_weight.set_in_translation(Weight::deform(
in_point.x,
in_point.y,
cubic_weight.in_indices() as usize,
cubic_weight.in_values() as usize,
world_transform,
bone_transforms,
));
let out_point = self.out_point();
cubic_weight.set_out_translation(Weight::deform(
out_point.x,
out_point.y,
cubic_weight.out_indices() as usize,
cubic_weight.out_values() as usize,
world_transform,
bone_transforms,
));
}
pub(crate) fn invalidate_in(&self) {
self.in_is_valid.set(false);
}
pub(crate) fn invalidate_out(&self) {
self.out_is_valid.set(false);
}
}
impl Core for CubicVertex {
parent_types![(path_vertex, PathVertex)];
properties!(path_vertex);
}
impl OnAdded for ObjectRef<'_, CubicVertex> {
on_added!(PathVertex);
}