Skip to main content

draco_core/
lib.rs

1//! Core Draco geometry compression primitives.
2//!
3//! `draco-core` implements the raw Draco `.drc` bitstream layer for triangle
4//! meshes and point clouds. It intentionally stops at the geometry compression
5//! model: file containers such as glTF/GLB, OBJ, PLY, STL, and FBX live in
6//! `draco-io`.
7//!
8//! # Main Entry Points
9//!
10//! - [`Mesh`] and [`PointCloud`] hold decoded geometry.
11//! - [`PointAttribute`] stores typed attribute data such as positions, normals,
12//!   colors, texture coordinates, and generic attributes.
13//! - [`Metadata`], [`GeometryMetadata`], and [`AttributeMetadata`] expose raw
14//!   Draco metadata plus C++-compatible typed helpers.
15//! - With the `encoder` feature, use [`MeshEncoder`] or [`PointCloudEncoder`].
16//! - With the `decoder` feature, use [`MeshDecoder`] or [`PointCloudDecoder`].
17//!
18//! # Features
19//!
20//! The default feature set enables both encoding and decoding, point-cloud
21//! KD-tree decoding, EdgeBreaker valence traversal, and legacy bitstream
22//! compatibility helpers. Disable default features when embedding only the
23//! geometry data model or one codec direction is needed.
24//!
25//! # Metadata
26//!
27//! Draco metadata entries are stored as untyped byte blobs in the bitstream.
28//! The typed helpers on [`Metadata`] write the same bytes used by C++ Draco
29//! convenience APIs for `int32`, `double`, arrays, and strings.
30//!
31//! # Example
32//!
33//! ```no_run
34//! use draco_core::{DecoderBuffer, Mesh, MeshDecoder};
35//!
36//! let bytes = std::fs::read("mesh.drc")?;
37//! let mut buffer = DecoderBuffer::new(&bytes);
38//! let mut mesh = Mesh::new();
39//! MeshDecoder::new().decode(&mut buffer, &mut mesh)?;
40//! println!("decoded {} faces", mesh.num_faces());
41//! # Ok::<(), Box<dyn std::error::Error>>(())
42//! ```
43
44#![cfg_attr(docsrs, feature(doc_cfg))]
45// Allow certain clippy lints that are intentional design decisions for C++ port compatibility
46#![allow(clippy::needless_range_loop)] // Many loops follow C++ patterns for array indexing
47#![allow(clippy::manual_memcpy)] // Manual copying matches C++ patterns for clarity
48
49#[cfg(feature = "debug_logs")]
50#[inline]
51pub(crate) fn debug_env_enabled(name: &str) -> bool {
52    std::env::var_os(name).is_some()
53}
54
55/// Emit a diagnostic line to stderr, but only when the `debug_logs` feature is
56/// enabled. `draco-core` is a library, so decode/encode paths must not print on
57/// their own. Using `if cfg!(...)` keeps the formatting arguments type-checked
58/// yet dead-code-eliminated in normal builds: nothing is evaluated and nothing
59/// is printed, so there is no runtime cost and no unused-variable churn.
60///
61/// Defined at the crate root before the module declarations below so every
62/// module can use it by bare name via textual macro scoping.
63macro_rules! debug_log {
64    ($($arg:tt)*) => {
65        if cfg!(feature = "debug_logs") {
66            eprintln!($($arg)*);
67        }
68    };
69}
70
71// =============================================================================
72// Core modules - always available
73// =============================================================================
74
75#[doc(hidden)]
76pub mod ans;
77#[doc(hidden)]
78pub mod attribute_octahedron_transform;
79#[doc(hidden)]
80pub mod attribute_transform;
81#[doc(hidden)]
82pub mod attribute_transform_data;
83#[doc(hidden)]
84pub mod bit_utils;
85#[doc(hidden)]
86pub mod compression_config;
87#[doc(hidden)]
88pub mod corner_table;
89/// Draco scalar data type identifiers.
90pub mod draco_types;
91/// Geometry attribute descriptors and point attribute storage.
92pub mod geometry_attribute;
93/// Strongly typed geometry index wrappers.
94pub mod geometry_indices;
95/// Keyframe animation container built on the point-cloud path.
96pub mod keyframe_animation;
97/// Triangle mesh geometry data.
98pub mod mesh;
99/// Draco metadata containers and bitstream serialization helpers.
100pub mod metadata;
101
102// Internal codec modules are kept public but hidden so existing parity tests can
103// exercise ported Draco internals without presenting them as the public API.
104#[doc(hidden)]
105pub mod attribute_quantization_transform;
106/// Depth-first corner-table traversal, shared by the two decode paths that
107/// order attribute values by connectivity.
108#[cfg(feature = "decoder")]
109mod corner_traversal;
110#[doc(hidden)]
111pub mod data_buffer;
112/// What a decode may allocate relative to the stream it is reading. Internal:
113/// the ratio is an implementation detail, not a knob.
114#[cfg(feature = "decoder")]
115mod decode_budget;
116/// Caller-set ceilings on what one decode may produce. Public: unlike the
117/// budget above, where the ceiling sits is the caller's policy.
118///
119/// Not gated on `decoder`, and the difference is not cosmetic: the type is a
120/// policy a caller states, so a crate that threads it through has to be able
121/// to name it whether or not the decoder is compiled in. Only the checks the
122/// decoder runs carry the gate.
123pub mod decode_limits;
124/// Coarse decode phase timing for the performance harness (`DECODE_PHASES=1`).
125#[doc(hidden)]
126#[cfg(feature = "decoder")]
127pub mod decode_phase_probe;
128#[doc(hidden)]
129#[cfg(any(feature = "encoder", feature = "decoder"))]
130pub mod dynamic_integer_points_kd_tree;
131#[doc(hidden)]
132pub mod edgebreaker_connectivity_decoder;
133#[doc(hidden)]
134pub mod folded_bit32_coder;
135#[doc(hidden)]
136pub mod math_utils;
137#[doc(hidden)]
138pub mod mesh_attribute_corner_table;
139#[doc(hidden)]
140pub mod mesh_edgebreaker_shared;
141#[doc(hidden)]
142pub mod mesh_prediction_scheme_data;
143#[doc(hidden)]
144pub mod normal_compression_utils;
145/// Point cloud geometry data.
146pub mod point_cloud;
147/// The prediction-parent binding: how a scheme obtains portable parent values.
148#[doc(hidden)]
149pub mod portable_attribute;
150#[doc(hidden)]
151pub mod prediction_scheme;
152#[doc(hidden)]
153#[cfg(any(feature = "encoder", feature = "decoder"))]
154pub mod prediction_scheme_constrained_multi_parallelogram;
155#[doc(hidden)]
156#[cfg(any(feature = "encoder", feature = "decoder"))]
157pub mod prediction_scheme_delta;
158#[doc(hidden)]
159#[cfg(any(feature = "encoder", feature = "decoder"))]
160pub mod prediction_scheme_geometric_normal;
161#[cfg(any(
162    all(feature = "encoder", feature = "legacy_bitstream_encode"),
163    all(feature = "decoder", feature = "legacy_bitstream_decode")
164))]
165#[cfg_attr(
166    docsrs,
167    doc(cfg(any(
168        all(feature = "encoder", feature = "legacy_bitstream_encode"),
169        all(feature = "decoder", feature = "legacy_bitstream_decode")
170    )))
171)]
172#[doc(hidden)]
173pub mod prediction_scheme_multi_parallelogram;
174#[doc(hidden)]
175pub mod prediction_scheme_normal_octahedron_canonicalized_transform_base;
176#[doc(hidden)]
177pub mod prediction_scheme_normal_octahedron_transform_base;
178#[doc(hidden)]
179#[cfg(any(feature = "encoder", feature = "decoder"))]
180pub mod prediction_scheme_parallelogram;
181#[doc(hidden)]
182pub mod prediction_scheme_selection;
183#[cfg(any(
184    all(feature = "encoder", feature = "legacy_bitstream_encode"),
185    all(feature = "decoder", feature = "legacy_bitstream_decode")
186))]
187#[cfg_attr(
188    docsrs,
189    doc(cfg(any(
190        all(feature = "encoder", feature = "legacy_bitstream_encode"),
191        all(feature = "decoder", feature = "legacy_bitstream_decode")
192    )))
193)]
194#[doc(hidden)]
195pub mod prediction_scheme_tex_coords_deprecated;
196#[doc(hidden)]
197#[cfg(any(feature = "encoder", feature = "decoder"))]
198pub mod prediction_scheme_tex_coords_portable;
199#[doc(hidden)]
200#[cfg(any(feature = "encoder", feature = "decoder"))]
201pub mod prediction_scheme_wrap;
202#[doc(hidden)]
203pub mod quantization_utils;
204#[doc(hidden)]
205pub mod rans_symbol_coding;
206/// Error and status types.
207pub mod status;
208#[doc(hidden)]
209#[cfg(any(feature = "encoder", feature = "decoder"))]
210pub mod symbol_encoding;
211#[doc(hidden)]
212pub mod test_event_log;
213#[doc(hidden)]
214pub mod version;
215
216// =============================================================================
217// Decoder-only modules
218// =============================================================================
219
220#[cfg(feature = "decoder")]
221#[cfg_attr(docsrs, doc(cfg(feature = "decoder")))]
222/// Decoder input buffer.
223pub mod decoder_buffer;
224#[cfg(feature = "decoder")]
225#[cfg_attr(docsrs, doc(cfg(feature = "decoder")))]
226#[doc(hidden)]
227pub mod direct_bit_decoder;
228#[cfg(all(feature = "decoder", feature = "point_cloud_decode"))]
229#[cfg_attr(
230    docsrs,
231    doc(cfg(all(feature = "decoder", feature = "point_cloud_decode")))
232)]
233#[doc(hidden)]
234pub mod kd_tree_attributes_decoder;
235#[cfg(all(feature = "decoder", feature = "point_cloud_decode"))]
236#[cfg_attr(
237    docsrs,
238    doc(cfg(all(feature = "decoder", feature = "point_cloud_decode")))
239)]
240/// Keyframe animation decoder entry point.
241pub mod keyframe_animation_decoder;
242#[cfg(feature = "decoder")]
243#[cfg_attr(docsrs, doc(cfg(feature = "decoder")))]
244/// Mesh decoder entry point.
245pub mod mesh_decoder;
246#[cfg(feature = "decoder")]
247#[cfg_attr(docsrs, doc(cfg(feature = "decoder")))]
248#[doc(hidden)]
249pub mod mesh_edgebreaker_decoder;
250#[cfg(all(feature = "decoder", feature = "legacy_bitstream_decode"))]
251#[cfg_attr(
252    docsrs,
253    doc(cfg(all(feature = "decoder", feature = "legacy_bitstream_decode")))
254)]
255#[doc(hidden)]
256pub mod mesh_edgebreaker_traversal_predictive_decoder;
257#[cfg(all(feature = "decoder", feature = "edgebreaker_valence_decode"))]
258#[cfg_attr(
259    docsrs,
260    doc(cfg(all(feature = "decoder", feature = "edgebreaker_valence_decode")))
261)]
262#[doc(hidden)]
263pub mod mesh_edgebreaker_traversal_valence_decoder;
264#[cfg(feature = "decoder")]
265#[cfg_attr(docsrs, doc(cfg(feature = "decoder")))]
266/// Point cloud decoder entry point.
267pub mod point_cloud_decoder;
268#[cfg(feature = "decoder")]
269#[cfg_attr(docsrs, doc(cfg(feature = "decoder")))]
270#[doc(hidden)]
271pub mod prediction_scheme_normal_octahedron_canonicalized_decoding_transform;
272#[cfg(feature = "decoder")]
273#[cfg_attr(docsrs, doc(cfg(feature = "decoder")))]
274#[doc(hidden)]
275pub mod rans_bit_decoder;
276#[cfg(feature = "decoder")]
277#[cfg_attr(docsrs, doc(cfg(feature = "decoder")))]
278#[doc(hidden)]
279pub mod rans_symbol_decoder;
280#[cfg(feature = "decoder")]
281#[cfg_attr(docsrs, doc(cfg(feature = "decoder")))]
282#[doc(hidden)]
283pub mod sequential_attribute_decoder;
284#[cfg(feature = "decoder")]
285#[cfg_attr(docsrs, doc(cfg(feature = "decoder")))]
286#[doc(hidden)]
287pub mod sequential_generic_attribute_decoder;
288#[cfg(feature = "decoder")]
289#[cfg_attr(docsrs, doc(cfg(feature = "decoder")))]
290#[doc(hidden)]
291pub mod sequential_integer_attribute_decoder;
292#[cfg(feature = "decoder")]
293#[cfg_attr(docsrs, doc(cfg(feature = "decoder")))]
294#[doc(hidden)]
295pub mod sequential_normal_attribute_decoder;
296#[cfg(feature = "decoder")]
297#[cfg_attr(docsrs, doc(cfg(feature = "decoder")))]
298#[doc(hidden)]
299pub mod sequential_quantization_attribute_decoder;
300
301// =============================================================================
302// Encoder-only modules
303// =============================================================================
304
305#[cfg(feature = "encoder")]
306#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
307#[doc(hidden)]
308pub mod direct_bit_encoder;
309#[cfg(feature = "encoder")]
310#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
311/// Encoder output buffer.
312pub mod encoder_buffer;
313#[cfg(feature = "encoder")]
314#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
315/// Encoder configuration options.
316pub mod encoder_options;
317#[cfg(feature = "encoder")]
318#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
319#[doc(hidden)]
320pub mod kd_tree_attributes_encoder;
321#[cfg(feature = "encoder")]
322#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
323/// Keyframe animation encoder entry point.
324pub mod keyframe_animation_encoder;
325#[cfg(feature = "encoder")]
326#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
327#[doc(hidden)]
328pub mod mesh_edgebreaker_encoder;
329#[cfg(all(feature = "encoder", feature = "legacy_bitstream_encode"))]
330#[cfg_attr(
331    docsrs,
332    doc(cfg(all(feature = "encoder", feature = "legacy_bitstream_encode")))
333)]
334#[doc(hidden)]
335pub mod mesh_edgebreaker_traversal_predictive_encoder;
336#[cfg(all(feature = "encoder", feature = "edgebreaker_valence_encode"))]
337#[cfg_attr(
338    docsrs,
339    doc(cfg(all(feature = "encoder", feature = "edgebreaker_valence_encode")))
340)]
341#[doc(hidden)]
342pub mod mesh_edgebreaker_traversal_valence_encoder;
343#[cfg(feature = "encoder")]
344#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
345/// Mesh encoder entry point.
346pub mod mesh_encoder;
347#[cfg(feature = "encoder")]
348#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
349/// Point cloud encoder entry point.
350pub mod point_cloud_encoder;
351#[cfg(feature = "encoder")]
352#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
353#[doc(hidden)]
354pub mod prediction_scheme_normal_octahedron_canonicalized_encoding_transform;
355#[cfg(feature = "encoder")]
356#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
357#[doc(hidden)]
358pub mod rans_bit_encoder;
359#[cfg(feature = "encoder")]
360#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
361#[doc(hidden)]
362pub mod rans_symbol_encoder;
363#[cfg(feature = "encoder")]
364#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
365#[doc(hidden)]
366pub mod sequential_attribute_encoder;
367#[cfg(feature = "encoder")]
368#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
369#[doc(hidden)]
370pub mod sequential_integer_attribute_encoder;
371#[cfg(feature = "encoder")]
372#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
373#[doc(hidden)]
374pub mod sequential_normal_attribute_encoder;
375#[cfg(feature = "encoder")]
376#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
377#[doc(hidden)]
378pub mod shannon_entropy;
379
380// =============================================================================
381// Core re-exports - always available
382// =============================================================================
383
384pub use draco_types::DataType;
385pub use geometry_attribute::{GeometryAttribute, GeometryAttributeType, PointAttribute};
386pub use geometry_indices::{AttributeValueIndex, FaceIndex, PointIndex};
387pub use keyframe_animation::KeyframeAnimation;
388pub use mesh::Mesh;
389pub use metadata::{AttributeMetadata, GeometryMetadata, Metadata};
390pub use point_cloud::PointCloud;
391pub use status::{DracoError, ErrorKind, Status};
392
393// =============================================================================
394// Decoder re-exports
395// =============================================================================
396
397pub use decode_limits::DecodeLimits;
398#[cfg(feature = "decoder")]
399#[cfg_attr(docsrs, doc(cfg(feature = "decoder")))]
400pub use decoder_buffer::DecoderBuffer;
401#[cfg(all(feature = "decoder", feature = "point_cloud_decode"))]
402#[cfg_attr(
403    docsrs,
404    doc(cfg(all(feature = "decoder", feature = "point_cloud_decode")))
405)]
406pub use keyframe_animation_decoder::KeyframeAnimationDecoder;
407#[cfg(feature = "decoder")]
408#[cfg_attr(docsrs, doc(cfg(feature = "decoder")))]
409pub use mesh_decoder::MeshDecoder;
410#[cfg(feature = "decoder")]
411#[cfg_attr(docsrs, doc(cfg(feature = "decoder")))]
412pub use point_cloud_decoder::PointCloudDecoder;
413
414// =============================================================================
415// Encoder re-exports
416// =============================================================================
417
418#[cfg(feature = "encoder")]
419#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
420pub use encoder_buffer::EncoderBuffer;
421#[cfg(feature = "encoder")]
422#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
423pub use encoder_options::EncoderOptions;
424#[cfg(feature = "encoder")]
425#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
426pub use keyframe_animation_encoder::KeyframeAnimationEncoder;
427#[cfg(feature = "encoder")]
428#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
429pub use mesh_encoder::{EncodedAttributeInfo, EncodedMeshInfo, MeshEncoder};
430#[cfg(feature = "encoder")]
431#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
432pub use point_cloud_encoder::{EncodedPointCloudInfo, PointCloudEncoder};