1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//! Keyframe animation container built on top of [`PointCloud`].
//!
//! Mirrors C++ Draco's `draco/animation/keyframe_animation.h`. A
//! [`KeyframeAnimation`] is a point cloud whose first attribute (unique id `0`)
//! always stores per-frame `f32` timestamps and whose remaining attributes each
//! store one keyframe track. Because Draco implements keyframe animation as a
//! point-cloud-like sequential stream, encode/decode reuse the existing
//! sequential point-cloud path (see [`crate::keyframe_animation_encoder`] and
//! [`crate::keyframe_animation_decoder`]).
use crate::draco_types::DataType;
use crate::geometry_attribute::{GeometryAttributeType, PointAttribute};
use crate::point_cloud::PointCloud;
/// Attribute unique id reserved for the timestamp track.
const TIMESTAMP_ID: u32 = 0;
/// Holds keyframe animation data as a [`PointCloud`].
///
/// The first attribute is always the timestamp track. Each additional attribute
/// is one keyframe track with the same number of frames.
#[derive(Debug, Default, Clone)]
pub struct KeyframeAnimation {
point_cloud: PointCloud,
}
impl KeyframeAnimation {
/// Creates an empty keyframe animation.
pub fn new() -> Self {
Self::default()
}
/// Wraps an existing point cloud (e.g. a freshly decoded one).
pub fn from_point_cloud(point_cloud: PointCloud) -> Self {
Self { point_cloud }
}
/// Returns the number of animation frames (equal to the point count).
pub fn num_frames(&self) -> i32 {
self.point_cloud.num_points() as i32
}
/// Sets the number of animation frames (equal to the point count).
pub fn set_num_frames(&mut self, num_frames: i32) {
self.point_cloud.set_num_points(num_frames.max(0) as usize);
}
/// Returns the number of keyframe tracks (attributes minus the timestamp).
pub fn num_animations(&self) -> i32 {
self.point_cloud.num_attributes() - 1
}
/// Sets the per-frame timestamps. Must be called only once, before any
/// keyframe data is added unless a track was added first.
///
/// Returns `false` if a timestamp track already holds data or if the frame
/// count is inconsistent with previously added keyframes. Mirrors C++
/// `KeyframeAnimation::SetTimestamps`.
pub fn set_timestamps(&mut self, timestamps: &[f32]) -> bool {
let num_frames = timestamps.len() as i32;
if self.point_cloud.num_attributes() > 0 {
// Timestamp attribute may be set only once.
match self.timestamps() {
Some(ts) if ts.size() > 0 => return false,
_ => {}
}
// Frame count must match keyframes added earlier.
if num_frames != self.num_frames() {
return false;
}
} else {
// This is the first attribute.
self.set_num_frames(num_frames);
}
let mut timestamp_att = PointAttribute::new();
timestamp_att.init(
GeometryAttributeType::Generic,
1,
DataType::Float32,
false,
num_frames as usize,
);
let bytes: &[u8] = bytemuck::cast_slice(timestamps);
timestamp_att.buffer_mut().write(0, bytes);
self.point_cloud
.set_attribute(TIMESTAMP_ID as i32, timestamp_att);
true
}
/// Adds one keyframe track and returns its animation id, or `-1` on error.
///
/// `num_components` is the number of scalar components per frame, and `data`
/// holds `num_components * num_frames` values laid out frame-major. Mirrors
/// C++ `KeyframeAnimation::AddKeyframes`.
pub fn add_keyframes<T: bytemuck::NoUninit>(
&mut self,
data_type: DataType,
num_components: u32,
data: &[T],
) -> i32 {
if num_components == 0 {
return -1;
}
// Reserve attribute id 0 for timestamps if nothing has been added yet.
if self.point_cloud.num_attributes() == 0 {
let mut temp_att = PointAttribute::new();
temp_att.init(
GeometryAttributeType::Generic,
num_components as u8,
data_type,
false,
0,
);
self.point_cloud.add_attribute(temp_att);
self.set_num_frames(data.len() as i32 / num_components as i32);
}
if data.len() != num_components as usize * self.num_frames() as usize {
return -1;
}
let mut keyframe_att = PointAttribute::new();
keyframe_att.init(
GeometryAttributeType::Generic,
num_components as u8,
data_type,
false,
self.num_frames() as usize,
);
let bytes: &[u8] = bytemuck::cast_slice(data);
keyframe_att.buffer_mut().write(0, bytes);
self.point_cloud.add_attribute(keyframe_att)
}
/// Returns the timestamp track, if present.
pub fn timestamps(&self) -> Option<&PointAttribute> {
self.point_cloud.attribute_by_unique_id(TIMESTAMP_ID)
}
/// Returns the keyframe track identified by `animation_id`, if present.
pub fn keyframes(&self, animation_id: i32) -> Option<&PointAttribute> {
if animation_id < 0 {
return None;
}
self.point_cloud.attribute_by_unique_id(animation_id as u32)
}
/// Returns the underlying point cloud.
pub fn point_cloud(&self) -> &PointCloud {
&self.point_cloud
}
/// Consumes the animation, returning the underlying point cloud.
pub fn into_point_cloud(self) -> PointCloud {
self.point_cloud
}
}