oxygengine_composite_renderer/
mesh_animation_asset_protocol.rs1use anims::phase::Phase;
2use core::{
3 assets::protocol::{AssetLoadResult, AssetProtocol},
4 Ignite, Scalar,
5};
6use serde::{Deserialize, Serialize};
7use std::{collections::HashMap, str::from_utf8};
8
9#[derive(Ignite, Debug, Clone, Serialize, Deserialize)]
10pub struct MeshAnimationSequence {
11 #[serde(default)]
12 pub submesh_alpha: HashMap<usize, Phase>,
13 #[serde(default)]
14 pub submesh_order: HashMap<usize, Phase>,
15 #[serde(default)]
16 pub bone_position_x: HashMap<String, Phase>,
17 #[serde(default)]
18 pub bone_position_y: HashMap<String, Phase>,
19 #[serde(default)]
20 pub bone_rotation: HashMap<String, Phase>,
21 #[serde(default)]
22 pub bone_scale_x: HashMap<String, Phase>,
23 #[serde(default)]
24 pub bone_scale_y: HashMap<String, Phase>,
25 #[serde(skip)]
26 #[ignite(ignore)]
27 length: Scalar,
28}
29
30impl MeshAnimationSequence {
31 pub fn initialize(&mut self) {
32 self.length = 0.0;
33 for key_frames in self.submesh_alpha.values() {
34 self.length = self.length.max(key_frames.duration());
35 }
36 for key_frames in self.submesh_order.values() {
37 self.length = self.length.max(key_frames.duration());
38 }
39 for key_frames in self.bone_position_x.values() {
40 self.length = self.length.max(key_frames.duration());
41 }
42 for key_frames in self.bone_position_y.values() {
43 self.length = self.length.max(key_frames.duration());
44 }
45 for key_frames in self.bone_rotation.values() {
46 self.length = self.length.max(key_frames.duration());
47 }
48 for key_frames in self.bone_scale_x.values() {
49 self.length = self.length.max(key_frames.duration());
50 }
51 for key_frames in self.bone_scale_y.values() {
52 self.length = self.length.max(key_frames.duration());
53 }
54 }
55
56 pub fn length(&self) -> Scalar {
57 self.length
58 }
59
60 pub fn sample_submesh_alpha(&self, time: Scalar, index: usize, current: Scalar) -> Scalar {
61 Self::sample_indexed(&self.submesh_alpha, time, index, current)
62 }
63
64 pub fn sample_submesh_order(&self, time: Scalar, index: usize, current: Scalar) -> Scalar {
65 Self::sample_indexed(&self.submesh_order, time, index, current)
66 }
67
68 pub fn sample_bone_position_x(&self, time: Scalar, name: &str, current: Scalar) -> Scalar {
69 Self::sample_named(&self.bone_position_x, time, name, current)
70 }
71
72 pub fn sample_bone_position_y(&self, time: Scalar, name: &str, current: Scalar) -> Scalar {
73 Self::sample_named(&self.bone_position_y, time, name, current)
74 }
75
76 pub fn sample_bone_rotation(&self, time: Scalar, name: &str, current: Scalar) -> Scalar {
77 Self::sample_named(&self.bone_rotation, time, name, current)
78 }
79
80 pub fn sample_bone_scale_x(&self, time: Scalar, name: &str, current: Scalar) -> Scalar {
81 Self::sample_named(&self.bone_scale_x, time, name, current)
82 }
83
84 pub fn sample_bone_scale_y(&self, time: Scalar, name: &str, current: Scalar) -> Scalar {
85 Self::sample_named(&self.bone_scale_y, time, name, current)
86 }
87
88 fn sample_key_frames(key_frames: &Phase, time: Scalar, current: Scalar) -> Scalar {
89 if key_frames.points().is_empty() {
90 current
91 } else {
92 key_frames.sample(time)
93 }
94 }
95
96 fn sample_indexed(
97 database: &HashMap<usize, Phase>,
98 time: Scalar,
99 index: usize,
100 current: Scalar,
101 ) -> Scalar {
102 database
103 .get(&index)
104 .map(|key_frames| Self::sample_key_frames(key_frames, time, current))
105 .unwrap_or(current)
106 }
107
108 fn sample_named(
109 database: &HashMap<String, Phase>,
110 time: Scalar,
111 name: &str,
112 current: Scalar,
113 ) -> Scalar {
114 database
115 .get(name)
116 .map(|key_frames| Self::sample_key_frames(key_frames, time, current))
117 .unwrap_or(current)
118 }
119}
120
121#[derive(Ignite, Debug, Clone, Serialize, Deserialize)]
122pub struct MeshAnimation {
123 pub sequences: HashMap<String, MeshAnimationSequence>,
124}
125
126impl MeshAnimation {
127 pub fn initialize(&mut self) {
128 for seq in self.sequences.values_mut() {
129 seq.initialize();
130 }
131 }
132}
133
134pub struct MeshAnimationAsset(MeshAnimation);
135
136impl MeshAnimationAsset {
137 pub fn animation(&self) -> &MeshAnimation {
138 &self.0
139 }
140}
141
142pub struct MeshAnimationAssetProtocol;
143
144impl AssetProtocol for MeshAnimationAssetProtocol {
145 fn name(&self) -> &str {
146 "mesh-anim"
147 }
148
149 fn on_load_with_path(&mut self, path: &str, data: Vec<u8>) -> AssetLoadResult {
150 let mut anim = if path.ends_with(".json") {
151 let data = from_utf8(&data).unwrap();
152 serde_json::from_str::<MeshAnimation>(data).unwrap()
153 } else if path.ends_with(".yaml") {
154 let data = from_utf8(&data).unwrap();
155 serde_yaml::from_str::<MeshAnimation>(data).unwrap()
156 } else {
157 bincode::deserialize::<MeshAnimation>(&data).unwrap()
158 };
159 anim.initialize();
160 AssetLoadResult::Data(Box::new(MeshAnimationAsset(anim)))
161 }
162
163 fn on_load(&mut self, _data: Vec<u8>) -> AssetLoadResult {
165 unreachable!()
166 }
167}