1use crate::builder::GltfBuilder;
2use crate::models::{Animation, AnimationChannel, AnimationChannelTarget, AnimationSampler};
3
4pub enum AnimationPath {
6 Translation,
7 Rotation,
8 Scale,
9 Weights,
10}
11
12impl AnimationPath {
13 pub fn to_string(&self) -> String {
15 match self {
16 AnimationPath::Translation => "translation".to_string(),
17 AnimationPath::Rotation => "rotation".to_string(),
18 AnimationPath::Scale => "scale".to_string(),
19 AnimationPath::Weights => "weights".to_string(),
20 }
21 }
22}
23
24pub enum InterpolationType {
26 Linear,
27 Step,
28 CubicSpline,
29}
30
31impl InterpolationType {
32 pub fn to_string(&self) -> String {
34 match self {
35 InterpolationType::Linear => "LINEAR".to_string(),
36 InterpolationType::Step => "STEP".to_string(),
37 InterpolationType::CubicSpline => "CUBICSPLINE".to_string(),
38 }
39 }
40}
41
42impl GltfBuilder {
43 pub fn add_animation(&mut self, name: Option<String>) -> usize {
53 let animation = Animation {
54 name,
55 channels: Some(Vec::new()),
56 samplers: Some(Vec::new()),
57 };
58
59 if let Some(animations) = &mut self.gltf.animations {
60 let index = animations.len();
61 animations.push(animation);
62 index
63 } else {
64 self.gltf.animations = Some(vec![animation]);
65 0
66 }
67 }
68
69 pub fn add_animation_sampler(
82 &mut self,
83 animation_index: usize,
84 input_accessor: usize,
85 output_accessor: usize,
86 interpolation: InterpolationType
87 ) -> usize {
88 let sampler = AnimationSampler {
89 input: input_accessor,
90 interpolation: Some(interpolation.to_string()),
91 output: output_accessor,
92 };
93
94 let animations = self.gltf.animations.as_mut().expect("Animations array not initialized");
95 if animation_index >= animations.len() {
96 panic!("Animation index out of bounds");
97 }
98
99 let animation = &mut animations[animation_index];
100 let samplers = animation.samplers.get_or_insert_with(|| Vec::new());
101 let sampler_index = samplers.len();
102 samplers.push(sampler);
103
104 sampler_index
105 }
106
107 pub fn add_animation_channel(
120 &mut self,
121 animation_index: usize,
122 sampler_index: usize,
123 target_node: usize,
124 target_path: AnimationPath
125 ) -> usize {
126 let channel = AnimationChannel {
127 sampler: sampler_index,
128 target: AnimationChannelTarget {
129 node: target_node,
130 path: target_path.to_string(),
131 }
132 };
133
134 let animations = self.gltf.animations.as_mut().expect("Animations array not initialized");
135 if animation_index >= animations.len() {
136 panic!("Animation index out of bounds");
137 }
138
139 let animation = &mut animations[animation_index];
140 let channels = animation.channels.get_or_insert_with(|| Vec::new());
141 let channel_index = channels.len();
142 channels.push(channel);
143
144 channel_index
145 }
146
147 pub fn create_translation_animation(
161 &mut self,
162 animation_index: usize,
163 node_index: usize,
164 timestamps: Vec<f32>,
165 translations: Vec<[f32; 3]>,
166 interpolation: InterpolationType,
167 ) -> (usize, usize) {
168 if timestamps.len() != translations.len() {
169 panic!("Timestamps and translations must have the same length");
170 }
171
172 let timestamps_data: Vec<u8> = timestamps.iter().flat_map(|&t| t.to_le_bytes()).collect();
174
175 let (time_offset, time_length) = self.add_buffer_data(×tamps_data);
177 let time_buffer_view = self.add_buffer_view(
178 time_offset,
179 time_length,
180 None
181 );
182
183 let input_accessor = self.add_accessor(
185 time_buffer_view,
186 5126, timestamps.len(),
188 "SCALAR".to_string(),
189 None,
190 None,
191 None
192 );
193
194 let translations_data: Vec<u8> = translations.iter().flat_map(|t| t.iter().flat_map(|&v| v.to_le_bytes())).collect();
196
197 let (trans_offset, trans_length) = self.add_buffer_data(&translations_data);
199 let trans_buffer_view = self.add_buffer_view(
200 trans_offset,
201 trans_length,
202 None
203 );
204
205 let output_accessor = self.add_accessor(
207 trans_buffer_view,
208 5126, translations.len(),
210 "VEC3".to_string(),
211 None,
212 None,
213 None
214 );
215
216 let sampler_index = self.add_animation_sampler(
218 animation_index,
219 input_accessor,
220 output_accessor,
221 interpolation,
222 );
223
224 let channel_index = self.add_animation_channel(
225 animation_index,
226 sampler_index,
227 node_index,
228 AnimationPath::Translation,
229 );
230
231 (channel_index, sampler_index)
232 }
233
234 pub fn create_rotation_animation(
248 &mut self,
249 animation_index: usize,
250 node_index: usize,
251 timestamps: Vec<f32>,
252 rotations: Vec<[f32; 4]>,
253 interpolation: InterpolationType,
254 ) -> (usize, usize) {
255 if timestamps.len() != rotations.len() {
256 panic!("Timestamps and rotations must have the same length");
257 }
258
259 let timestamps_data: Vec<u8> = timestamps.iter().flat_map(|&t| t.to_le_bytes()).collect();
261
262 let (time_offset, time_length) = self.add_buffer_data(×tamps_data);
264 let time_buffer_view = self.add_buffer_view(
265 time_offset,
266 time_length,
267 None
268 );
269
270 let input_accessor = self.add_accessor(
272 time_buffer_view,
273 5126, timestamps.len(),
275 "SCALAR".to_string(),
276 None,
277 None,
278 None
279 );
280
281 let rotations_data: Vec<u8> = rotations.iter().flat_map(|q| q.iter().flat_map(|&v| v.to_le_bytes())).collect();
283
284 let (rot_offset, rot_length) = self.add_buffer_data(&rotations_data);
286 let rot_buffer_view = self.add_buffer_view(
287 rot_offset,
288 rot_length,
289 None
290 );
291
292 let output_accessor = self.add_accessor(
294 rot_buffer_view,
295 5126, rotations.len(),
297 "VEC4".to_string(),
298 None,
299 None,
300 None
301 );
302
303 let sampler_index = self.add_animation_sampler(
305 animation_index,
306 input_accessor,
307 output_accessor,
308 interpolation,
309 );
310
311 let channel_index = self.add_animation_channel(
312 animation_index,
313 sampler_index,
314 node_index,
315 AnimationPath::Rotation,
316 );
317
318 (channel_index, sampler_index)
319 }
320
321 pub fn create_scale_animation(
335 &mut self,
336 animation_index: usize,
337 node_index: usize,
338 timestamps: Vec<f32>,
339 scales: Vec<[f32; 3]>,
340 interpolation: InterpolationType,
341 ) -> (usize, usize) {
342 if timestamps.len() != scales.len() {
343 panic!("Timestamps and scales must have the same length");
344 }
345
346 let timestamps_data: Vec<u8> = timestamps.iter().flat_map(|&t| t.to_le_bytes()).collect();
348
349 let (time_offset, time_length) = self.add_buffer_data(×tamps_data);
351 let time_buffer_view = self.add_buffer_view(
352 time_offset,
353 time_length,
354 None
355 );
356
357 let input_accessor = self.add_accessor(
359 time_buffer_view,
360 5126, timestamps.len(),
362 "SCALAR".to_string(),
363 None,
364 None,
365 None
366 );
367
368 let scales_data: Vec<u8> = scales.iter().flat_map(|s| s.iter().flat_map(|&v| v.to_le_bytes())).collect();
370
371 let (scale_offset, scale_length) = self.add_buffer_data(&scales_data);
373 let scale_buffer_view = self.add_buffer_view(
374 scale_offset,
375 scale_length,
376 None
377 );
378
379 let output_accessor = self.add_accessor(
381 scale_buffer_view,
382 5126, scales.len(),
384 "VEC3".to_string(),
385 None,
386 None,
387 None
388 );
389
390 let sampler_index = self.add_animation_sampler(
392 animation_index,
393 input_accessor,
394 output_accessor,
395 interpolation,
396 );
397
398 let channel_index = self.add_animation_channel(
399 animation_index,
400 sampler_index,
401 node_index,
402 AnimationPath::Scale,
403 );
404
405 (channel_index, sampler_index)
406 }
407}