1use crate::attribute_transform_data::AttributeTransformData;
2use crate::data_buffer::DataBuffer;
3use crate::draco_types::DataType;
4use crate::geometry_indices::{AttributeValueIndex, PointIndex, INVALID_ATTRIBUTE_VALUE_INDEX};
5use crate::status::DracoError;
6use std::convert::TryFrom;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum GeometryAttributeType {
11 Invalid = -1,
13 Position = 0,
15 Normal,
17 Color,
19 TexCoord,
21 Generic,
23}
24
25impl TryFrom<u8> for GeometryAttributeType {
26 type Error = DracoError;
27
28 fn try_from(value: u8) -> Result<Self, Self::Error> {
29 match value {
30 0 => Ok(Self::Position),
31 1 => Ok(Self::Normal),
32 2 => Ok(Self::Color),
33 3 => Ok(Self::TexCoord),
34 4 => Ok(Self::Generic),
35 _ => Err(DracoError::DracoError(format!(
36 "Invalid geometry attribute type: {value}"
37 ))),
38 }
39 }
40}
41
42#[derive(Debug, Clone)]
44pub struct GeometryAttribute {
45 attribute_type: GeometryAttributeType,
46 data_type: DataType,
47 num_components: u8,
48 normalized: bool,
49 byte_stride: i64,
50 byte_offset: i64,
51 unique_id: u32,
52}
53
54impl Default for GeometryAttribute {
55 fn default() -> Self {
56 Self {
57 attribute_type: GeometryAttributeType::Invalid,
58 data_type: DataType::Invalid,
59 num_components: 0,
60 normalized: false,
61 byte_stride: 0,
62 byte_offset: 0,
63 unique_id: 0,
64 }
65 }
66}
67
68impl GeometryAttribute {
69 #[allow(clippy::too_many_arguments)]
75 pub fn init(
76 &mut self,
77 attribute_type: GeometryAttributeType,
78 _buffer: Option<&DataBuffer>,
79 num_components: u8,
80 data_type: DataType,
81 normalized: bool,
82 byte_stride: i64,
83 byte_offset: i64,
84 ) {
85 self.attribute_type = attribute_type;
86 self.num_components = num_components;
87 self.data_type = data_type;
88 self.normalized = normalized;
89 self.byte_stride = byte_stride;
90 self.byte_offset = byte_offset;
91 }
92
93 pub fn attribute_type(&self) -> GeometryAttributeType {
95 self.attribute_type
96 }
97
98 pub fn data_type(&self) -> DataType {
100 self.data_type
101 }
102
103 pub fn num_components(&self) -> u8 {
105 self.num_components
106 }
107
108 pub fn normalized(&self) -> bool {
110 self.normalized
111 }
112
113 pub fn byte_stride(&self) -> i64 {
115 self.byte_stride
116 }
117
118 pub fn byte_offset(&self) -> i64 {
120 self.byte_offset
121 }
122
123 pub fn unique_id(&self) -> u32 {
125 self.unique_id
126 }
127
128 pub fn set_unique_id(&mut self, id: u32) {
130 self.unique_id = id;
131 }
132
133 pub fn set_attribute_type(&mut self, attribute_type: GeometryAttributeType) {
135 self.attribute_type = attribute_type;
136 }
137
138 pub fn set_data_type(&mut self, data_type: DataType) {
140 self.data_type = data_type;
141 }
142
143 pub fn set_num_components(&mut self, num_components: u8) {
145 self.num_components = num_components;
146 }
147}
148
149#[derive(Debug, Clone)]
155pub struct PointAttribute {
156 base: GeometryAttribute,
157 buffer: DataBuffer,
158 indices_map: Vec<AttributeValueIndex>,
159 identity_mapping: bool,
160 num_unique_entries: usize,
161 attribute_transform_data: Option<Box<AttributeTransformData>>,
162}
163
164impl Default for PointAttribute {
165 fn default() -> Self {
166 Self {
167 base: GeometryAttribute::default(),
168 buffer: DataBuffer::new(),
169 indices_map: Vec::new(),
170 identity_mapping: true,
171 num_unique_entries: 0,
172 attribute_transform_data: None,
173 }
174 }
175}
176
177impl PointAttribute {
178 pub fn new() -> Self {
180 Self::default()
181 }
182
183 pub fn init(
185 &mut self,
186 attribute_type: GeometryAttributeType,
187 num_components: u8,
188 data_type: DataType,
189 normalized: bool,
190 num_attribute_values: usize,
191 ) {
192 let byte_stride = (num_components as usize * data_type.byte_length()) as i64;
193 self.base.init(
194 attribute_type,
195 None,
196 num_components,
197 data_type,
198 normalized,
199 byte_stride,
200 0,
201 );
202 self.buffer
203 .resize(num_attribute_values * byte_stride as usize);
204 self.num_unique_entries = num_attribute_values;
205 self.identity_mapping = true;
206 }
207
208 pub fn try_init(
210 &mut self,
211 attribute_type: GeometryAttributeType,
212 num_components: u8,
213 data_type: DataType,
214 normalized: bool,
215 num_attribute_values: usize,
216 ) -> Result<(), DracoError> {
217 let byte_stride = num_components as usize * data_type.byte_length();
218 let buffer_size = num_attribute_values
219 .checked_mul(byte_stride)
220 .ok_or_else(|| {
221 DracoError::DracoError("Point attribute buffer size overflow".to_string())
222 })?;
223 self.base.init(
224 attribute_type,
225 None,
226 num_components,
227 data_type,
228 normalized,
229 byte_stride as i64,
230 0,
231 );
232 self.buffer.try_resize(buffer_size).map_err(|_| {
233 DracoError::DracoError("Failed to allocate point attribute buffer".to_string())
234 })?;
235 self.num_unique_entries = num_attribute_values;
236 self.identity_mapping = true;
237 Ok(())
238 }
239
240 pub fn mapped_index(&self, point_index: PointIndex) -> AttributeValueIndex {
242 if self.identity_mapping {
243 AttributeValueIndex(point_index.0)
244 } else if (point_index.0 as usize) < self.indices_map.len() {
245 self.indices_map[point_index.0 as usize]
246 } else {
247 INVALID_ATTRIBUTE_VALUE_INDEX
248 }
249 }
250
251 pub fn size(&self) -> usize {
253 self.num_unique_entries
254 }
255
256 pub fn resize_unique_entries(&mut self, num_attribute_values: usize) -> Result<(), DracoError> {
258 let byte_stride = self.byte_stride() as usize;
259 let buffer_size = num_attribute_values
260 .checked_mul(byte_stride)
261 .ok_or_else(|| {
262 DracoError::DracoError("Point attribute buffer size overflow".to_string())
263 })?;
264 self.buffer.try_resize(buffer_size).map_err(|_| {
265 DracoError::DracoError("Failed to allocate point attribute buffer".to_string())
266 })?;
267 self.num_unique_entries = num_attribute_values;
268 if self.identity_mapping {
269 self.indices_map.clear();
270 }
271 Ok(())
272 }
273
274 pub fn buffer(&self) -> &DataBuffer {
276 &self.buffer
277 }
278
279 pub fn buffer_mut(&mut self) -> &mut DataBuffer {
281 &mut self.buffer
282 }
283
284 pub fn attribute_type(&self) -> GeometryAttributeType {
286 self.base.attribute_type()
287 }
288
289 pub fn unique_id(&self) -> u32 {
291 self.base.unique_id()
292 }
293
294 pub fn set_unique_id(&mut self, id: u32) {
296 self.base.set_unique_id(id);
297 }
298
299 pub fn set_attribute_type(&mut self, attribute_type: GeometryAttributeType) {
301 self.base.set_attribute_type(attribute_type);
302 }
303
304 pub fn set_data_type(&mut self, data_type: DataType) {
306 self.base.set_data_type(data_type);
307 }
308
309 pub fn set_num_components(&mut self, num_components: u8) {
311 self.base.set_num_components(num_components);
312 }
313
314 pub fn set_identity_mapping(&mut self) {
316 self.identity_mapping = true;
317 self.indices_map.clear();
318 }
319
320 pub fn set_explicit_mapping(&mut self, num_points: usize) {
322 self.identity_mapping = false;
323 self.indices_map
324 .resize(num_points, INVALID_ATTRIBUTE_VALUE_INDEX);
325 }
326
327 pub fn set_point_map_entry(
329 &mut self,
330 point_index: PointIndex,
331 entry_index: AttributeValueIndex,
332 ) {
333 self.try_set_point_map_entry(point_index, entry_index)
334 .expect("point map entry must be in range");
335 }
336
337 pub fn try_set_point_map_entry(
339 &mut self,
340 point_index: PointIndex,
341 entry_index: AttributeValueIndex,
342 ) -> Result<(), DracoError> {
343 if self.identity_mapping {
344 return Ok(());
345 }
346 let Some(slot) = self.indices_map.get_mut(point_index.0 as usize) else {
347 return Err(DracoError::DracoError(
348 "Point map entry index out of range".to_string(),
349 ));
350 };
351 *slot = entry_index;
352 Ok(())
353 }
354
355 pub fn set_attribute_transform_data(&mut self, data: AttributeTransformData) {
357 self.attribute_transform_data = Some(Box::new(data));
358 }
359
360 pub fn attribute_transform_data(&self) -> Option<&AttributeTransformData> {
362 self.attribute_transform_data.as_deref()
363 }
364
365 pub fn data_type(&self) -> DataType {
367 self.base.data_type()
368 }
369
370 pub fn normalized(&self) -> bool {
372 self.base.normalized()
373 }
374
375 pub fn num_components(&self) -> u8 {
377 self.base.num_components()
378 }
379
380 pub fn byte_stride(&self) -> i64 {
382 self.base.byte_stride()
383 }
384}
385
386#[cfg(test)]
387mod tests {
388 use super::*;
389
390 #[test]
391 fn try_set_point_map_entry_rejects_out_of_range_point() {
392 let mut attribute = PointAttribute::new();
393 attribute.set_explicit_mapping(1);
394
395 assert!(attribute
396 .try_set_point_map_entry(PointIndex(1), AttributeValueIndex(0))
397 .is_err());
398 }
399}