use draco_core::decoder_buffer::DecoderBuffer;
use draco_core::draco_types::DataType;
use draco_core::encoder_buffer::EncoderBuffer;
use draco_core::encoder_options::EncoderOptions;
use draco_core::geometry_attribute::{GeometryAttributeType, PointAttribute};
use draco_core::geometry_indices::PointIndex;
use draco_core::point_cloud::PointCloud;
use draco_core::point_cloud_decoder::PointCloudDecoder;
use draco_core::point_cloud_encoder::PointCloudEncoder;
const POSITIONS: [f32; 12] = [
0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, ];
fn cloud_with_positions() -> PointCloud {
let num_points = POSITIONS.len() / 3;
let mut pc = PointCloud::new();
pc.set_num_points(num_points);
let mut att = PointAttribute::new();
att.init(
GeometryAttributeType::Position,
3,
DataType::Float32,
false,
num_points,
);
for (i, value) in POSITIONS.iter().enumerate() {
att.buffer_mut().write(i * 4, &value.to_le_bytes());
}
pc.add_attribute(att);
pc
}
fn encode(pc: PointCloud, options: &EncoderOptions) -> Result<Vec<u8>, String> {
let mut encoder = PointCloudEncoder::new();
encoder.set_point_cloud(pc);
let mut buffer = EncoderBuffer::new();
encoder
.encode(options, &mut buffer)
.map_err(|e| format!("{e:?}"))?;
Ok(buffer.data().to_vec())
}
fn decode(bytes: &[u8]) -> PointCloud {
let mut buffer = DecoderBuffer::new(bytes);
let mut out = PointCloud::new();
PointCloudDecoder::new()
.decode(&mut buffer, &mut out)
.expect("decode");
out
}
fn method_byte(bytes: &[u8]) -> u8 {
assert_eq!(&bytes[0..5], b"DRACO", "not a Draco stream");
assert_eq!(bytes[7], 0, "not a point cloud");
bytes[8]
}
#[test]
fn an_unset_method_selects_kd_tree() {
let mut options = EncoderOptions::new();
options.set_attribute_int(0, "quantization_bits", 14);
let bytes = encode(cloud_with_positions(), &options).expect("encode");
assert_eq!(method_byte(&bytes), 1, "expected KD-tree");
}
#[test]
fn an_unset_method_at_speed_10_selects_sequential() {
let mut options = EncoderOptions::new();
options.set_global_int("encoding_speed", 10);
options.set_global_int("decoding_speed", 10);
options.set_attribute_int(0, "quantization_bits", 14);
let bytes = encode(cloud_with_positions(), &options).expect("encode");
assert_eq!(method_byte(&bytes), 0, "expected sequential");
}
#[test]
fn an_unquantized_attribute_falls_back_to_sequential() {
let options = EncoderOptions::new();
let bytes = encode(cloud_with_positions(), &options).expect("encode");
assert_eq!(method_byte(&bytes), 0, "expected sequential");
}
#[test]
fn an_unquantized_attribute_rejects_an_explicit_kd_tree() {
let mut options = EncoderOptions::new();
options.set_encoding_method(1);
let error = encode(cloud_with_positions(), &options).expect_err("must not encode");
assert!(
error.contains("Invalid encoding method"),
"unexpected error: {error}"
);
}
#[test]
fn kd_tree_survives_a_cloud_with_no_attributes() {
let mut pc = PointCloud::new();
pc.set_num_points(4);
let mut options = EncoderOptions::new();
options.set_encoding_method(1);
let bytes = encode(pc, &options).expect("encode");
assert_eq!(method_byte(&bytes), 1, "expected KD-tree");
assert_eq!(decode(&bytes).num_attributes(), 0);
}
#[test]
fn quantization_requested_on_an_integer_attribute_is_ignored() {
let mut pc = cloud_with_positions();
let colors: [u8; 12] = [0, 17, 250, 255, 3, 128, 64, 200, 9, 90, 180, 7];
let mut att = PointAttribute::new();
att.init(GeometryAttributeType::Color, 3, DataType::Uint8, true, 4);
for (i, value) in colors.iter().enumerate() {
att.buffer_mut().write(i, &[*value]);
}
pc.add_attribute(att);
let mut options = EncoderOptions::new();
options.set_encoding_method(0);
options.set_attribute_int(0, "quantization_bits", 14);
options.set_attribute_int(1, "quantization_bits", 8);
let decoded = decode(&encode(pc, &options).expect("encode"));
assert_eq!(decoded.num_attributes(), 2);
let att = decoded.attribute(1);
assert_eq!(att.data_type(), DataType::Uint8);
let mut round_tripped = [0u8; 12];
for point in 0..4 {
let index = att.mapped_index(PointIndex(point as u32)).0 as usize;
att.buffer()
.read(index * 3, &mut round_tripped[point * 3..point * 3 + 3]);
}
assert_eq!(round_tripped, colors);
}
#[test]
fn an_unquantized_normal_encodes_as_raw_floats() {
let normals: [f32; 12] = [
1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.57735, 0.57735, 0.57735,
];
let mut pc = PointCloud::new();
pc.set_num_points(4);
let mut att = PointAttribute::new();
att.init(
GeometryAttributeType::Normal,
3,
DataType::Float32,
false,
4,
);
for (i, value) in normals.iter().enumerate() {
att.buffer_mut().write(i * 4, &value.to_le_bytes());
}
pc.add_attribute(att);
let options = EncoderOptions::new();
let decoded = decode(&encode(pc, &options).expect("encode"));
let att = decoded.attribute(0);
assert_eq!(att.attribute_type(), GeometryAttributeType::Normal);
for (i, expected) in normals.iter().enumerate() {
let mut bytes = [0u8; 4];
att.buffer().read(i * 4, &mut bytes);
assert_eq!(
f32::from_le_bytes(bytes),
*expected,
"component {i} changed value"
);
}
}