lotus_shared/
animation.rs1#[cfg(feature = "bevy")]
2use bevy::prelude::Component;
3use glam::Vec3;
4#[cfg(feature = "ffi")]
5use lotus_script_sys::FfiObject;
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, thiserror::Error)]
9pub enum AnimationError {
10 #[error("animation not found")]
11 AnimationNotFound = 65536,
12 #[error("unknown error")]
13 Unknown = 0,
14}
15
16impl From<u32> for AnimationError {
17 fn from(value: u32) -> Self {
18 match value {
19 65536 => AnimationError::AnimationNotFound,
20 _ => AnimationError::Unknown,
21 }
22 }
23}
24
25#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
26#[cfg_attr(feature = "bevy", derive(Component))]
27pub struct AccelerationVelocity {
28 pub linear_velocity: Vec3,
29 pub linear_acceleration: Vec3,
30 pub angular_velocity: Vec3,
31 pub angular_acceleration: Vec3,
32}
33
34impl AccelerationVelocity {
35 pub fn from_rail_axle_local(
38 longitudinal_velocity: f32,
39 longitudinal_acceleration: f32,
40 inv_radius: f32,
41 elevation_derivation: f32,
42 elevation_second_derivation: f32,
43 axle_rotation: glam::Quat,
44 ) -> Self {
45 let v = longitudinal_velocity;
46 let a_long = longitudinal_acceleration;
47 let lateral_acceleration = v * v * inv_radius;
48 let vertical_acceleration =
49 elevation_second_derivation * v * v + elevation_derivation * a_long;
50
51 let local = Self {
52 linear_velocity: Vec3::new(0.0, v, elevation_derivation * v),
53 linear_acceleration: Vec3::new(lateral_acceleration, a_long, vertical_acceleration),
54 angular_velocity: Vec3::new(0.0, 0.0, v * inv_radius),
55 angular_acceleration: Vec3::new(0.0, 0.0, a_long * inv_radius),
56 };
57
58 local.transform_axes_to_global(axle_rotation)
59 }
60
61 pub fn transform_axes_to_global(self, rotation: glam::Quat) -> Self {
63 Self {
64 linear_velocity: rotation * self.linear_velocity,
65 linear_acceleration: rotation * self.linear_acceleration,
66 angular_velocity: rotation * self.angular_velocity,
67 angular_acceleration: rotation * self.angular_acceleration,
68 }
69 }
70
71 pub fn transform_axes_to_local(self, rotation: glam::Quat) -> Self {
73 let inv = rotation.inverse();
74 Self {
75 linear_velocity: inv * self.linear_velocity,
76 linear_acceleration: inv * self.linear_acceleration,
77 angular_velocity: inv * self.angular_velocity,
78 angular_acceleration: inv * self.angular_acceleration,
79 }
80 }
81
82 pub fn average(self, other: Self) -> Self {
83 Self {
84 linear_velocity: 0.5 * (self.linear_velocity + other.linear_velocity),
85 linear_acceleration: 0.5 * (self.linear_acceleration + other.linear_acceleration),
86 angular_velocity: 0.5 * (self.angular_velocity + other.angular_velocity),
87 angular_acceleration: 0.5 * (self.angular_acceleration + other.angular_acceleration),
88 }
89 }
90
91 pub fn relative_to_parent(
92 self,
93 parent: &AccelerationVelocity,
94 position_relative_to_parent: Vec3,
95 ) -> Self {
96 Self {
97 angular_velocity: parent.angular_velocity + self.angular_velocity,
98 angular_acceleration: parent.angular_acceleration
99 + self.angular_acceleration
100 + parent.angular_velocity.cross(self.angular_velocity),
101 linear_velocity: parent.linear_velocity
102 + parent.angular_velocity.cross(position_relative_to_parent)
103 + self.linear_velocity,
104
105 linear_acceleration: parent.linear_acceleration
106 + parent
107 .angular_acceleration
108 .cross(position_relative_to_parent)
109 + parent
110 .angular_velocity
111 .cross(parent.angular_velocity.cross(position_relative_to_parent))
112 + (2.0 * parent.angular_velocity).cross(self.linear_velocity)
113 + self.linear_acceleration,
114 }
115 }
116
117 pub fn acceleration_at_local_point(self, local_offset: Vec3) -> LocalPointAcceleration {
122 LocalPointAcceleration {
123 linear_acceleration: self.linear_acceleration
124 + self.angular_acceleration.cross(local_offset)
125 + self.angular_velocity.cross(self.angular_velocity.cross(local_offset)),
126 angular_acceleration: self.angular_acceleration,
127 }
128 }
129}
130
131#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
132pub struct LocalPointAcceleration {
133 pub linear_acceleration: Vec3,
134 pub angular_acceleration: Vec3,
135}
136
137#[cfg(feature = "ffi")]
138#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
139pub struct Animation {
140 index: usize,
141}
142
143#[cfg(feature = "ffi")]
144impl Animation {
145 pub fn index(&self) -> usize {
146 self.index
147 }
148
149 pub fn get(name: &str) -> Result<Self, AnimationError> {
150 let name = FfiObject::new(&name);
151
152 match unsafe { lotus_script_sys::animation::get_animation_index(name.packed()) } {
153 65536 => Err(AnimationError::AnimationNotFound),
154 index => Ok(Self {
155 index: index as usize,
156 }),
157 }
158 }
159
160 pub fn get_animation_global_acceleration_velocity(self) -> AccelerationVelocity {
161 let state = unsafe {
162 lotus_script_sys::animation::get_animation_global_acceleration_velocity(
163 self.index as i32,
164 )
165 };
166
167 FfiObject::from_packed(state).deserialize()
168 }
169}