draco_core/
point_cloud_encoder.rs1use crate::compression_config::EncodedGeometryType;
2use crate::encoder_buffer::EncoderBuffer;
3use crate::encoder_options::EncoderOptions;
4use crate::geometry_attribute::GeometryAttributeType;
5use crate::geometry_indices::PointIndex;
6use crate::kd_tree_attributes_encoder::KdTreeAttributesEncoder;
7use crate::mesh::Mesh;
8use crate::metadata::METADATA_FLAG_MASK;
9use crate::point_cloud::PointCloud;
10use crate::sequential_integer_attribute_encoder::SequentialIntegerAttributeEncoder;
11use crate::sequential_normal_attribute_encoder::SequentialNormalAttributeEncoder;
12use crate::status::{DracoError, Status};
13use crate::version::{
14 has_header_flags, uses_varint_encoding, uses_varint_unique_id,
15 DEFAULT_POINT_CLOUD_KD_TREE_VERSION, DEFAULT_POINT_CLOUD_SEQUENTIAL_VERSION,
16};
17
18use crate::corner_table::CornerTable;
19
20pub trait GeometryEncoder {
22 fn point_cloud(&self) -> Option<&PointCloud>;
24 fn mesh(&self) -> Option<&Mesh>;
26 fn corner_table(&self) -> Option<&CornerTable>;
28 fn options(&self) -> &EncoderOptions;
30 fn get_geometry_type(&self) -> EncodedGeometryType;
32 fn get_encoding_method(&self) -> Option<i32> {
34 None
35 }
36 fn get_data_to_corner_map(&self) -> Option<&[u32]> {
38 None
39 }
40 fn get_vertex_to_data_map(&self) -> Option<&[i32]> {
42 None
43 }
44}
45
46pub struct PointCloudEncoder {
83 point_cloud: Option<PointCloud>,
84 options: EncoderOptions,
85}
86
87impl GeometryEncoder for PointCloudEncoder {
88 fn point_cloud(&self) -> Option<&PointCloud> {
89 self.point_cloud.as_ref()
90 }
91
92 fn mesh(&self) -> Option<&Mesh> {
93 None
94 }
95
96 fn corner_table(&self) -> Option<&CornerTable> {
97 None
98 }
99
100 fn options(&self) -> &EncoderOptions {
101 &self.options
102 }
103
104 fn get_geometry_type(&self) -> EncodedGeometryType {
105 EncodedGeometryType::PointCloud
106 }
107}
108
109impl Default for PointCloudEncoder {
110 fn default() -> Self {
111 Self::new()
112 }
113}
114
115impl PointCloudEncoder {
116 pub fn new() -> Self {
118 Self {
119 point_cloud: None,
120 options: EncoderOptions::default(),
121 }
122 }
123
124 pub fn point_cloud(&self) -> Option<&PointCloud> {
126 self.point_cloud.as_ref()
127 }
128
129 pub fn set_point_cloud(&mut self, pc: PointCloud) {
131 self.point_cloud = Some(pc);
132 }
133
134 pub fn encode(&mut self, options: &EncoderOptions, out_buffer: &mut EncoderBuffer) -> Status {
144 self.options = options.clone();
145
146 if self.point_cloud.is_none() {
147 return Err(DracoError::DracoError("Point cloud not set".to_string()));
148 }
149 let pc = self.point_cloud.as_ref().unwrap();
150
151 let method = self.options.get_encoding_method().unwrap_or(0);
152
153 self.encode_header(out_buffer, method)?;
155 self.encode_metadata(out_buffer)?;
156
157 if method == 1 {
158 out_buffer.encode_u32(pc.num_points() as u32);
164
165 let mut att_encoder = KdTreeAttributesEncoder::new(0);
168 for i in 1..pc.num_attributes() {
169 att_encoder.add_attribute_id(i);
170 }
171
172 out_buffer.encode_u8(1); if !att_encoder.transform_attributes_to_portable_format(pc, &self.options) {
177 return Err(DracoError::DracoError(
178 "Failed to transform attributes".to_string(),
179 ));
180 }
181
182 if !att_encoder.encode_attributes_encoder_data(pc, out_buffer) {
189 return Err(DracoError::DracoError(
190 "Failed to encode attribute metadata".to_string(),
191 ));
192 }
193
194 if !att_encoder.encode_attributes(pc, &self.options, out_buffer) {
196 return Err(DracoError::DracoError(
197 "Failed to encode attributes".to_string(),
198 ));
199 }
200
201 if !att_encoder.encode_data_needed_by_portable_transforms(out_buffer) {
203 return Err(DracoError::DracoError(
204 "Failed to encode attribute transform data".to_string(),
205 ));
206 }
207 } else {
208 let num_points = pc.num_points();
221 let num_attributes = pc.num_attributes();
222 let point_ids: Vec<PointIndex> =
223 (0..num_points).map(|i| PointIndex(i as u32)).collect();
224
225 out_buffer.encode_u32(num_points as u32);
227
228 if num_attributes == 0 {
231 out_buffer.encode_u8(0);
232 return Ok(());
233 }
234
235 out_buffer.encode_u8(1);
237
238 let major = out_buffer.version_major();
241 let minor = out_buffer.version_minor();
242 if !uses_varint_encoding(major, minor) {
243 out_buffer.encode_u32(num_attributes as u32);
244 } else {
245 out_buffer.encode_varint(num_attributes as u64);
246 }
247
248 for i in 0..num_attributes {
250 let att = pc.attribute(i);
251 out_buffer.encode_u8(att.attribute_type() as u8);
252 out_buffer.encode_u8(att.data_type() as u8);
253 out_buffer.encode_u8(att.num_components());
254 out_buffer.encode_u8(if att.normalized() { 1 } else { 0 });
255
256 if !uses_varint_unique_id(major, minor) {
257 out_buffer.encode_u16(att.unique_id() as u16);
258 } else {
259 out_buffer.encode_varint(att.unique_id() as u64);
260 }
261 }
262
263 for i in 0..num_attributes {
269 let att = pc.attribute(i);
270 if att.attribute_type() == GeometryAttributeType::Normal {
271 out_buffer.encode_u8(3); } else {
273 let quant_bits = self.options.get_attribute_int(i, "quantization_bits", 0);
275 if quant_bits > 0 {
276 out_buffer.encode_u8(2); } else {
278 out_buffer.encode_u8(0); }
280 }
281 }
282
283 let mut integer_encoders: Vec<Option<SequentialIntegerAttributeEncoder>> =
289 Vec::with_capacity(num_attributes as usize);
290 let mut normal_encoders: Vec<Option<SequentialNormalAttributeEncoder>> =
291 Vec::with_capacity(num_attributes as usize);
292
293 for i in 0..num_attributes {
295 let att = pc.attribute(i);
296
297 if att.attribute_type() == GeometryAttributeType::Normal {
298 let mut att_encoder = SequentialNormalAttributeEncoder::new();
299 if !att_encoder.init(pc, i, &self.options) {
300 return Err(DracoError::DracoError(format!(
301 "Failed to init normal attribute encoder {}",
302 i
303 )));
304 }
305
306 if !att_encoder.encode_values(pc, &point_ids, out_buffer, &self.options, self) {
307 return Err(DracoError::DracoError(format!(
308 "Failed to encode attribute {}",
309 i
310 )));
311 }
312
313 integer_encoders.push(None);
314 normal_encoders.push(Some(att_encoder));
315 } else {
316 let quant_bits = self.options.get_attribute_int(i, "quantization_bits", 0);
317 let uses_quantization = quant_bits > 0
318 && (att.data_type() == crate::draco_types::DataType::Float32
319 || att.data_type() == crate::draco_types::DataType::Float64);
320
321 if uses_quantization {
322 let mut att_encoder = SequentialIntegerAttributeEncoder::new();
323 att_encoder.init(i);
324
325 if !att_encoder.encode_values(
326 pc,
327 &point_ids,
328 out_buffer,
329 &self.options,
330 self,
331 None,
332 false,
333 ) {
334 return Err(DracoError::DracoError(format!(
335 "Failed to encode attribute {}",
336 i
337 )));
338 }
339
340 integer_encoders.push(Some(att_encoder));
341 } else {
342 let entry_size = att.byte_stride() as usize;
343 let data = att.buffer().data();
344 for &point_id in &point_ids {
345 let value_index = att.mapped_index(point_id).0 as usize;
346 let offset = value_index.checked_mul(entry_size).ok_or_else(|| {
347 DracoError::DracoError(
348 "Point cloud raw attribute offset overflow".to_string(),
349 )
350 })?;
351 let end = offset.checked_add(entry_size).ok_or_else(|| {
352 DracoError::DracoError(
353 "Point cloud raw attribute byte range overflow".to_string(),
354 )
355 })?;
356 if end > data.len() {
357 return Err(DracoError::DracoError(
358 "Point cloud raw attribute data out of bounds".to_string(),
359 ));
360 }
361 out_buffer.encode_data(&data[offset..end]);
362 }
363
364 integer_encoders.push(None);
365 }
366
367 normal_encoders.push(None);
368 }
369 }
370
371 for i in 0..num_attributes as usize {
373 let att = pc.attribute(i as i32);
374
375 if att.attribute_type() == GeometryAttributeType::Normal {
376 if let Some(ref att_encoder) = normal_encoders[i] {
377 let (major, minor) = self.options.get_version();
378 let bitstream_version = crate::version::bitstream_version(major, minor);
379 if bitstream_version != 0 && bitstream_version < 0x0102 {
380 continue;
381 }
382 if !att_encoder.encode_data_needed_by_portable_transform(out_buffer) {
383 return Err(DracoError::DracoError(format!(
384 "Failed to encode normal attribute transform data {}",
385 i
386 )));
387 }
388 }
389 } else if let Some(ref att_encoder) = integer_encoders[i] {
390 if !att_encoder.encode_data_needed_by_portable_transform(out_buffer) {
391 return Err(DracoError::DracoError(format!(
392 "Failed to encode quantization transform data {}",
393 i
394 )));
395 }
396 }
397 }
398 }
399
400 Ok(())
401 }
402
403 fn encode_metadata(&self, buffer: &mut EncoderBuffer) -> Status {
404 if let Some(metadata) = self
405 .point_cloud
406 .as_ref()
407 .and_then(|point_cloud| point_cloud.metadata())
408 .filter(|metadata| !metadata.is_empty())
409 {
410 metadata.encode(buffer)?;
411 }
412 Ok(())
413 }
414
415 fn encode_header(&self, buffer: &mut EncoderBuffer, method: i32) -> Status {
416 let (mut major, mut minor) = self.options.get_version();
417 if major == 0 && minor == 0 {
418 if method == 1 {
419 (major, minor) = DEFAULT_POINT_CLOUD_KD_TREE_VERSION;
420 } else {
421 (major, minor) = DEFAULT_POINT_CLOUD_SEQUENTIAL_VERSION;
422 }
423 }
424 let has_metadata = self
425 .point_cloud
426 .as_ref()
427 .and_then(|point_cloud| point_cloud.metadata())
428 .is_some_and(|metadata| !metadata.is_empty());
429
430 if has_metadata && !has_header_flags(major, minor) {
431 return Err(DracoError::UnsupportedVersion(
432 "Metadata requires Draco bitstream version 1.3 or newer".to_string(),
433 ));
434 }
435
436 buffer.encode_data(b"DRACO");
437
438 buffer.encode_u8(major);
439 buffer.encode_u8(minor);
440 buffer.set_version(major, minor);
441
442 buffer.encode_u8(self.get_geometry_type() as u8);
443 buffer.encode_u8(method as u8);
444
445 if has_header_flags(major, minor) {
446 let flags = if has_metadata { METADATA_FLAG_MASK } else { 0 };
447 buffer.encode_u16(flags);
448 }
449 Ok(())
450 }
451
452 pub fn get_geometry_type(&self) -> EncodedGeometryType {
454 EncodedGeometryType::PointCloud
455 }
456}